]> git.karo-electronics.de Git - linux-beck.git/blobdiff - sound/pci/hda/patch_sigmatel.c
Merge branch 'test/hda-jack' into topic/hda
[linux-beck.git] / sound / pci / hda / patch_sigmatel.c
index 4e715fefebefb1b0ae5c9e43fe73000447d11664..03145aec65f1eaeb2db1b44fd7eddd8ca588fafb 100644 (file)
@@ -37,6 +37,7 @@
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_beep.h"
+#include "hda_jack.h"
 
 enum {
        STAC_VREF_EVENT = 1,
@@ -95,7 +96,7 @@ 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_92HD83XXX_MODELS
@@ -175,13 +176,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;
@@ -214,6 +208,7 @@ 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 */
@@ -226,13 +221,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;
@@ -373,18 +364,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,
 };
@@ -1096,13 +1084,10 @@ static const char * const slave_sws[] = {
 };
 
 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;
        int err;
        int i;
 
@@ -1188,31 +1173,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;       
 }
@@ -1644,6 +1607,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", STAC_ALIENWARE_M17X),
        {} /* terminator */
 };
 
@@ -1659,6 +1624,12 @@ 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,
@@ -1675,6 +1646,7 @@ 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,
 };
@@ -1684,7 +1656,7 @@ 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",
 };
@@ -1697,8 +1669,8 @@ 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,
@@ -2865,7 +2837,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);
        }
@@ -3543,7 +3516,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)
@@ -3556,7 +3529,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);
@@ -4154,65 +4128,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);
-
-       if (connectivity && connectivity != AC_JACK_PORT_FIXED)
-               return 0;
-
-       return snd_hda_input_jack_add(codec, nid, type, NULL);
-#else
-       return 0;
-#endif /* CONFIG_SND_HDA_INPUT_JACK */
-}
-
-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
@@ -4222,24 +4149,17 @@ 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;
 }
 
@@ -4309,12 +4229,10 @@ static void stac_store_hints(struct hda_codec *codec)
                spec->eapd_switch = val;
        get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity);
        if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
-               if (spec->gpio_led <= 8) {
-                       spec->gpio_mask |= spec->gpio_led;
-                       spec->gpio_dir |= spec->gpio_led;
-                       if (spec->gpio_led_polarity)
-                               spec->gpio_data |= spec->gpio_led;
-               }
+               spec->gpio_mask |= spec->gpio_led;
+               spec->gpio_dir |= spec->gpio_led;
+               if (spec->gpio_led_polarity)
+                       spec->gpio_data |= spec->gpio_led;
        }
 }
 
@@ -4432,7 +4350,9 @@ 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;
                }
@@ -4459,10 +4379,16 @@ static int stac92xx_init(struct hda_codec *codec)
                                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);
@@ -4519,8 +4445,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);
@@ -4716,11 +4640,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)
@@ -4788,26 +4708,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);
@@ -4817,7 +4724,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:
@@ -4825,7 +4732,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:
@@ -4850,11 +4756,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)
@@ -4893,7 +4821,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;
@@ -4904,8 +4832,14 @@ static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity)
                        if (sscanf(dev->name, "HP_Mute_LED_%d_%x",
                                  &spec->gpio_led_polarity,
                                  &spec->gpio_led) == 2) {
-                               if (spec->gpio_led < 4)
+                               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",
@@ -4913,13 +4847,21 @@ 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);
+                               spec->gpio_led_polarity = 1;
+                               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;
@@ -5034,29 +4976,12 @@ static int stac92xx_pre_resume(struct hda_codec *codec)
        struct sigmatel_spec *spec = codec->spec;
 
        /* sync mute LED */
-       if (spec->gpio_led) {
-               if (spec->gpio_led <= 8) {
-                       stac_gpio_set(codec, spec->gpio_mask,
-                                       spec->gpio_dir, spec->gpio_data);
-               } else {
-                       stac_vrefout_set(codec,
-                                       spec->gpio_led, spec->vref_led);
-               }
-       }
-       return 0;
-}
-
-static int stac92xx_post_suspend(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       if (spec->gpio_led > 8) {
-               /* with vref-out pin used for mute led control
-                * codec AFG is prevented from D3 state, but on
-                * system suspend it can (and should) be used
-                */
-               snd_hda_codec_read(codec, codec->afg, 0,
-                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-       }
+       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;
 }
 
@@ -5067,7 +4992,7 @@ static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
        struct sigmatel_spec *spec = codec->spec;
 
        if (power_state == AC_PWRST_D3) {
-               if (spec->gpio_led > 8) {
+               if (spec->vref_mute_led_nid) {
                        /* with vref-out pin used for mute led control
                         * codec AFG is prevented from D3 state
                         */
@@ -5120,7 +5045,7 @@ static int stac92xx_update_led_status(struct hda_codec *codec)
                }
        }
        /*polarity defines *not* muted state level*/
-       if (spec->gpio_led <= 8) {
+       if (!spec->vref_mute_led_nid) {
                if (muted)
                        spec->gpio_data &= ~spec->gpio_led; /* orange */
                else
@@ -5138,7 +5063,8 @@ static int stac92xx_update_led_status(struct hda_codec *codec)
                muted_lvl = spec->gpio_led_polarity ?
                                AC_PINCTL_VREF_GRD : AC_PINCTL_VREF_HIZ;
                spec->vref_led = muted ? muted_lvl : notmtd_lvl;
-               stac_vrefout_set(codec, spec->gpio_led, spec->vref_led);
+               stac_vrefout_set(codec, spec->vref_mute_led_nid,
+                                spec->vref_led);
        }
        return 0;
 }
@@ -5618,9 +5544,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;
 
@@ -5630,7 +5553,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;
@@ -5647,27 +5569,22 @@ again:
                stac92xx_set_config_regs(codec,
                                stac92hd83xxx_brd_tbl[spec->board_config]);
 
-       if (spec->board_config != STAC_92HD83XXX_PWR_REF)
-               spec->num_pwrs = 0;
-
        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) {
-               if (spec->gpio_led <= 8) {
+               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;
-                       codec->patch_ops.post_suspend =
-                                       stac92xx_post_suspend;
                }
                codec->patch_ops.pre_resume = stac92xx_pre_resume;
                codec->patch_ops.check_power_status =
@@ -5842,15 +5759,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;
                }
@@ -5858,8 +5773,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++;
@@ -5874,8 +5787,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;
@@ -5971,22 +5882,20 @@ 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) {
-               if (spec->gpio_led <= 8) {
+               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;
-                       codec->patch_ops.post_suspend =
-                                       stac92xx_post_suspend;
                }
                codec->patch_ops.pre_resume = stac92xx_pre_resume;
                codec->patch_ops.check_power_status =
@@ -6327,14 +6236,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;