ALSA: hda/idt - Fix power-map for speaker-pins with some HP laptops
[linux-flexiantxendom0-3.2.10.git] / sound / pci / hda / patch_sigmatel.c
index 56425a5..2cb1e08 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/dmi.h>
+#include <linux/module.h>
 #include <sound/core.h>
 #include <sound/asoundef.h>
 #include <sound/jack.h>
@@ -36,6 +37,7 @@
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_beep.h"
+#include "hda_jack.h"
 
 enum {
        STAC_VREF_EVENT = 1,
@@ -94,8 +96,10 @@ enum {
        STAC_92HD83XXX_REF,
        STAC_92HD83XXX_PWR_REF,
        STAC_DELL_S14,
-       STAC_92HD83XXX_HP,
+       STAC_DELL_VOSTRO_3500,
+       STAC_92HD83XXX_HP_cNB11_INTQUAD,
        STAC_HP_DV7_4000,
+       STAC_HP_ZEPHYR,
        STAC_92HD83XXX_MODELS
 };
 
@@ -173,13 +177,6 @@ enum {
        STAC_9872_MODELS
 };
 
-struct sigmatel_event {
-       hda_nid_t nid;
-       unsigned char type;
-       unsigned char tag;
-       int data;
-};
-
 struct sigmatel_mic_route {
        hda_nid_t pin;
        signed char mux_idx;
@@ -212,6 +209,8 @@ struct sigmatel_spec {
        unsigned int gpio_mute;
        unsigned int gpio_led;
        unsigned int gpio_led_polarity;
+       unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */
+       unsigned int vref_led;
 
        /* stream */
        unsigned int stream_delay;
@@ -223,13 +222,9 @@ struct sigmatel_spec {
 
        /* power management */
        unsigned int num_pwrs;
-       const unsigned int *pwr_mapping;
        const hda_nid_t *pwr_nids;
        const hda_nid_t *dac_list;
 
-       /* events */
-       struct snd_array events;
-
        /* playback */
        struct hda_input_mux *mono_mux;
        unsigned int cur_mmux;
@@ -315,6 +310,8 @@ struct sigmatel_spec {
        unsigned long auto_capvols[MAX_ADCS_NUM];
        unsigned auto_dmic_cnt;
        hda_nid_t auto_dmic_nids[MAX_DMICS_NUM];
+
+       struct hda_vmaster_mute_hook vmaster_mute;
 };
 
 static const hda_nid_t stac9200_adc_nids[1] = {
@@ -370,18 +367,15 @@ static const unsigned long stac92hd73xx_capvols[] = {
 
 #define STAC92HD83_DAC_COUNT 3
 
-static const hda_nid_t stac92hd83xxx_pwr_nids[4] = {
-       0xa, 0xb, 0xd, 0xe,
+static const hda_nid_t stac92hd83xxx_pwr_nids[7] = {
+       0x0a, 0x0b, 0x0c, 0xd, 0x0e,
+       0x0f, 0x10
 };
 
 static const hda_nid_t stac92hd83xxx_slave_dig_outs[2] = {
        0x1e, 0,
 };
 
-static const unsigned int stac92hd83xxx_pwr_mapping[4] = {
-       0x03, 0x0c, 0x20, 0x40,
-};
-
 static const hda_nid_t stac92hd83xxx_dmic_nids[] = {
                0x11, 0x20,
 };
@@ -671,6 +665,30 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+static int stac_vrefout_set(struct hda_codec *codec,
+                                       hda_nid_t nid, unsigned int new_vref)
+{
+       int error, pinctl;
+
+       snd_printdd("%s, nid %x ctl %x\n", __func__, nid, new_vref);
+       pinctl = snd_hda_codec_read(codec, nid, 0,
+                               AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+
+       if (pinctl < 0)
+               return pinctl;
+
+       pinctl &= 0xff;
+       pinctl &= ~AC_PINCTL_VREFEN;
+       pinctl |= (new_vref & AC_PINCTL_VREFEN);
+
+       error = snd_hda_codec_write_cache(codec, nid, 0,
+                                       AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
+       if (error < 0)
+               return error;
+
+       return 1;
+}
+
 static unsigned int stac92xx_vref_set(struct hda_codec *codec,
                                        hda_nid_t nid, unsigned int new_vref)
 {
@@ -877,6 +895,13 @@ static const struct hda_verb stac92hd83xxx_core_init[] = {
        {}
 };
 
+static const struct hda_verb stac92hd83xxx_hp_zephyr_init[] = {
+       { 0x22, 0x785, 0x43 },
+       { 0x22, 0x782, 0xe0 },
+       { 0x22, 0x795, 0x00 },
+       {}
+};
+
 static const struct hda_verb stac92hd71bxx_core_init[] = {
        /* set master volume and direct control */
        { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
@@ -982,8 +1007,8 @@ static const struct hda_verb stac9205_core_init[] = {
        }
 
 static const struct snd_kcontrol_new stac9200_mixer[] = {
-       HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xb, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("PCM Playback Switch", 0xb, 0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
        { } /* end */
@@ -1010,8 +1035,8 @@ static const struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
 };
 
 static const struct snd_kcontrol_new stac925x_mixer[] = {
-       HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xe, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("PCM Playback Switch", 0x0e, 0, HDA_OUTPUT),
        { } /* end */
 };
 
@@ -1043,37 +1068,25 @@ static struct snd_kcontrol_new stac_smux_mixer = {
        .put = stac92xx_smux_enum_put,
 };
 
-static const char * const slave_vols[] = {
-       "Front Playback Volume",
-       "Surround Playback Volume",
-       "Center Playback Volume",
-       "LFE Playback Volume",
-       "Side Playback Volume",
-       "Headphone Playback Volume",
-       "Speaker Playback Volume",
+static const char * const slave_pfxs[] = {
+       "Front", "Surround", "Center", "LFE", "Side",
+       "Headphone", "Speaker", "IEC958",
        NULL
 };
 
-static const char * const slave_sws[] = {
-       "Front Playback Switch",
-       "Surround Playback Switch",
-       "Center Playback Switch",
-       "LFE Playback Switch",
-       "Side Playback Switch",
-       "Headphone Playback Switch",
-       "Speaker Playback Switch",
-       "IEC958 Playback Switch",
-       NULL
-};
+static void stac92xx_update_led_status(struct hda_codec *codec, int enabled);
+
+static void stac92xx_vmaster_hook(void *private_data, int val)
+{
+       stac92xx_update_led_status(private_data, val);
+}
 
 static void stac92xx_free_kctls(struct hda_codec *codec);
-static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type);
 
 static int stac92xx_build_controls(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       hda_nid_t nid;
+       unsigned int vmaster_tlv[4];
        int err;
        int i;
 
@@ -1130,22 +1143,28 @@ static int stac92xx_build_controls(struct hda_codec *codec)
        }
 
        /* if we have no master control, let's create it */
-       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
-               unsigned int vmaster_tlv[4];
-               snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
-                                       HDA_OUTPUT, vmaster_tlv);
-               /* correct volume offset */
-               vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
-               /* minimum value is actually mute */
-               vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
-               err = snd_hda_add_vmaster(codec, "Master Playback Volume",
-                                         vmaster_tlv, slave_vols);
-               if (err < 0)
-                       return err;
-       }
-       if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
-               err = snd_hda_add_vmaster(codec, "Master Playback Switch",
-                                         NULL, slave_sws);
+       snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
+                               HDA_OUTPUT, vmaster_tlv);
+       /* correct volume offset */
+       vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
+       /* minimum value is actually mute */
+       vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
+       err = snd_hda_add_vmaster(codec, "Master Playback Volume",
+                                 vmaster_tlv, slave_pfxs,
+                                 "Playback Volume");
+       if (err < 0)
+               return err;
+
+       err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
+                                   NULL, slave_pfxs,
+                                   "Playback Switch", true,
+                                   &spec->vmaster_mute.sw_kctl);
+       if (err < 0)
+               return err;
+
+       if (spec->gpio_led) {
+               spec->vmaster_mute.hook = stac92xx_vmaster_hook;
+               err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true);
                if (err < 0)
                        return err;
        }
@@ -1159,31 +1178,9 @@ static int stac92xx_build_controls(struct hda_codec *codec)
 
        stac92xx_free_kctls(codec); /* no longer needed */
 
-       /* create jack input elements */
-       if (spec->hp_detect) {
-               for (i = 0; i < cfg->hp_outs; i++) {
-                       int type = SND_JACK_HEADPHONE;
-                       nid = cfg->hp_pins[i];
-                       /* jack detection */
-                       if (cfg->hp_outs == i)
-                               type |= SND_JACK_LINEOUT;
-                       err = stac92xx_add_jack(codec, nid, type);
-                       if (err < 0)
-                               return err;
-               }
-       }
-       for (i = 0; i < cfg->line_outs; i++) {
-               err = stac92xx_add_jack(codec, cfg->line_out_pins[i],
-                                       SND_JACK_LINEOUT);
-               if (err < 0)
-                       return err;
-       }
-       for (i = 0; i < cfg->num_inputs; i++) {
-               nid = cfg->inputs[i].pin;
-               err = stac92xx_add_jack(codec, nid, SND_JACK_MICROPHONE);
-               if (err < 0)
-                       return err;
-       }
+       err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
+       if (err < 0)
+               return err;
 
        return 0;       
 }
@@ -1604,7 +1601,7 @@ static const struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd,
                                "Dell Studio 1557", STAC_DELL_M6_DMIC),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe,
-                               "Dell Studio XPS 1645", STAC_DELL_M6_BOTH),
+                               "Dell Studio XPS 1645", STAC_DELL_M6_DMIC),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413,
                                "Dell Studio 1558", STAC_DELL_M6_DMIC),
        {} /* terminator */
@@ -1615,6 +1612,8 @@ static const struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = {
                      "Alienware M17x", STAC_ALIENWARE_M17X),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a,
                      "Alienware M17x", STAC_ALIENWARE_M17X),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
+                     "Alienware M17x R3", STAC_DELL_EQ),
        {} /* terminator */
 };
 
@@ -1630,17 +1629,38 @@ static const unsigned int dell_s14_pin_configs[10] = {
        0x40f000f0, 0x40f000f0,
 };
 
+static const unsigned int dell_vostro_3500_pin_configs[10] = {
+       0x02a11020, 0x0221101f, 0x400000f0, 0x90170110,
+       0x400000f1, 0x400000f2, 0x400000f3, 0x90a60160,
+       0x400000f4, 0x400000f5,
+};
+
 static const unsigned int hp_dv7_4000_pin_configs[10] = {
        0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110,
        0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140,
        0x40f000f0, 0x40f000f0,
 };
 
+static const unsigned int hp_zephyr_pin_configs[10] = {
+       0x01813050, 0x0421201f, 0x04a1205e, 0x96130310,
+       0x96130310, 0x0101401f, 0x1111611f, 0xd5a30130,
+       0, 0,
+};
+
+static const unsigned int hp_cNB11_intquad_pin_configs[10] = {
+       0x40f000f0, 0x0221101f, 0x02a11020, 0x92170110,
+       0x40f000f0, 0x92170110, 0x40f000f0, 0xd5a30130,
+       0x40f000f0, 0x40f000f0,
+};
+
 static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
        [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
        [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
        [STAC_DELL_S14] = dell_s14_pin_configs,
+       [STAC_DELL_VOSTRO_3500] = dell_vostro_3500_pin_configs,
+       [STAC_92HD83XXX_HP_cNB11_INTQUAD] = hp_cNB11_intquad_pin_configs,
        [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs,
+       [STAC_HP_ZEPHYR] = hp_zephyr_pin_configs,
 };
 
 static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
@@ -1648,8 +1668,10 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
        [STAC_92HD83XXX_REF] = "ref",
        [STAC_92HD83XXX_PWR_REF] = "mic-ref",
        [STAC_DELL_S14] = "dell-s14",
-       [STAC_92HD83XXX_HP] = "hp",
+       [STAC_DELL_VOSTRO_3500] = "dell-vostro-3500",
+       [STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad",
        [STAC_HP_DV7_4000] = "hp-dv7-4000",
+       [STAC_HP_ZEPHYR] = "hp-zephyr",
 };
 
 static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
@@ -1660,8 +1682,56 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
                      "DFI LanParty", STAC_92HD83XXX_REF),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba,
                      "unknown Dell", STAC_DELL_S14),
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600,
-                     "HP", STAC_92HD83XXX_HP),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x1028,
+                     "Dell Vostro 3500", STAC_DELL_VOSTRO_3500),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1657,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355B,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355C,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355D,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355E,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355F,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3560,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358B,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358C,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358D,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3591,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3592,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3593,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561,
+                         "HP", STAC_HP_ZEPHYR),
+       {} /* terminator */
+};
+
+static const struct snd_pci_quirk stac92hd83xxx_codec_id_cfg_tbl[] = {
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561,
+                         "HP", STAC_HP_ZEPHYR),
        {} /* terminator */
 };
 
@@ -2788,7 +2858,8 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
        }
 
        if (control) {
-               strcpy(name, hda_get_input_pin_label(codec, nid, 1));
+               snd_hda_get_pin_label(codec, nid, &spec->autocfg,
+                                     name, sizeof(name), NULL);
                return stac92xx_add_control(codec->spec, control,
                                        strcat(name, " Jack Mode"), nid);
        }
@@ -2896,8 +2967,9 @@ static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
 static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
 {
        struct sigmatel_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int j, conn_len;
-       hda_nid_t conn[HDA_MAX_CONNECTIONS];
+       hda_nid_t conn[HDA_MAX_CONNECTIONS], fallback_dac;
        unsigned int wcaps, wtype;
 
        conn_len = snd_hda_get_connections(codec, nid, conn,
@@ -2925,10 +2997,21 @@ static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid)
                        return conn[j];
                }
        }
-       /* if all DACs are already assigned, connect to the primary DAC */
+
+       /* if all DACs are already assigned, connect to the primary DAC,
+          unless we're assigning a secondary headphone */
+       fallback_dac = spec->multiout.dac_nids[0];
+       if (spec->multiout.hp_nid) {
+               for (j = 0; j < cfg->hp_outs; j++)
+                       if (cfg->hp_pins[j] == nid) {
+                               fallback_dac = spec->multiout.hp_nid;
+                               break;
+                       }
+       }
+
        if (conn_len > 1) {
                for (j = 0; j < conn_len; j++) {
-                       if (conn[j] == spec->multiout.dac_nids[0]) {
+                       if (conn[j] == fallback_dac) {
                                snd_hda_codec_write_cache(codec, nid, 0,
                                                  AC_VERB_SET_CONNECT_SEL, j);
                                break;
@@ -3454,7 +3537,7 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
        for (i = 0; i < spec->num_dmics; i++) {
                hda_nid_t nid;
                int index, type_idx;
-               const char *label;
+               char label[32];
 
                nid = spec->dmic_nids[i];
                if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
@@ -3467,7 +3550,8 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
                if (index < 0)
                        continue;
 
-               label = hda_get_input_pin_label(codec, nid, 1);
+               snd_hda_get_pin_label(codec, nid, &spec->autocfg,
+                                     label, sizeof(label), NULL);
                snd_hda_add_imux_item(dimux, label, index, &type_idx);
                if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1)
                        snd_hda_add_imux_item(imux, label, index, &type_idx);
@@ -3703,9 +3787,10 @@ static int is_dual_headphones(struct hda_codec *codec)
 }
 
 
-static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in)
+static int stac92xx_parse_auto_config(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
+       hda_nid_t dig_out = 0, dig_in = 0;
        int hp_swap = 0;
        int i, err;
 
@@ -3888,6 +3973,22 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
        if (spec->multiout.max_channels > 2)
                spec->surr_switch = 1;
 
+       /* find digital out and in converters */
+       for (i = codec->start_nid; i < codec->start_nid + codec->num_nodes; i++) {
+               unsigned int wid_caps = get_wcaps(codec, i);
+               if (wid_caps & AC_WCAP_DIGITAL) {
+                       switch (get_wcaps_type(wid_caps)) {
+                       case AC_WID_AUD_OUT:
+                               if (!dig_out)
+                                       dig_out = i;
+                               break;
+                       case AC_WID_AUD_IN:
+                               if (!dig_in)
+                                       dig_in = i;
+                               break;
+                       }
+               }
+       }
        if (spec->autocfg.dig_outs)
                spec->multiout.dig_out_nid = dig_out;
        if (dig_in && spec->autocfg.dig_in_pin)
@@ -4020,6 +4121,8 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
 {
        unsigned int gpiostate, gpiomask, gpiodir;
 
+       snd_printdd("%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data);
+
        gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
                                       AC_VERB_GET_GPIO_DATA, 0);
        gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
@@ -4046,73 +4149,18 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
                           AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
 }
 
-static int stac92xx_add_jack(struct hda_codec *codec,
-               hda_nid_t nid, int type)
-{
-#ifdef CONFIG_SND_HDA_INPUT_JACK
-       int def_conf = snd_hda_codec_get_pincfg(codec, nid);
-       int connectivity = get_defcfg_connect(def_conf);
-       char name[32];
-       int err;
-
-       if (connectivity && connectivity != AC_JACK_PORT_FIXED)
-               return 0;
-
-       snprintf(name, sizeof(name), "%s at %s %s Jack",
-               snd_hda_get_jack_type(def_conf),
-               snd_hda_get_jack_connectivity(def_conf),
-               snd_hda_get_jack_location(def_conf));
-
-       err = snd_hda_input_jack_add(codec, nid, type, name);
-       if (err < 0)
-               return err;
-#endif /* CONFIG_SND_HDA_INPUT_JACK */
-       return 0;
-}
-
-static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
+static int stac_add_event(struct hda_codec *codec, hda_nid_t nid,
                          unsigned char type, int data)
 {
-       struct sigmatel_event *event;
+       struct hda_jack_tbl *event;
 
-       snd_array_init(&spec->events, sizeof(*event), 32);
-       event = snd_array_new(&spec->events);
+       event = snd_hda_jack_tbl_new(codec, nid);
        if (!event)
                return -ENOMEM;
-       event->nid = nid;
-       event->type = type;
-       event->tag = spec->events.used;
-       event->data = data;
+       event->action = type;
+       event->private_data = data;
 
-       return event->tag;
-}
-
-static struct sigmatel_event *stac_get_event(struct hda_codec *codec,
-                                            hda_nid_t nid)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       struct sigmatel_event *event = spec->events.list;
-       int i;
-
-       for (i = 0; i < spec->events.used; i++, event++) {
-               if (event->nid == nid)
-                       return event;
-       }
-       return NULL;
-}
-
-static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec,
-                                                     unsigned char tag)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       struct sigmatel_event *event = spec->events.list;
-       int i;
-
-       for (i = 0; i < spec->events.used; i++, event++) {
-               if (event->tag == tag)
-                       return event;
-       }
-       return NULL;
+       return 0;
 }
 
 /* check if given nid is a valid pin and no other events are assigned
@@ -4122,34 +4170,29 @@ static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec,
 static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
                             unsigned int type)
 {
-       struct sigmatel_event *event;
-       int tag;
+       struct hda_jack_tbl *event;
 
        if (!is_jack_detectable(codec, nid))
                return 0;
-       event = stac_get_event(codec, nid);
-       if (event) {
-               if (event->type != type)
-                       return 0;
-               tag = event->tag;
-       } else {
-               tag = stac_add_event(codec->spec, nid, type, 0);
-               if (tag < 0)
-                       return 0;
-       }
-       snd_hda_codec_write_cache(codec, nid, 0,
-                                 AC_VERB_SET_UNSOLICITED_ENABLE,
-                                 AC_USRSP_EN | tag);
+       event = snd_hda_jack_tbl_new(codec, nid);
+       if (!event)
+               return -ENOMEM;
+       if (event->action && event->action != type)
+               return 0;
+       event->action = type;
+       snd_hda_jack_detect_enable(codec, nid, 0);
        return 1;
 }
 
-static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
+static int is_nid_out_jack_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
 {
        int i;
        for (i = 0; i < cfg->hp_outs; i++)
                if (cfg->hp_pins[i] == nid)
                        return 1; /* nid is a HP-Out */
-
+       for (i = 0; i < cfg->line_outs; i++)
+               if (cfg->line_out_pins[i] == nid)
+                       return 1; /* nid is a line-Out */
        return 0; /* nid is not a HP-Out */
 };
 
@@ -4216,6 +4259,27 @@ static void stac_store_hints(struct hda_codec *codec)
        }
 }
 
+static void stac_issue_unsol_events(struct hda_codec *codec, int num_pins,
+                                   const hda_nid_t *pins)
+{
+       while (num_pins--)
+               stac_issue_unsol_event(codec, *pins++);
+}
+
+/* fake event to set up pins */
+static void stac_fake_hp_events(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (spec->autocfg.hp_outs)
+               stac_issue_unsol_events(codec, spec->autocfg.hp_outs,
+                                       spec->autocfg.hp_pins);
+       if (spec->autocfg.line_outs &&
+           spec->autocfg.line_out_pins[0] != spec->autocfg.hp_pins[0])
+               stac_issue_unsol_events(codec, spec->autocfg.line_outs,
+                                       spec->autocfg.line_out_pins);
+}
+
 static int stac92xx_init(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -4266,10 +4330,7 @@ static int stac92xx_init(struct hda_codec *codec)
                stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
                                AC_PINCTL_OUT_EN);
                /* fake event to set up pins */
-               if (cfg->hp_pins[0])
-                       stac_issue_unsol_event(codec, cfg->hp_pins[0]);
-               else if (cfg->line_out_pins[0])
-                       stac_issue_unsol_event(codec, cfg->line_out_pins[0]);
+               stac_fake_hp_events(codec);
        } else {
                stac92xx_auto_init_multi_out(codec);
                stac92xx_auto_init_hp_out(codec);
@@ -4330,12 +4391,14 @@ static int stac92xx_init(struct hda_codec *codec)
                int pinctl, def_conf;
 
                /* power on when no jack detection is available */
-               if (!spec->hp_detect) {
+               /* or when the VREF is used for controlling LED */
+               if (!spec->hp_detect ||
+                   spec->vref_mute_led_nid == nid) {
                        stac_toggle_power_map(codec, nid, 1);
                        continue;
                }
 
-               if (is_nid_hp_pin(cfg, nid))
+               if (is_nid_out_jack_pin(cfg, nid))
                        continue; /* already has an unsol event */
 
                pinctl = snd_hda_codec_read(codec, nid, 0,
@@ -4352,18 +4415,23 @@ static int stac92xx_init(struct hda_codec *codec)
                def_conf = get_defcfg_connect(def_conf);
                /* skip any ports that don't have jacks since presence
                 * detection is useless */
-               if (def_conf != AC_JACK_PORT_COMPLEX) {
-                       if (def_conf != AC_JACK_PORT_NONE)
-                               stac_toggle_power_map(codec, nid, 1);
+               if (def_conf != AC_JACK_PORT_NONE &&
+                   !is_jack_detectable(codec, nid)) {
+                       stac_toggle_power_map(codec, nid, 1);
                        continue;
                }
-               if (enable_pin_detect(codec, nid, STAC_PWR_EVENT))
+               if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) {
                        stac_issue_unsol_event(codec, nid);
+                       continue;
+               }
+               /* none of the above, turn the port OFF */
+               stac_toggle_power_map(codec, nid, 0);
        }
 
+       snd_hda_jack_report_sync(codec);
+
        /* sync mute LED */
-       if (spec->gpio_led)
-               hda_call_check_power_status(codec, 0x01);
+       snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
        if (spec->dac_list)
                stac92xx_power_down(codec);
        return 0;
@@ -4382,11 +4450,26 @@ static void stac92xx_free_kctls(struct hda_codec *codec)
        snd_array_free(&spec->kctls);
 }
 
+static void stac92xx_shutup_pins(struct hda_codec *codec)
+{
+       unsigned int i, def_conf;
+
+       if (codec->bus->shutdown)
+               return;
+       for (i = 0; i < codec->init_pins.used; i++) {
+               struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
+               def_conf = snd_hda_codec_get_pincfg(codec, pin->nid);
+               if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
+                       snd_hda_codec_write(codec, pin->nid, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+       }
+}
+
 static void stac92xx_shutup(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
 
-       snd_hda_shutup_pins(codec);
+       stac92xx_shutup_pins(codec);
 
        if (spec->eapd_mask)
                stac_gpio_set(codec, spec->gpio_mask,
@@ -4402,8 +4485,6 @@ static void stac92xx_free(struct hda_codec *codec)
                return;
 
        stac92xx_shutup(codec);
-       snd_hda_input_jack_free(codec);
-       snd_array_free(&spec->events);
 
        kfree(spec);
        snd_hda_detach_beep_device(codec);
@@ -4568,7 +4649,7 @@ static void stac92xx_hp_detect(struct hda_codec *codec)
                unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN;
                if (no_hp_sensing(spec, i))
                        continue;
-               if (presence)
+               if (1 /*presence*/)
                        stac92xx_set_pinctl(codec, cfg->hp_pins[i], val);
 #if 0 /* FIXME */
 /* Resetting the pinctl like below may lead to (a sort of) regressions
@@ -4599,11 +4680,7 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
        if (idx >= spec->num_pwrs)
                return;
 
-       /* several codecs have two power down bits */
-       if (spec->pwr_mapping)
-               idx = spec->pwr_mapping[idx];
-       else
-               idx = 1 << idx;
+       idx = 1 << idx;
 
        val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff;
        if (enable)
@@ -4671,26 +4748,13 @@ static void stac92xx_mic_detect(struct hda_codec *codec)
                                          mic->mux_idx);
 }
 
-static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct sigmatel_event *event = stac_get_event(codec, nid);
-       if (!event)
-               return;
-       codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26);
-}
-
-static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
+static void handle_unsol_event(struct hda_codec *codec,
+                              struct hda_jack_tbl *event)
 {
        struct sigmatel_spec *spec = codec->spec;
-       struct sigmatel_event *event;
-       int tag, data;
-
-       tag = (res >> 26) & 0x7f;
-       event = stac_get_event_from_tag(codec, tag);
-       if (!event)
-               return;
+       int data;
 
-       switch (event->type) {
+       switch (event->action) {
        case STAC_HP_EVENT:
        case STAC_LO_EVENT:
                stac92xx_hp_detect(codec);
@@ -4700,7 +4764,7 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
                break;
        }
 
-       switch (event->type) {
+       switch (event->action) {
        case STAC_HP_EVENT:
        case STAC_LO_EVENT:
        case STAC_MIC_EVENT:
@@ -4708,7 +4772,6 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
        case STAC_PWR_EVENT:
                if (spec->num_pwrs > 0)
                        stac92xx_pin_sense(codec, event->nid);
-               snd_hda_input_jack_report(codec, event->nid);
 
                switch (codec->subsystem_id) {
                case 0x103c308f:
@@ -4733,11 +4796,33 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
                                          AC_VERB_GET_GPIO_DATA, 0);
                /* toggle VREF state based on GPIOx status */
                snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
-                                   !!(data & (1 << event->data)));
+                                   !!(data & (1 << event->private_data)));
                break;
        }
 }
 
+static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct hda_jack_tbl *event = snd_hda_jack_tbl_get(codec, nid);
+       if (!event)
+               return;
+       handle_unsol_event(codec, event);
+}
+
+static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       struct hda_jack_tbl *event;
+       int tag;
+
+       tag = (res >> 26) & 0x7f;
+       event = snd_hda_jack_tbl_get_from_tag(codec, tag);
+       if (!event)
+               return;
+       event->jack_dirty = 1;
+       handle_unsol_event(codec, event);
+       snd_hda_jack_report_sync(codec);
+}
+
 static int hp_blike_system(u32 subsystem_id);
 
 static void set_hp_led_gpio(struct hda_codec *codec)
@@ -4776,7 +4861,7 @@ static void set_hp_led_gpio(struct hda_codec *codec)
  * Need more information on whether it is true across the entire series.
  * -- kunal
  */
-static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity)
+static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity)
 {
        struct sigmatel_spec *spec = codec->spec;
        const struct dmi_device *dev = NULL;
@@ -4784,10 +4869,17 @@ static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity)
        if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) {
                while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING,
                                                                NULL, dev))) {
-                       if (sscanf(dev->name, "HP_Mute_LED_%d_%d",
+                       if (sscanf(dev->name, "HP_Mute_LED_%d_%x",
                                  &spec->gpio_led_polarity,
                                  &spec->gpio_led) == 2) {
-                               spec->gpio_led = 1 << spec->gpio_led;
+                               unsigned int max_gpio;
+                               max_gpio = snd_hda_param_read(codec, codec->afg,
+                                                             AC_PAR_GPIO_CAP);
+                               max_gpio &= AC_GPIO_IO_COUNT;
+                               if (spec->gpio_led < max_gpio)
+                                       spec->gpio_led = 1 << spec->gpio_led;
+                               else
+                                       spec->vref_mute_led_nid = spec->gpio_led;
                                return 1;
                        }
                        if (sscanf(dev->name, "HP_Mute_LED_%d",
@@ -4795,13 +4887,28 @@ static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity)
                                set_hp_led_gpio(codec);
                                return 1;
                        }
+                       /* BIOS bug: unfilled OEM string */
+                       if (strstr(dev->name, "HP_Mute_LED_P_G")) {
+                               set_hp_led_gpio(codec);
+                               switch (codec->subsystem_id) {
+                               case 0x103c148a:
+                                       spec->gpio_led_polarity = 0;
+                                       break;
+                               default:
+                                       spec->gpio_led_polarity = 1;
+                                       break;
+                               }
+                               return 1;
+                       }
                }
 
                /*
                 * Fallback case - if we don't find the DMI strings,
-                * we statically set the GPIO - if not a B-series system.
+                * we statically set the GPIO - if not a B-series system
+                * and default polarity is provided
                 */
-               if (!hp_blike_system(codec->subsystem_id)) {
+               if (!hp_blike_system(codec->subsystem_id) &&
+                       (default_polarity == 0 || default_polarity == 1)) {
                        set_hp_led_gpio(codec);
                        spec->gpio_led_polarity = default_polarity;
                        return 1;
@@ -4885,75 +4992,90 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer,
 #define stac927x_proc_hook     NULL
 #endif
 
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 static int stac92xx_resume(struct hda_codec *codec)
 {
-       struct sigmatel_spec *spec = codec->spec;
-
        stac92xx_init(codec);
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
        /* fake event to set up pins again to override cached values */
-       if (spec->hp_detect) {
-               if (spec->autocfg.hp_pins[0])
-                       stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0]);
-               else if (spec->autocfg.line_out_pins[0])
-                       stac_issue_unsol_event(codec,
-                                              spec->autocfg.line_out_pins[0]);
-       }
-       /* sync mute LED */
-       if (spec->gpio_led)
-               hda_call_check_power_status(codec, 0x01);
+       stac_fake_hp_events(codec);
        return 0;
 }
 
-/*
- * using power check for controlling mute led of HP notebooks
- * check for mute state only on Speakers (nid = 0x10)
- *
- * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise
- * the LED is NOT working properly !
- *
- * Changed name to reflect that it now works for any designated
- * model, not just HP HDX.
- */
+static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
+{
+       stac92xx_shutup(codec);
+       return 0;
+}
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static int stac92xx_hp_check_power_status(struct hda_codec *codec,
-                                             hda_nid_t nid)
+static int stac92xx_pre_resume(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
-       int i, muted = 1;
 
-       for (i = 0; i < spec->multiout.num_dacs; i++) {
-               nid = spec->multiout.dac_nids[i];
-               if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
-                     HDA_AMP_MUTE)) {
-                       muted = 0; /* something heard */
-                       break;
-               }
-       }
-       if (muted)
-               spec->gpio_data &= ~spec->gpio_led; /* orange */
-       else
-               spec->gpio_data |= spec->gpio_led; /* white */
+       /* sync mute LED */
+       if (spec->vref_mute_led_nid)
+               stac_vrefout_set(codec, spec->vref_mute_led_nid,
+                                spec->vref_led);
+       else if (spec->gpio_led)
+               stac_gpio_set(codec, spec->gpio_mask,
+                             spec->gpio_dir, spec->gpio_data);
+       return 0;
+}
 
-       if (!spec->gpio_led_polarity) {
-               /* LED state is inverted on these systems */
-               spec->gpio_data ^= spec->gpio_led;
-       }
+static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
+                               unsigned int power_state)
+{
+       unsigned int afg_power_state = power_state;
+       struct sigmatel_spec *spec = codec->spec;
 
-       stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
-       return 0;
+       if (power_state == AC_PWRST_D3) {
+               if (spec->vref_mute_led_nid) {
+                       /* with vref-out pin used for mute led control
+                        * codec AFG is prevented from D3 state
+                        */
+                       afg_power_state = AC_PWRST_D1;
+               }
+               /* this delay seems necessary to avoid click noise at power-down */
+               msleep(100);
+       }
+       snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
+                       afg_power_state);
+       snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
 }
-#endif
+#else
+#define stac92xx_suspend       NULL
+#define stac92xx_resume                NULL
+#define stac92xx_pre_resume    NULL
+#define stac92xx_set_power_state NULL
+#endif /* CONFIG_PM */
 
-static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
+/* update mute-LED accoring to the master switch */
+static void stac92xx_update_led_status(struct hda_codec *codec, int enabled)
 {
-       stac92xx_shutup(codec);
-       return 0;
+       struct sigmatel_spec *spec = codec->spec;
+       int muted = !enabled;
+
+       if (!spec->gpio_led)
+               return;
+
+       /* LED state is inverted on these systems */
+       if (spec->gpio_led_polarity)
+               muted = !muted;
+
+       if (!spec->vref_mute_led_nid) {
+               if (muted)
+                       spec->gpio_data |= spec->gpio_led;
+               else
+                       spec->gpio_data &= ~spec->gpio_led;
+               stac_gpio_set(codec, spec->gpio_mask,
+                               spec->gpio_dir, spec->gpio_data);
+       } else {
+               spec->vref_led = muted ? AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD;
+               stac_vrefout_set(codec, spec->vref_mute_led_nid,
+                                spec->vref_led);
+       }
 }
-#endif
 
 static const struct hda_codec_ops stac92xx_patch_ops = {
        .build_controls = stac92xx_build_controls,
@@ -4961,7 +5083,7 @@ static const struct hda_codec_ops stac92xx_patch_ops = {
        .init = stac92xx_init,
        .free = stac92xx_free,
        .unsol_event = stac92xx_unsol_event,
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
        .suspend = stac92xx_suspend,
        .resume = stac92xx_resume,
 #endif
@@ -5096,7 +5218,7 @@ static int patch_stac925x(struct hda_codec *codec)
        spec->capvols = stac925x_capvols;
        spec->capsws = stac925x_capsws;
 
-       err = stac92xx_parse_auto_config(codec, 0x8, 0x7);
+       err = stac92xx_parse_auto_config(codec);
        if (!err) {
                if (spec->board_config < 0) {
                        printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -5237,7 +5359,7 @@ again:
        spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
        spec->pwr_nids = stac92hd73xx_pwr_nids;
 
-       err = stac92xx_parse_auto_config(codec, 0x25, 0x27);
+       err = stac92xx_parse_auto_config(codec);
 
        if (!err) {
                if (spec->board_config < 0) {
@@ -5406,9 +5528,7 @@ static void stac92hd8x_fill_auto_spec(struct hda_codec *codec)
 static int patch_stac92hd83xxx(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
-       hda_nid_t conn[STAC92HD83_DAC_COUNT + 1];
        int err;
-       int num_dacs;
 
        spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -5419,9 +5539,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
                snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e);
        }
 
-       /* reset pin power-down; Windows may leave these bits after reboot */
-       snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7EC, 0);
-       snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0);
        codec->no_trigger_sense = 1;
        codec->spec = spec;
 
@@ -5431,7 +5548,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
        spec->digbeep_nid = 0x21;
        spec->pwr_nids = stac92hd83xxx_pwr_nids;
-       spec->pwr_mapping = stac92hd83xxx_pwr_mapping;
        spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
        spec->multiout.dac_nids = spec->dac_nids;
        spec->init = stac92hd83xxx_core_init;
@@ -5440,6 +5556,12 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
                                                        STAC_92HD83XXX_MODELS,
                                                        stac92hd83xxx_models,
                                                        stac92hd83xxx_cfg_tbl);
+       /* check codec subsystem id if not found */
+       if (spec->board_config < 0)
+               spec->board_config =
+                       snd_hda_check_board_codec_sid_config(codec,
+                               STAC_92HD83XXX_MODELS, stac92hd83xxx_models,
+                               stac92hd83xxx_codec_id_cfg_tbl);
 again:
        if (spec->board_config < 0)
                snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
@@ -5448,45 +5570,34 @@ again:
                stac92xx_set_config_regs(codec,
                                stac92hd83xxx_brd_tbl[spec->board_config]);
 
-       switch (codec->vendor_id) {
-       case 0x111d76d1:
-       case 0x111d76d9:
-       case 0x111d76e5:
-       case 0x111d7666:
-       case 0x111d7667:
-       case 0x111d7668:
-       case 0x111d7669:
-       case 0x111d76e3:
-       case 0x111d7604:
-       case 0x111d76d4:
-       case 0x111d7605:
-       case 0x111d76d5:
-       case 0x111d76e7:
-               if (spec->board_config == STAC_92HD83XXX_PWR_REF)
-                       break;
-               spec->num_pwrs = 0;
+       codec->patch_ops = stac92xx_patch_ops;
+
+       switch (spec->board_config) {
+       case STAC_HP_ZEPHYR:
+               spec->init = stac92hd83xxx_hp_zephyr_init;
                break;
        }
 
-       codec->patch_ops = stac92xx_patch_ops;
-
-       if (find_mute_led_gpio(codec, 0))
+       if (find_mute_led_cfg(codec, -1/*no default cfg*/))
                snd_printd("mute LED gpio %d polarity %d\n",
                                spec->gpio_led,
                                spec->gpio_led_polarity);
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
        if (spec->gpio_led) {
-               spec->gpio_mask |= spec->gpio_led;
-               spec->gpio_dir |= spec->gpio_led;
-               spec->gpio_data |= spec->gpio_led;
-               /* register check_power_status callback. */
-               codec->patch_ops.check_power_status =
-                       stac92xx_hp_check_power_status;
+               if (!spec->vref_mute_led_nid) {
+                       spec->gpio_mask |= spec->gpio_led;
+                       spec->gpio_dir |= spec->gpio_led;
+                       spec->gpio_data |= spec->gpio_led;
+               } else {
+                       codec->patch_ops.set_power_state =
+                                       stac92xx_set_power_state;
+               }
+#ifdef CONFIG_PM
+               codec->patch_ops.pre_resume = stac92xx_pre_resume;
+#endif
        }
-#endif 
 
-       err = stac92xx_parse_auto_config(codec, 0x1d, 0);
+       err = stac92xx_parse_auto_config(codec);
        if (!err) {
                if (spec->board_config < 0) {
                        printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -5502,22 +5613,6 @@ again:
                return err;
        }
 
-       /* docking output support */
-       num_dacs = snd_hda_get_connections(codec, 0xF,
-                               conn, STAC92HD83_DAC_COUNT + 1) - 1;
-       /* skip non-DAC connections */
-       while (num_dacs >= 0 &&
-                       (get_wcaps_type(get_wcaps(codec, conn[num_dacs]))
-                                       != AC_WID_AUD_OUT))
-               num_dacs--;
-       /* set port E and F to select the last DAC */
-       if (num_dacs >= 0) {
-               snd_hda_codec_write_cache(codec, 0xE, 0,
-                       AC_VERB_SET_CONNECT_SEL, num_dacs);
-               snd_hda_codec_write_cache(codec, 0xF, 0,
-                       AC_VERB_SET_CONNECT_SEL, num_dacs);
-       }
-
        codec->proc_widget_hook = stac92hd_proc_hook;
 
        return 0;
@@ -5669,15 +5764,13 @@ again:
                switch (spec->board_config) {
                case STAC_HP_M4:
                        /* Enable VREF power saving on GPIO1 detect */
-                       err = stac_add_event(spec, codec->afg,
+                       err = stac_add_event(codec, codec->afg,
                                             STAC_VREF_EVENT, 0x02);
                        if (err < 0)
                                return err;
                        snd_hda_codec_write_cache(codec, codec->afg, 0,
                                AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
-                       snd_hda_codec_write_cache(codec, codec->afg, 0,
-                               AC_VERB_SET_UNSOLICITED_ENABLE,
-                               AC_USRSP_EN | err);
+                       snd_hda_jack_detect_enable(codec, codec->afg, 0);
                        spec->gpio_mask |= 0x02;
                        break;
                }
@@ -5685,8 +5778,6 @@ again:
                    (codec->revision_id & 0xf) == 1)
                        spec->stream_delay = 40; /* 40 milliseconds */
 
-               /* no output amps */
-               spec->num_pwrs = 0;
                /* disable VSW */
                spec->init = stac92hd71bxx_core_init;
                unmute_init++;
@@ -5701,8 +5792,6 @@ again:
                if ((codec->revision_id & 0xf) == 1)
                        spec->stream_delay = 40; /* 40 milliseconds */
 
-               /* no output amps */
-               spec->num_pwrs = 0;
                /* fallthru */
        default:
                spec->init = stac92hd71bxx_core_init;
@@ -5798,25 +5887,28 @@ again:
                }
        }
 
-       if (find_mute_led_gpio(codec, 1))
+       if (find_mute_led_cfg(codec, 1))
                snd_printd("mute LED gpio %d polarity %d\n",
                                spec->gpio_led,
                                spec->gpio_led_polarity);
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
        if (spec->gpio_led) {
-               spec->gpio_mask |= spec->gpio_led;
-               spec->gpio_dir |= spec->gpio_led;
-               spec->gpio_data |= spec->gpio_led;
-               /* register check_power_status callback. */
-               codec->patch_ops.check_power_status =
-                       stac92xx_hp_check_power_status;
+               if (!spec->vref_mute_led_nid) {
+                       spec->gpio_mask |= spec->gpio_led;
+                       spec->gpio_dir |= spec->gpio_led;
+                       spec->gpio_data |= spec->gpio_led;
+               } else {
+                       codec->patch_ops.set_power_state =
+                                       stac92xx_set_power_state;
+               }
+#ifdef CONFIG_PM
+               codec->patch_ops.pre_resume = stac92xx_pre_resume;
+#endif
        }
-#endif 
 
        spec->multiout.dac_nids = spec->dac_nids;
 
-       err = stac92xx_parse_auto_config(codec, 0x21, 0);
+       err = stac92xx_parse_auto_config(codec);
        if (!err) {
                if (spec->board_config < 0) {
                        printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -5925,7 +6017,7 @@ static int patch_stac922x(struct hda_codec *codec)
 
        spec->multiout.dac_nids = spec->dac_nids;
        
-       err = stac92xx_parse_auto_config(codec, 0x08, 0x09);
+       err = stac92xx_parse_auto_config(codec);
        if (!err) {
                if (spec->board_config < 0) {
                        printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -6050,7 +6142,7 @@ static int patch_stac927x(struct hda_codec *codec)
        spec->aloopback_shift = 0;
        spec->eapd_switch = 1;
 
-       err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
+       err = stac92xx_parse_auto_config(codec);
        if (!err) {
                if (spec->board_config < 0) {
                        printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -6147,14 +6239,12 @@ static int patch_stac9205(struct hda_codec *codec)
                snd_hda_codec_set_pincfg(codec, 0x20, 0x1c410030);
 
                /* Enable unsol response for GPIO4/Dock HP connection */
-               err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01);
+               err = stac_add_event(codec, codec->afg, STAC_VREF_EVENT, 0x01);
                if (err < 0)
                        return err;
                snd_hda_codec_write_cache(codec, codec->afg, 0,
                        AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
-               snd_hda_codec_write_cache(codec, codec->afg, 0,
-                                         AC_VERB_SET_UNSOLICITED_ENABLE,
-                                         AC_USRSP_EN | err);
+               snd_hda_jack_detect_enable(codec, codec->afg, 0);
 
                spec->gpio_dir = 0x0b;
                spec->eapd_mask = 0x01;
@@ -6175,7 +6265,7 @@ static int patch_stac9205(struct hda_codec *codec)
                break;
        }
 
-       err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
+       err = stac92xx_parse_auto_config(codec);
        if (!err) {
                if (spec->board_config < 0) {
                        printk(KERN_WARNING "hda_codec: No auto-config is "
@@ -6280,7 +6370,7 @@ static int patch_stac9872(struct hda_codec *codec)
        spec->capvols = stac9872_capvols;
        spec->capsws = stac9872_capsws;
 
-       err = stac92xx_parse_auto_config(codec, 0x10, 0x12);
+       err = stac92xx_parse_auto_config(codec);
        if (err < 0) {
                stac92xx_free(codec);
                return -EINVAL;
@@ -6380,10 +6470,23 @@ static const struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx },
        { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx },
        { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76df, .name = "92HD93BXX", .patch = patch_stac92hd83xxx},
        { .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx},
        { .id = 0x111d76e3, .name = "92HD98BXX", .patch = patch_stac92hd83xxx},
        { .id = 0x111d76e5, .name = "92HD99BXX", .patch = patch_stac92hd83xxx},
        { .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76e8, .name = "92HD66B1X5", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76e9, .name = "92HD66B2X5", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76ea, .name = "92HD66B3X5", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76eb, .name = "92HD66C1X5", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76ec, .name = "92HD66C2X5", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76ed, .name = "92HD66C3X5", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76ee, .name = "92HD66B1X3", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76ef, .name = "92HD66B2X3", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76f0, .name = "92HD66B3X3", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76f1, .name = "92HD66C1X3", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76f2, .name = "92HD66C2X3", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76f3, .name = "92HD66C3/65", .patch = patch_stac92hd83xxx},
        {} /* terminator */
 };