]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - sound/pci/hda/patch_sigmatel.c
Merge branch 'for-davem' of ssh://master.kernel.org/pub/scm/linux/kernel/git/linville...
[linux-2.6.git] / sound / pci / hda / patch_sigmatel.c
index ea254235470d9d0afae397363e597d594056a0a4..bd7b123f64407e5398f0ddfe8a48ec10acfb1308 100644 (file)
@@ -32,6 +32,7 @@
 #include <sound/core.h>
 #include <sound/asoundef.h>
 #include <sound/jack.h>
+#include <sound/tlv.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_beep.h"
@@ -94,6 +95,7 @@ enum {
        STAC_92HD83XXX_PWR_REF,
        STAC_DELL_S14,
        STAC_92HD83XXX_HP,
+       STAC_HP_DV7_4000,
        STAC_92HD83XXX_MODELS
 };
 
@@ -104,6 +106,7 @@ enum {
        STAC_DELL_M4_2,
        STAC_DELL_M4_3,
        STAC_HP_M4,
+       STAC_HP_DV4,
        STAC_HP_DV5,
        STAC_HP_HDX,
        STAC_HP_DV4_1222NR,
@@ -201,6 +204,7 @@ struct sigmatel_spec {
        unsigned int spdif_mute: 1;
        unsigned int check_volume_offset:1;
        unsigned int auto_mic:1;
+       unsigned int linear_tone_beep:1;
 
        /* gpio lines */
        unsigned int eapd_mask;
@@ -260,8 +264,9 @@ struct sigmatel_spec {
 
        struct sigmatel_mic_route ext_mic;
        struct sigmatel_mic_route int_mic;
+       struct sigmatel_mic_route dock_mic;
 
-       const char **spdif_labels;
+       const char * const *spdif_labels;
 
        hda_nid_t dig_in_nid;
        hda_nid_t mono_nid;
@@ -379,6 +384,19 @@ static unsigned int stac92hd83xxx_pwr_mapping[4] = {
        0x03, 0x0c, 0x20, 0x40,
 };
 
+#define STAC92HD83XXX_NUM_DMICS         2
+static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
+       0x11, 0x20, 0
+};
+
+#define STAC92HD88XXX_NUM_DMICS        STAC92HD83XXX_NUM_DMICS
+#define stac92hd88xxx_dmic_nids        stac92hd83xxx_dmic_nids
+
+#define STAC92HD87B_NUM_DMICS   1
+static hda_nid_t stac92hd87b_dmic_nids[STAC92HD87B_NUM_DMICS + 1] = {
+       0x11, 0
+};
+
 #define STAC92HD83XXX_NUM_CAPS 2
 static unsigned long stac92hd83xxx_capvols[] = {
        HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
@@ -506,7 +524,7 @@ static unsigned long stac927x_capsws[] = {
        HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
 };
 
-static const char *stac927x_spdif_labels[5] = {
+static const char * const stac927x_spdif_labels[5] = {
        "Digital Playback", "ADAT", "Analog Mux 1",
        "Analog Mux 2", "Analog Mux 3"
 };
@@ -568,7 +586,12 @@ static hda_nid_t stac92hd83xxx_pin_nids[10] = {
        0x0f, 0x10, 0x11, 0x1f, 0x20,
 };
 
-static hda_nid_t stac92hd88xxx_pin_nids[10] = {
+static hda_nid_t stac92hd87xxx_pin_nids[6] = {
+       0x0a, 0x0b, 0x0c, 0x0d,
+       0x0f, 0x11,
+};
+
+static hda_nid_t stac92hd88xxx_pin_nids[8] = {
        0x0a, 0x0b, 0x0c, 0x0d,
        0x0f, 0x11, 0x1f, 0x20,
 };
@@ -983,7 +1006,7 @@ static struct hda_verb stac9205_core_init[] = {
        }
 
 static struct snd_kcontrol_new stac9200_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
+       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("Capture Volume", 0x0a, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
@@ -1011,7 +1034,7 @@ static struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
 };
 
 static struct snd_kcontrol_new stac925x_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
        { } /* end */
 };
@@ -1044,7 +1067,7 @@ static struct snd_kcontrol_new stac_smux_mixer = {
        .put = stac92xx_smux_enum_put,
 };
 
-static const char *slave_vols[] = {
+static const char * const slave_vols[] = {
        "Front Playback Volume",
        "Surround Playback Volume",
        "Center Playback Volume",
@@ -1055,7 +1078,7 @@ static const char *slave_vols[] = {
        NULL
 };
 
-static const char *slave_sws[] = {
+static const char * const slave_sws[] = {
        "Front Playback Switch",
        "Surround Playback Switch",
        "Center Playback Switch",
@@ -1102,9 +1125,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                struct hda_input_mux *smux = &spec->private_smux;
                /* check for mute support on SPDIF out */
                if (wcaps & AC_WCAP_OUT_AMP) {
-                       smux->items[smux->num_items].label = "Off";
-                       smux->items[smux->num_items].index = 0;
-                       smux->num_items++;
+                       snd_hda_add_imux_item(smux, "Off", 0, NULL);
                        spec->spdif_mute = 1;
                }
                stac_smux_mixer.count = spec->num_smuxes;
@@ -1137,6 +1158,8 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                                        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)
@@ -1177,14 +1200,11 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
        }
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               nid = cfg->input_pins[i];
-               if (nid) {
-                       err = stac92xx_add_jack(codec, nid,
-                                               SND_JACK_MICROPHONE);
-                       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;
        }
 
        return 0;       
@@ -1339,7 +1359,7 @@ static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
        [STAC_9200_PANASONIC] = ref9200_pin_configs,
 };
 
-static const char *stac9200_models[STAC_9200_MODELS] = {
+static const char * const stac9200_models[STAC_9200_MODELS] = {
        [STAC_AUTO] = "auto",
        [STAC_REF] = "ref",
        [STAC_9200_OQO] = "oqo",
@@ -1485,7 +1505,7 @@ static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
        [STAC_M6] = stac925xM6_pin_configs,
 };
 
-static const char *stac925x_models[STAC_925x_MODELS] = {
+static const char * const stac925x_models[STAC_925x_MODELS] = {
        [STAC_925x_AUTO] = "auto",
        [STAC_REF] = "ref",
        [STAC_M1] = "m1",
@@ -1544,11 +1564,9 @@ static unsigned int alienware_m17x_pin_configs[13] = {
        0x904601b0,
 };
 
-static unsigned int intel_dg45id_pin_configs[14] = {
+static unsigned int intel_dg45id_pin_configs[13] = {
        0x02214230, 0x02A19240, 0x01013214, 0x01014210,
-       0x01A19250, 0x01011212, 0x01016211, 0x40f000f0,
-       0x40f000f0, 0x40f000f0, 0x40f000f0, 0x014510A0,
-       0x074510B0, 0x40f000f0
+       0x01A19250, 0x01011212, 0x01016211
 };
 
 static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
@@ -1561,7 +1579,7 @@ static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
        [STAC_92HD73XX_INTEL]   = intel_dg45id_pin_configs,
 };
 
-static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
+static const char * const stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
        [STAC_92HD73XX_AUTO] = "auto",
        [STAC_92HD73XX_NO_JD] = "no-jd",
        [STAC_92HD73XX_REF] = "ref",
@@ -1607,12 +1625,18 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = {
                                "Dell Studio 1555", STAC_DELL_M6_DMIC),
        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),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413,
+                               "Dell Studio 1558", STAC_DELL_M6_BOTH),
        {} /* terminator */
 };
 
 static struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1,
                      "Alienware M17x", STAC_ALIENWARE_M17X),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a,
+                     "Alienware M17x", STAC_ALIENWARE_M17X),
        {} /* terminator */
 };
 
@@ -1628,18 +1652,26 @@ static unsigned int dell_s14_pin_configs[10] = {
        0x40f000f0, 0x40f000f0,
 };
 
+static unsigned int hp_dv7_4000_pin_configs[10] = {
+       0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110,
+       0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140,
+       0x40f000f0, 0x40f000f0,
+};
+
 static 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_HP_DV7_4000] = hp_dv7_4000_pin_configs,
 };
 
-static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
+static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
        [STAC_92HD83XXX_AUTO] = "auto",
        [STAC_92HD83XXX_REF] = "ref",
        [STAC_92HD83XXX_PWR_REF] = "mic-ref",
        [STAC_DELL_S14] = "dell-s14",
        [STAC_92HD83XXX_HP] = "hp",
+       [STAC_HP_DV7_4000] = "hp-dv7-4000",
 };
 
 static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
@@ -1689,18 +1721,20 @@ static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
        [STAC_DELL_M4_2]        = dell_m4_2_pin_configs,
        [STAC_DELL_M4_3]        = dell_m4_3_pin_configs,
        [STAC_HP_M4]            = NULL,
+       [STAC_HP_DV4]           = NULL,
        [STAC_HP_DV5]           = NULL,
        [STAC_HP_HDX]           = NULL,
        [STAC_HP_DV4_1222NR]    = NULL,
 };
 
-static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
+static const char * const stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
        [STAC_92HD71BXX_AUTO] = "auto",
        [STAC_92HD71BXX_REF] = "ref",
        [STAC_DELL_M4_1] = "dell-m4-1",
        [STAC_DELL_M4_2] = "dell-m4-2",
        [STAC_DELL_M4_3] = "dell-m4-3",
        [STAC_HP_M4] = "hp-m4",
+       [STAC_HP_DV4] = "hp-dv4",
        [STAC_HP_DV5] = "hp-dv5",
        [STAC_HP_HDX] = "hp-hdx",
        [STAC_HP_DV4_1222NR] = "hp-dv4-1222nr",
@@ -1719,7 +1753,7 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080,
                      "HP", STAC_HP_DV5),
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0,
-                     "HP dv4-7", STAC_HP_DV5),
+                     "HP dv4-7", STAC_HP_DV4),
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3600,
                      "HP dv4-7", STAC_HP_DV5),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3610,
@@ -1730,6 +1764,10 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
                      "HP HDX", STAC_HP_HDX),  /* HDX16 */
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3620,
                      "HP dv6", STAC_HP_DV5),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3061,
+                     "HP dv6", STAC_HP_DV5), /* HP dv6-1110ax */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x363e,
+                     "HP DV6", STAC_HP_DV5),
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010,
                      "HP", STAC_HP_DV5),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
@@ -1882,7 +1920,7 @@ static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
        [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,       
 };
 
-static const char *stac922x_models[STAC_922X_MODELS] = {
+static const char * const stac922x_models[STAC_922X_MODELS] = {
        [STAC_922X_AUTO] = "auto",
        [STAC_D945_REF] = "ref",
        [STAC_D945GTP5] = "5stack",
@@ -2044,7 +2082,7 @@ static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
        [STAC_927X_VOLKNOB] = NULL,
 };
 
-static const char *stac927x_models[STAC_927X_MODELS] = {
+static const char * const stac927x_models[STAC_927X_MODELS] = {
        [STAC_927X_AUTO]        = "auto",
        [STAC_D965_REF_NO_JD]   = "ref-no-jd",
        [STAC_D965_REF]         = "ref",
@@ -2071,12 +2109,12 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = {
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2000,
                           "Intel D965", STAC_D965_3ST),
        /* Dell 3 stack systems */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01ed, "Dell     ", STAC_DELL_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f4, "Dell     ", STAC_DELL_3ST),
        /* Dell 3 stack systems with verb table in BIOS */
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f7, "Dell XPS M1730", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0227, "Dell Vostro 1400  ", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022e, "Dell     ", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022f, "Dell Inspiron 1525", STAC_DELL_BIOS),
@@ -2147,7 +2185,7 @@ static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
        [STAC_9205_EAPD] = NULL,
 };
 
-static const char *stac9205_models[STAC_9205_MODELS] = {
+static const char * const stac9205_models[STAC_9205_MODELS] = {
        [STAC_9205_AUTO] = "auto",
        [STAC_9205_REF] = "ref",
        [STAC_9205_DELL_M42] = "dell-m42",
@@ -2760,7 +2798,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
        struct sigmatel_spec *spec = codec->spec;
        char name[22];
 
-       if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) {
+       if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
                if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
                        && nid == spec->line_switch)
                        control = STAC_CTL_WIDGET_IO_SWITCH;
@@ -2772,7 +2810,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
        }
 
        if (control) {
-               strcpy(name, auto_pin_cfg_labels[idx]);
+               strcpy(name, hda_get_input_pin_label(codec, nid, 1));
                return stac92xx_add_control(codec->spec, control,
                                        strcat(name, " Jack Mode"), nid);
        }
@@ -2804,41 +2842,49 @@ static hda_nid_t check_line_out_switch(struct hda_codec *codec)
        struct auto_pin_cfg *cfg = &spec->autocfg;
        hda_nid_t nid;
        unsigned int pincap;
+       int i;
 
        if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
                return 0;
-       nid = cfg->input_pins[AUTO_PIN_LINE];
-       pincap = snd_hda_query_pin_caps(codec, nid);
-       if (pincap & AC_PINCAP_OUT)
-               return nid;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (cfg->inputs[i].type == AUTO_PIN_LINE_IN) {
+                       nid = cfg->inputs[i].pin;
+                       pincap = snd_hda_query_pin_caps(codec, nid);
+                       if (pincap & AC_PINCAP_OUT)
+                               return nid;
+               }
+       }
        return 0;
 }
 
+static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid);
+
 /* check whether the mic-input can be used as line-out */
-static hda_nid_t check_mic_out_switch(struct hda_codec *codec)
+static hda_nid_t check_mic_out_switch(struct hda_codec *codec, hda_nid_t *dac)
 {
        struct sigmatel_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
        unsigned int def_conf, pincap;
-       unsigned int mic_pin;
+       int i;
 
+       *dac = 0;
        if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
                return 0;
-       mic_pin = AUTO_PIN_MIC;
-       for (;;) {
-               hda_nid_t nid = cfg->input_pins[mic_pin];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               if (cfg->inputs[i].type != AUTO_PIN_MIC)
+                       continue;
                def_conf = snd_hda_codec_get_pincfg(codec, nid);
                /* some laptops have an internal analog microphone
                 * which can't be used as a output */
-               if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
+               if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
                        pincap = snd_hda_query_pin_caps(codec, nid);
-                       if (pincap & AC_PINCAP_OUT)
-                               return nid;
+                       if (pincap & AC_PINCAP_OUT) {
+                               *dac = get_unassigned_dac(codec, nid);
+                               if (*dac)
+                                       return nid;
+                       }
                }
-               if (mic_pin == AUTO_PIN_MIC)
-                       mic_pin = AUTO_PIN_FRONT_MIC;
-               else
-                       break;
        }
        return 0;
 }
@@ -2985,17 +3031,14 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
                }
        }
        /* add mic as output */
-       nid = check_mic_out_switch(codec);
-       if (nid) {
-               dac = get_unassigned_dac(codec, nid);
-               if (dac) {
-                       snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
-                                   nid, cfg->line_outs);
-                       cfg->line_out_pins[cfg->line_outs] = nid;
-                       cfg->line_outs++;
-                       spec->mic_switch = nid;
-                       add_spec_dacs(spec, dac);
-               }
+       nid = check_mic_out_switch(codec, &dac);
+       if (nid && dac) {
+               snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
+                           nid, cfg->line_outs);
+               cfg->line_out_pins[cfg->line_outs] = nid;
+               cfg->line_outs++;
+               spec->mic_switch = nid;
+               add_spec_dacs(spec, dac);
        }
 
        snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
@@ -3085,7 +3128,7 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
                                 int type)
 {
        struct sigmatel_spec *spec = codec->spec;
-       static const char *chname[4] = {
+       static const char * const chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
        hda_nid_t nid;
@@ -3185,13 +3228,13 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                        return err;
        }
 
-       for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) {
-               nid = cfg->input_pins[idx];
-               if (nid) {
-                       err = stac92xx_add_jack_mode_control(codec, nid, idx);
-                       if (err < 0)
-                               return err;
-               }
+       for (idx = 0; idx < cfg->num_inputs; idx++) {
+               if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN)
+                       break;
+               nid = cfg->inputs[idx].pin;
+               err = stac92xx_add_jack_mode_control(codec, nid, idx);
+               if (err < 0)
+                       return err;
        }
 
        return 0;
@@ -3218,7 +3261,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
 }
 
 /* labels for mono mux outputs */
-static const char *stac92xx_mono_labels[4] = {
+static const char * const stac92xx_mono_labels[4] = {
        "DAC0", "DAC1", "Mixer", "DAC2"
 };
 
@@ -3237,12 +3280,9 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
        if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
                return -EINVAL;
 
-       for (i = 0; i < num_cons; i++) {
-               mono_mux->items[mono_mux->num_items].label =
-                                       stac92xx_mono_labels[i];
-               mono_mux->items[mono_mux->num_items].index = i;
-               mono_mux->num_items++;
-       }
+       for (i = 0; i < num_cons; i++)
+               snd_hda_add_imux_item(mono_mux, stac92xx_mono_labels[i], i,
+                                     NULL);
 
        return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
                                "Mono Mux", spec->mono_nid);
@@ -3345,7 +3385,7 @@ static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
        return 0;
 };
 
-static const char *stac92xx_spdif_labels[3] = {
+static const char * const stac92xx_spdif_labels[3] = {
        "Digital Playback", "Analog Mux 1", "Analog Mux 2",
 };
 
@@ -3353,7 +3393,7 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
        struct hda_input_mux *spdif_mux = &spec->private_smux;
-       const char **labels = spec->spdif_labels;
+       const char * const *labels = spec->spdif_labels;
        int i, num_cons;
        hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
 
@@ -3367,17 +3407,14 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
        if (!labels)
                labels = stac92xx_spdif_labels;
 
-       for (i = 0; i < num_cons; i++) {
-               spdif_mux->items[spdif_mux->num_items].label = labels[i];
-               spdif_mux->items[spdif_mux->num_items].index = i;
-               spdif_mux->num_items++;
-       }
+       for (i = 0; i < num_cons; i++)
+               snd_hda_add_imux_item(spdif_mux, labels[i], i, NULL);
 
        return 0;
 }
 
 /* labels for dmic mux inputs */
-static const char *stac92xx_dmic_labels[5] = {
+static const char * const stac92xx_dmic_labels[5] = {
        "Analog Inputs", "Digital Mic 1", "Digital Mic 2",
        "Digital Mic 3", "Digital Mic 4"
 };
@@ -3398,7 +3435,7 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
 /* create a volume assigned to the given pin (only if supported) */
 /* return 1 if the volume control is created */
 static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid,
-                                  const char *label, int direction)
+                                  const char *label, int idx, int direction)
 {
        unsigned int caps, nums;
        char name[32];
@@ -3415,8 +3452,8 @@ static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid,
        if (!nums)
                return 0;
        snprintf(name, sizeof(name), "%s Capture Volume", label);
-       err = stac92xx_add_control(codec->spec, STAC_CTL_WIDGET_VOL, name,
-                                   HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction));
+       err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, name,
+                                      HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction));
        if (err < 0)
                return err;
        return 1;
@@ -3429,27 +3466,14 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
        struct sigmatel_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux;
        struct hda_input_mux *dimux = &spec->private_dimux;
-       int err, i, active_mics;
+       int err, i;
        unsigned int def_conf;
 
-       dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
-       dimux->items[dimux->num_items].index = 0;
-       dimux->num_items++;
-
-       active_mics = 0;
-       for (i = 0; i < spec->num_dmics; i++) {
-               /* check the validity: sometimes it's a dead vendor-spec node */
-               if (get_wcaps_type(get_wcaps(codec, spec->dmic_nids[i]))
-                   != AC_WID_PIN)
-                       continue;
-               def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]);
-               if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
-                       active_mics++;
-       }
+       snd_hda_add_imux_item(dimux, stac92xx_dmic_labels[0], 0, NULL);
 
        for (i = 0; i < spec->num_dmics; i++) {
                hda_nid_t nid;
-               int index;
+               int index, type_idx;
                const char *label;
 
                nid = spec->dmic_nids[i];
@@ -3463,49 +3487,48 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
                if (index < 0)
                        continue;
 
-               if (active_mics == 1)
-                       label = "Digital Mic";
-               else
-                       label = stac92xx_dmic_labels[dimux->num_items];
+               label = hda_get_input_pin_label(codec, nid, 1);
+               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);
 
-               err = create_elem_capture_vol(codec, nid, label, HDA_INPUT);
+               err = create_elem_capture_vol(codec, nid, label, type_idx,
+                                             HDA_INPUT);
                if (err < 0)
                        return err;
                if (!err) {
                        err = create_elem_capture_vol(codec, nid, label,
-                                                     HDA_OUTPUT);
+                                                     type_idx, HDA_OUTPUT);
                        if (err < 0)
                                return err;
                }
-
-               dimux->items[dimux->num_items].label = label;
-               dimux->items[dimux->num_items].index = index;
-               dimux->num_items++;
-               if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) {
-                       imux->items[imux->num_items].label = label;
-                       imux->items[imux->num_items].index = index;
-                       imux->num_items++;
-               }
        }
 
        return 0;
 }
 
 static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
-                        hda_nid_t *fixed, hda_nid_t *ext)
+                        hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock)
 {
        unsigned int cfg;
 
        if (!nid)
                return 0;
        cfg = snd_hda_codec_get_pincfg(codec, nid);
-       switch (get_defcfg_connect(cfg)) {
-       case AC_JACK_PORT_FIXED:
+       switch (snd_hda_get_input_pin_attr(cfg)) {
+       case INPUT_PIN_ATTR_INT:
                if (*fixed)
                        return 1; /* already occupied */
                *fixed = nid;
                break;
-       case AC_JACK_PORT_COMPLEX:
+       case INPUT_PIN_ATTR_UNUSED:
+               break;
+       case INPUT_PIN_ATTR_DOCK:
+               if (*dock)
+                       return 1; /* already occupied */
+               *dock = nid;
+               break;
+       default:
                if (*ext)
                        return 1; /* already occupied */
                *ext = nid;
@@ -3523,10 +3546,13 @@ static int set_mic_route(struct hda_codec *codec,
        int i;
 
        mic->pin = pin;
-       for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
-               if (pin == cfg->input_pins[i])
+       if (pin == 0)
+               return 0;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (pin == cfg->inputs[i].pin)
                        break;
-       if (i <= AUTO_PIN_FRONT_MIC) {
+       }
+       if (i < cfg->num_inputs && cfg->inputs[i].type == AUTO_PIN_MIC) {
                /* analog pin */
                i = get_connection_index(codec, spec->mux_nids[0], pin);
                if (i < 0)
@@ -3557,26 +3583,29 @@ static int stac_check_auto_mic(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
-       hda_nid_t fixed, ext;
+       hda_nid_t fixed, ext, dock;
        int i;
 
-       for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) {
-               if (cfg->input_pins[i])
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
                        return 0; /* must be exclusively mics */
        }
-       fixed = ext = 0;
-       for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
-               if (check_mic_pin(codec, cfg->input_pins[i], &fixed, &ext))
+       fixed = ext = dock = 0;
+       for (i = 0; i < cfg->num_inputs; i++)
+               if (check_mic_pin(codec, cfg->inputs[i].pin,
+                   &fixed, &ext, &dock))
                        return 0;
        for (i = 0; i < spec->num_dmics; i++)
-               if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext))
+               if (check_mic_pin(codec, spec->dmic_nids[i],
+                   &fixed, &ext, &dock))
                        return 0;
-       if (!fixed || !ext)
-               return 0;
+       if (!fixed || (!ext && !dock))
+               return 0; /* no input to switch */
        if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
                return 0; /* no unsol support */
        if (set_mic_route(codec, &spec->ext_mic, ext) ||
-           set_mic_route(codec, &spec->int_mic, fixed))
+           set_mic_route(codec, &spec->int_mic, fixed) ||
+           set_mic_route(codec, &spec->dock_mic, dock))
                return 0; /* something is wrong */
        return 1;
 }
@@ -3587,13 +3616,12 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
        struct sigmatel_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux;
        int i, j;
+       const char *label;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = cfg->input_pins[i];
-               int index, err;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               int index, err, type_idx;
 
-               if (!nid)
-                       continue;
                index = -1;
                for (j = 0; j < spec->num_muxes; j++) {
                        index = get_connection_index(codec, spec->mux_nids[j],
@@ -3604,15 +3632,14 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
                if (index < 0)
                        continue;
 
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               snd_hda_add_imux_item(imux, label, index, &type_idx);
+
                err = create_elem_capture_vol(codec, nid,
-                                             auto_pin_cfg_labels[i],
+                                             label, type_idx,
                                              HDA_INPUT);
                if (err < 0)
                        return err;
-
-               imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
-               imux->items[imux->num_items].index = index;
-               imux->num_items++;
        }
        spec->num_analog_muxes = imux->num_items;
 
@@ -3795,7 +3822,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
                        return err;
                if (codec->beep) {
                        /* IDT/STAC codecs have linear beep tone parameter */
-                       codec->beep->linear_tone = 1;
+                       codec->beep->linear_tone = spec->linear_tone_beep;
                        /* if no beep switch is available, make its own one */
                        caps = query_amp_caps(codec, nid, HDA_OUTPUT);
                        if (!(caps & AC_AMPCAP_MUTE)) {
@@ -4286,38 +4313,38 @@ static int stac92xx_init(struct hda_codec *codec)
                                          AC_VERB_SET_CONNECT_SEL, 0);
                if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT))
                        stac_issue_unsol_event(codec, spec->ext_mic.pin);
-       }
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = cfg->input_pins[i];
-               if (nid) {
-                       unsigned int pinctl, conf;
-                       if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
-                               /* for mic pins, force to initialize */
-                               pinctl = stac92xx_get_default_vref(codec, nid);
+               if (enable_pin_detect(codec, spec->dock_mic.pin,
+                   STAC_MIC_EVENT))
+                       stac_issue_unsol_event(codec, spec->dock_mic.pin);
+       }
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               int type = cfg->inputs[i].type;
+               unsigned int pinctl, conf;
+               if (type == AUTO_PIN_MIC) {
+                       /* for mic pins, force to initialize */
+                       pinctl = stac92xx_get_default_vref(codec, nid);
+                       pinctl |= AC_PINCTL_IN_EN;
+                       stac92xx_auto_set_pinctl(codec, nid, pinctl);
+               } else {
+                       pinctl = snd_hda_codec_read(codec, nid, 0,
+                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+                       /* if PINCTL already set then skip */
+                       /* Also, if both INPUT and OUTPUT are set,
+                        * it must be a BIOS bug; need to override, too
+                        */
+                       if (!(pinctl & AC_PINCTL_IN_EN) ||
+                           (pinctl & AC_PINCTL_OUT_EN)) {
+                               pinctl &= ~AC_PINCTL_OUT_EN;
                                pinctl |= AC_PINCTL_IN_EN;
                                stac92xx_auto_set_pinctl(codec, nid, pinctl);
-                       } else {
-                               pinctl = snd_hda_codec_read(codec, nid, 0,
-                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-                               /* if PINCTL already set then skip */
-                               /* Also, if both INPUT and OUTPUT are set,
-                                * it must be a BIOS bug; need to override, too
-                                */
-                               if (!(pinctl & AC_PINCTL_IN_EN) ||
-                                   (pinctl & AC_PINCTL_OUT_EN)) {
-                                       pinctl &= ~AC_PINCTL_OUT_EN;
-                                       pinctl |= AC_PINCTL_IN_EN;
-                                       stac92xx_auto_set_pinctl(codec, nid,
-                                                                pinctl);
-                               }
-                       }
-                       conf = snd_hda_codec_get_pincfg(codec, nid);
-                       if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
-                               if (enable_pin_detect(codec, nid,
-                                                     STAC_INSERT_EVENT))
-                                       stac_issue_unsol_event(codec, nid);
                        }
                }
+               conf = snd_hda_codec_get_pincfg(codec, nid);
+               if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
+                       if (enable_pin_detect(codec, nid, STAC_INSERT_EVENT))
+                               stac_issue_unsol_event(codec, nid);
+               }
        }
        for (i = 0; i < spec->num_dmics; i++)
                stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
@@ -4364,11 +4391,9 @@ static int stac92xx_init(struct hda_codec *codec)
                        stac_issue_unsol_event(codec, nid);
        }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
        /* sync mute LED */
-       if (spec->gpio_led && codec->patch_ops.check_power_status)
-               codec->patch_ops.check_power_status(codec, 0x01);
-#endif 
+       if (spec->gpio_led)
+               hda_call_check_power_status(codec, 0x01);
        if (spec->dac_list)
                stac92xx_power_down(codec);
        return 0;
@@ -4669,6 +4694,36 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
        }
 }
 
+/* get the pin connection (fixed, none, etc) */
+static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       unsigned int cfg;
+
+       cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
+       return get_defcfg_connect(cfg);
+}
+
+static int stac92xx_connected_ports(struct hda_codec *codec,
+                                        hda_nid_t *nids, int num_nids)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int idx, num;
+       unsigned int def_conf;
+
+       for (num = 0; num < num_nids; num++) {
+               for (idx = 0; idx < spec->num_pins; idx++)
+                       if (spec->pin_nids[idx] == nids[num])
+                               break;
+               if (idx >= spec->num_pins)
+                       break;
+               def_conf = stac_get_defcfg_connect(codec, idx);
+               if (def_conf == AC_JACK_PORT_NONE)
+                       break;
+       }
+       return num;
+}
+
 static void stac92xx_mic_detect(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -4676,6 +4731,8 @@ static void stac92xx_mic_detect(struct hda_codec *codec)
 
        if (get_pin_presence(codec, spec->ext_mic.pin))
                mic = &spec->ext_mic;
+       else if (get_pin_presence(codec, spec->dock_mic.pin))
+               mic = &spec->dock_mic;
        else
                mic = &spec->int_mic;
        if (mic->dmux_idx >= 0)
@@ -4762,6 +4819,9 @@ static void set_hp_led_gpio(struct hda_codec *codec)
        struct sigmatel_spec *spec = codec->spec;
        unsigned int gpio;
 
+       if (spec->gpio_led)
+               return;
+
        gpio = snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP);
        gpio &= AC_GPIO_IO_COUNT;
        if (gpio > 3)
@@ -4790,7 +4850,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)
+static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity)
 {
        struct sigmatel_spec *spec = codec->spec;
        const struct dmi_device *dev = NULL;
@@ -4817,7 +4877,7 @@ static int find_mute_led_gpio(struct hda_codec *codec)
                 */
                if (!hp_blike_system(codec->subsystem_id)) {
                        set_hp_led_gpio(codec);
-                       spec->gpio_led_polarity = 1;
+                       spec->gpio_led_polarity = default_polarity;
                        return 1;
                }
        }
@@ -4915,11 +4975,9 @@ static int stac92xx_resume(struct hda_codec *codec)
                        stac_issue_unsol_event(codec,
                                               spec->autocfg.line_out_pins[0]);
        }
-#ifdef CONFIG_SND_HDA_POWER_SAVE
        /* sync mute LED */
-       if (spec->gpio_led && codec->patch_ops.check_power_status)
-               codec->patch_ops.check_power_status(codec, 0x01);
-#endif 
+       if (spec->gpio_led)
+               hda_call_check_power_status(codec, 0x01);
        return 0;
 }
 
@@ -4995,6 +5053,7 @@ static int patch_stac9200(struct hda_codec *codec)
 
        codec->no_trigger_sense = 1;
        codec->spec = spec;
+       spec->linear_tone_beep = 1;
        spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
        spec->pin_nids = stac9200_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
@@ -5058,6 +5117,7 @@ static int patch_stac925x(struct hda_codec *codec)
 
        codec->no_trigger_sense = 1;
        codec->spec = spec;
+       spec->linear_tone_beep = 1;
        spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
        spec->pin_nids = stac925x_pin_nids;
 
@@ -5143,6 +5203,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
 
        codec->no_trigger_sense = 1;
        codec->spec = spec;
+       spec->linear_tone_beep = 0;
        codec->slave_dig_outs = stac92hd73xx_slave_dig_outs;
        spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids);
        spec->pin_nids = stac92hd73xx_pin_nids;
@@ -5277,6 +5338,46 @@ again:
        return 0;
 }
 
+static int hp_bnb2011_with_dock(struct hda_codec *codec)
+{
+       if (codec->vendor_id != 0x111d7605 &&
+           codec->vendor_id != 0x111d76d1)
+               return 0;
+
+       switch (codec->subsystem_id) {
+       case 0x103c1618:
+       case 0x103c1619:
+       case 0x103c161a:
+       case 0x103c161b:
+       case 0x103c161c:
+       case 0x103c161d:
+       case 0x103c161e:
+       case 0x103c161f:
+
+       case 0x103c162a:
+       case 0x103c162b:
+
+       case 0x103c1630:
+       case 0x103c1631:
+
+       case 0x103c1633:
+       case 0x103c1634:
+       case 0x103c1635:
+
+       case 0x103c3587:
+       case 0x103c3588:
+       case 0x103c3589:
+       case 0x103c358a:
+
+       case 0x103c3667:
+       case 0x103c3668:
+       case 0x103c3669:
+
+               return 1;
+       }
+       return 0;
+}
+
 static int patch_stac92hd83xxx(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
@@ -5288,10 +5389,21 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        if (spec == NULL)
                return -ENOMEM;
 
+       if (hp_bnb2011_with_dock(codec)) {
+               snd_hda_codec_set_pincfg(codec, 0xa, 0x2101201f);
+               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;
+       spec->linear_tone_beep = 0;
        codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
        spec->digbeep_nid = 0x21;
+       spec->dmic_nids = stac92hd83xxx_dmic_nids;
+       spec->dmux_nids = stac92hd83xxx_mux_nids;
        spec->mux_nids = stac92hd83xxx_mux_nids;
        spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids);
        spec->adc_nids = stac92hd83xxx_adc_nids;
@@ -5321,32 +5433,48 @@ again:
                                stac92hd83xxx_brd_tbl[spec->board_config]);
 
        switch (codec->vendor_id) {
+       case 0x111d76d1:
+       case 0x111d76d9:
+       case 0x111d76e5:
+               spec->dmic_nids = stac92hd87b_dmic_nids;
+               spec->num_dmics = stac92xx_connected_ports(codec,
+                               stac92hd87b_dmic_nids,
+                               STAC92HD87B_NUM_DMICS);
+               spec->num_pins = ARRAY_SIZE(stac92hd87xxx_pin_nids);
+               spec->pin_nids = stac92hd87xxx_pin_nids;
+               spec->mono_nid = 0;
+               spec->num_pwrs = 0;
+               break;
        case 0x111d7666:
        case 0x111d7667:
        case 0x111d7668:
        case 0x111d7669:
+       case 0x111d76e3:
+               spec->num_dmics = stac92xx_connected_ports(codec,
+                               stac92hd88xxx_dmic_nids,
+                               STAC92HD88XXX_NUM_DMICS);
                spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
                spec->pin_nids = stac92hd88xxx_pin_nids;
                spec->mono_nid = 0;
-               spec->digbeep_nid = 0;
                spec->num_pwrs = 0;
                break;
        case 0x111d7604:
        case 0x111d76d4:
        case 0x111d7605:
        case 0x111d76d5:
+       case 0x111d76e7:
                if (spec->board_config == STAC_92HD83XXX_PWR_REF)
                        break;
                spec->num_pwrs = 0;
+               spec->num_dmics = stac92xx_connected_ports(codec,
+                               stac92hd83xxx_dmic_nids,
+                               STAC92HD83XXX_NUM_DMICS);
                break;
        }
 
        codec->patch_ops = stac92xx_patch_ops;
 
-       if (spec->board_config == STAC_92HD83XXX_HP)
-               spec->gpio_led = 0x01;
-
-       if (find_mute_led_gpio(codec))
+       if (find_mute_led_gpio(codec, 0))
                snd_printd("mute LED gpio %d polarity %d\n",
                                spec->gpio_led,
                                spec->gpio_led_polarity);
@@ -5399,36 +5527,6 @@ again:
        return 0;
 }
 
-/* get the pin connection (fixed, none, etc) */
-static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       unsigned int cfg;
-
-       cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
-       return get_defcfg_connect(cfg);
-}
-
-static int stac92hd71bxx_connected_ports(struct hda_codec *codec,
-                                        hda_nid_t *nids, int num_nids)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       int idx, num;
-       unsigned int def_conf;
-
-       for (num = 0; num < num_nids; num++) {
-               for (idx = 0; idx < spec->num_pins; idx++)
-                       if (spec->pin_nids[idx] == nids[num])
-                               break;
-               if (idx >= spec->num_pins)
-                       break;
-               def_conf = stac_get_defcfg_connect(codec, idx);
-               if (def_conf == AC_JACK_PORT_NONE)
-                       break;
-       }
-       return num;
-}
-
 static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec,
                                          hda_nid_t dig0pin)
 {
@@ -5515,6 +5613,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
 
        codec->no_trigger_sense = 1;
        codec->spec = spec;
+       spec->linear_tone_beep = 0;
        codec->patch_ops = stac92xx_patch_ops;
        spec->num_pins = STAC92HD71BXX_NUM_PINS;
        switch (codec->vendor_id) {
@@ -5566,7 +5665,7 @@ again:
        case 0x111d76b5:
                spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
-               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+               spec->num_dmics = stac92xx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
                                        STAC92HD71BXX_NUM_DMICS);
                break;
@@ -5598,7 +5697,7 @@ again:
                snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
                snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
                stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0;
-               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+               spec->num_dmics = stac92xx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
                                        STAC92HD71BXX_NUM_DMICS - 1);
                break;
@@ -5612,7 +5711,7 @@ again:
        default:
                spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
-               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+               spec->num_dmics = stac92xx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
                                        STAC92HD71BXX_NUM_DMICS);
                break;
@@ -5673,6 +5772,8 @@ again:
                 */
                spec->num_smuxes = 1;
                spec->num_dmuxes = 1;
+               /* fallthrough */
+       case STAC_HP_DV4:
                spec->gpio_led = 0x01;
                /* fallthrough */
        case STAC_HP_DV5:
@@ -5688,7 +5789,6 @@ again:
                spec->num_dmics = 1;
                spec->num_dmuxes = 1;
                spec->num_smuxes = 1;
-               /* orange/white mute led on GPIO3, orange=0, white=1 */
                spec->gpio_led = 0x08;
                break;
        }
@@ -5711,7 +5811,7 @@ again:
                }
        }
 
-       if (find_mute_led_gpio(codec))
+       if (find_mute_led_gpio(codec, 1))
                snd_printd("mute LED gpio %d polarity %d\n",
                                spec->gpio_led,
                                spec->gpio_led_polarity);
@@ -5746,7 +5846,8 @@ again:
        }
 
        /* enable bass on HP dv7 */
-       if (spec->board_config == STAC_HP_DV5) {
+       if (spec->board_config == STAC_HP_DV4 ||
+           spec->board_config == STAC_HP_DV5) {
                unsigned int cap;
                cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP);
                cap &= AC_GPIO_IO_COUNT;
@@ -5770,6 +5871,7 @@ static int patch_stac922x(struct hda_codec *codec)
 
        codec->no_trigger_sense = 1;
        codec->spec = spec;
+       spec->linear_tone_beep = 1;
        spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
        spec->pin_nids = stac922x_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
@@ -5874,6 +5976,7 @@ static int patch_stac927x(struct hda_codec *codec)
 
        codec->no_trigger_sense = 1;
        codec->spec = spec;
+       spec->linear_tone_beep = 1;
        codec->slave_dig_outs = stac927x_slave_dig_outs;
        spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
        spec->pin_nids = stac927x_pin_nids;
@@ -6009,6 +6112,7 @@ static int patch_stac9205(struct hda_codec *codec)
 
        codec->no_trigger_sense = 1;
        codec->spec = spec;
+       spec->linear_tone_beep = 1;
        spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
        spec->pin_nids = stac9205_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
@@ -6140,7 +6244,7 @@ static unsigned int stac9872_vaio_pin_configs[9] = {
        0x90a7013e
 };
 
-static const char *stac9872_models[STAC_9872_MODELS] = {
+static const char * const stac9872_models[STAC_9872_MODELS] = {
        [STAC_9872_AUTO] = "auto",
        [STAC_9872_VAIO] = "vaio",
 };
@@ -6165,6 +6269,7 @@ static int patch_stac9872(struct hda_codec *codec)
                return -ENOMEM;
        codec->no_trigger_sense = 1;
        codec->spec = spec;
+       spec->linear_tone_beep = 1;
        spec->num_pins = ARRAY_SIZE(stac9872_pin_nids);
        spec->pin_nids = stac9872_pin_nids;
 
@@ -6255,6 +6360,8 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x111d76d4, .name = "92HD83C1C5", .patch = patch_stac92hd83xxx},
        { .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
        { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76d1, .name = "92HD87B1/3", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76d9, .name = "92HD87B2/4", .patch = patch_stac92hd83xxx},
        { .id = 0x111d7666, .name = "92HD88B3", .patch = patch_stac92hd83xxx},
        { .id = 0x111d7667, .name = "92HD88B1", .patch = patch_stac92hd83xxx},
        { .id = 0x111d7668, .name = "92HD88B2", .patch = patch_stac92hd83xxx},
@@ -6271,6 +6378,25 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx },
        { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
        { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx },
+       { .id = 0x111d76c0, .name = "92HD89C3", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76c1, .name = "92HD89C2", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76c2, .name = "92HD89C1", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76c3, .name = "92HD89B3", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76c4, .name = "92HD89B2", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76c5, .name = "92HD89B1", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76c6, .name = "92HD89E3", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76c7, .name = "92HD89E2", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76c8, .name = "92HD89E1", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76c9, .name = "92HD89D3", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76ca, .name = "92HD89D2", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76cb, .name = "92HD89D1", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx },
+       { .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},
        {} /* terminator */
 };