Merge branch 'fix/hda' into topic/hda
Takashi Iwai [Mon, 2 May 2011 08:41:40 +0000 (10:41 +0200)]
1  2 
sound/pci/hda/hda_codec.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c

@@@ -307,12 -307,6 +307,12 @@@ int snd_hda_get_sub_nodes(struct hda_co
  }
  EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
  
 +static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 +                              hda_nid_t *conn_list, int max_conns);
 +static bool add_conn_list(struct snd_array *array, hda_nid_t nid);
 +static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
 +                        hda_nid_t *src, int len);
 +
  /**
   * snd_hda_get_connections - get connection list
   * @codec: the HDA codec
   * Returns the number of connections, or a negative error code.
   */
  int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 -                          hda_nid_t *conn_list, int max_conns)
 +                           hda_nid_t *conn_list, int max_conns)
 +{
 +      struct snd_array *array = &codec->conn_lists;
 +      int i, len, old_used;
 +      hda_nid_t list[HDA_MAX_CONNECTIONS];
 +
 +      /* look up the cached results */
 +      for (i = 0; i < array->used; ) {
 +              hda_nid_t *p = snd_array_elem(array, i);
 +              len = p[1];
 +              if (nid == *p)
 +                      return copy_conn_list(nid, conn_list, max_conns,
 +                                            p + 2, len);
 +              i += len + 2;
 +      }
 +
 +      len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
 +      if (len < 0)
 +              return len;
 +
 +      /* add to the cache */
 +      old_used = array->used;
 +      if (!add_conn_list(array, nid) || !add_conn_list(array, len))
 +              goto error_add;
 +      for (i = 0; i < len; i++)
 +              if (!add_conn_list(array, list[i]))
 +                      goto error_add;
 +
 +      return copy_conn_list(nid, conn_list, max_conns, list, len);
 +              
 + error_add:
 +      array->used = old_used;
 +      return -ENOMEM;
 +}
 +EXPORT_SYMBOL_HDA(snd_hda_get_connections);
 +
 +static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
 +                           hda_nid_t *conn_list, int max_conns)
  {
        unsigned int parm;
        int i, conn_len, conns;
        }
        return conns;
  }
 -EXPORT_SYMBOL_HDA(snd_hda_get_connections);
  
 +static bool add_conn_list(struct snd_array *array, hda_nid_t nid)
 +{
 +      hda_nid_t *p = snd_array_new(array);
 +      if (!p)
 +              return false;
 +      *p = nid;
 +      return true;
 +}
 +
 +static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
 +                        hda_nid_t *src, int len)
 +{
 +      if (len > max_dst) {
 +              snd_printk(KERN_ERR "hda_codec: "
 +                         "Too many connections %d for NID 0x%x\n",
 +                         len, nid);
 +              return -EINVAL;
 +      }
 +      memcpy(dst, src, len * sizeof(hda_nid_t));
 +      return len;
 +}
  
  /**
   * snd_hda_queue_unsol_event - add an unsolicited event to queue
@@@ -1082,7 -1019,6 +1082,7 @@@ static void snd_hda_codec_free(struct h
        list_del(&codec->list);
        snd_array_free(&codec->mixers);
        snd_array_free(&codec->nids);
 +      snd_array_free(&codec->conn_lists);
        codec->bus->caddr_tbl[codec->addr] = NULL;
        if (codec->patch_ops.free)
                codec->patch_ops.free(codec);
@@@ -1143,7 -1079,6 +1143,7 @@@ int /*__devinit*/ snd_hda_codec_new(str
        snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
        snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
        snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
 +      snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
        if (codec->bus->modelname) {
                codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
                if (!codec->modelname) {
@@@ -3730,7 -3665,7 +3730,7 @@@ int snd_hda_codec_build_pcms(struct hda
   * with the proper parameters for set up.
   * ops.cleanup should be called in hw_free for clean up of streams.
   *
-  * This function returns 0 if successfull, or a negative error code.
+  * This function returns 0 if successful, or a negative error code.
   */
  int __devinit snd_hda_build_pcms(struct hda_bus *bus)
  {
@@@ -4697,13 -4632,10 +4697,13 @@@ int snd_hda_parse_pin_def_config(struc
        /*
         * debug prints of the parsed results
         */
 -      snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
 +      snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
                   cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
                   cfg->line_out_pins[2], cfg->line_out_pins[3],
 -                 cfg->line_out_pins[4]);
 +                 cfg->line_out_pins[4],
 +                 cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
 +                 (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
 +                  "speaker" : "line"));
        snd_printd("   speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
                   cfg->speaker_outs, cfg->speaker_pins[0],
                   cfg->speaker_pins[1], cfg->speaker_pins[2],
@@@ -4923,7 -4855,7 +4923,7 @@@ EXPORT_SYMBOL_HDA(snd_hda_suspend)
   *
   * Returns 0 if successful.
   *
-  * This fucntion is defined only when POWER_SAVE isn't set.
+  * This function is defined only when POWER_SAVE isn't set.
   * In the power-save mode, the codec is resumed dynamically.
   */
  int snd_hda_resume(struct hda_bus *bus)
@@@ -299,18 -299,6 +299,18 @@@ struct alc_customize_define 
  
  struct alc_fixup;
  
 +struct alc_multi_io {
 +      hda_nid_t pin;          /* multi-io widget pin NID */
 +      hda_nid_t dac;          /* DAC to be connected */
 +      unsigned int ctl_in;    /* cached input-pin control value */
 +};
 +
 +enum {
 +      ALC_AUTOMUTE_PIN,       /* change the pin control */
 +      ALC_AUTOMUTE_AMP,       /* mute/unmute the pin AMP */
 +      ALC_AUTOMUTE_MIXER,     /* mute/unmute mixer widget AMP */
 +};
 +
  struct alc_spec {
        /* codec parameterization */
        struct snd_kcontrol_new *mixers[5];     /* mixer arrays */
  #ifdef CONFIG_SND_HDA_POWER_SAVE
        void (*power_hook)(struct hda_codec *codec);
  #endif
 +      void (*shutup)(struct hda_codec *codec);
  
        /* for pin sensing */
 -      unsigned int sense_updated: 1;
        unsigned int jack_present: 1;
 -      unsigned int master_sw: 1;
 +      unsigned int line_jack_present:1;
 +      unsigned int master_mute:1;
        unsigned int auto_mic:1;
 +      unsigned int automute:1;        /* HP automute enabled */
 +      unsigned int detect_line:1;     /* Line-out detection enabled */
 +      unsigned int automute_lines:1;  /* automute line-out as well */
 +      unsigned int automute_hp_lo:1;  /* both HP and LO available */
  
        /* other flags */
        unsigned int no_analog :1; /* digital I/O only */
        unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
        unsigned int single_input_src:1;
 +
 +      /* auto-mute control */
 +      int automute_mode;
 +      hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS];
 +
        int init_amp;
        int codec_variant;      /* flag for other variants */
  
        int fixup_id;
        const struct alc_fixup *fixup_list;
        const char *fixup_name;
 +
 +      /* multi-io */
 +      int multi_ios;
 +      struct alc_multi_io multi_io[4];
  };
  
  /*
@@@ -575,7 -549,7 +575,7 @@@ static int alc_ch_mode_put(struct snd_k
  
  /*
   * Control the mode of pin widget settings via the mixer.  "pc" is used
-  * instead of "%" to avoid consequences of accidently treating the % as
+  * instead of "%" to avoid consequences of accidentally treating the % as
   * being part of a format specifier.  Maximum allowed length of a value is
   * 63 characters plus NULL terminator.
   *
@@@ -1077,105 -1051,42 +1077,105 @@@ static int alc_init_jacks(struct hda_co
        return 0;
  }
  
 -static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
 +static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
  {
 -      struct alc_spec *spec = codec->spec;
 -      unsigned int mute;
 -      hda_nid_t nid;
 -      int i;
 +      int i, present = 0;
  
 -      spec->jack_present = 0;
 -      for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
 -              nid = spec->autocfg.hp_pins[i];
 +      for (i = 0; i < num_pins; i++) {
 +              hda_nid_t nid = pins[i];
                if (!nid)
                        break;
                snd_hda_input_jack_report(codec, nid);
 -              spec->jack_present |= snd_hda_jack_detect(codec, nid);
 +              present |= snd_hda_jack_detect(codec, nid);
        }
 +      return present;
 +}
  
 -      mute = spec->jack_present ? HDA_AMP_MUTE : 0;
 -      /* Toggle internal speakers muting */
 -      for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
 -              nid = spec->autocfg.speaker_pins[i];
 +static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
 +                      bool mute, bool hp_out)
 +{
 +      struct alc_spec *spec = codec->spec;
 +      unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0;
 +      unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT);
 +      int i;
 +
 +      for (i = 0; i < num_pins; i++) {
 +              hda_nid_t nid = pins[i];
                if (!nid)
                        break;
 -              if (pinctl) {
 +              switch (spec->automute_mode) {
 +              case ALC_AUTOMUTE_PIN:
                        snd_hda_codec_write(codec, nid, 0,
 -                                  AC_VERB_SET_PIN_WIDGET_CONTROL,
 -                                  spec->jack_present ? 0 : PIN_OUT);
 -              } else {
 +                                          AC_VERB_SET_PIN_WIDGET_CONTROL,
 +                                          pin_bits);
 +                      break;
 +              case ALC_AUTOMUTE_AMP:
                        snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
 -                                       HDA_AMP_MUTE, mute);
 +                                               HDA_AMP_MUTE, mute_bits);
 +                      break;
 +              case ALC_AUTOMUTE_MIXER:
 +                      nid = spec->automute_mixer_nid[i];
 +                      if (!nid)
 +                              break;
 +                      snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
 +                                               HDA_AMP_MUTE, mute_bits);
 +                      snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1,
 +                                               HDA_AMP_MUTE, mute_bits);
 +                      break;
                }
        }
  }
  
 -static void alc_automute_pin(struct hda_codec *codec)
 +/* Toggle internal speakers muting */
 +static void update_speakers(struct hda_codec *codec)
 +{
 +      struct alc_spec *spec = codec->spec;
 +      int on;
 +
 +      if (!spec->automute)
 +              on = 0;
 +      else
 +              on = spec->jack_present | spec->line_jack_present;
 +      on |= spec->master_mute;
 +      do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
 +                  spec->autocfg.speaker_pins, on, false);
 +
 +      /* toggle line-out mutes if needed, too */
 +      /* if LO is a copy of either HP or Speaker, don't need to handle it */
 +      if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
 +          spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
 +              return;
 +      if (!spec->automute_lines || !spec->automute)
 +              on = 0;
 +      else
 +              on = spec->jack_present;
 +      on |= spec->master_mute;
 +      do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
 +                  spec->autocfg.line_out_pins, on, false);
 +}
 +
 +static void alc_hp_automute(struct hda_codec *codec)
  {
 -      alc_automute_speaker(codec, 1);
 +      struct alc_spec *spec = codec->spec;
 +
 +      if (!spec->automute)
 +              return;
 +      spec->jack_present =
 +              detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
 +                           spec->autocfg.hp_pins);
 +      update_speakers(codec);
 +}
 +
 +static void alc_line_automute(struct hda_codec *codec)
 +{
 +      struct alc_spec *spec = codec->spec;
 +
 +      if (!spec->automute || !spec->detect_line)
 +              return;
 +      spec->line_jack_present =
 +              detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
 +                           spec->autocfg.line_out_pins);
 +      update_speakers(codec);
  }
  
  static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
@@@ -1273,10 -1184,7 +1273,10 @@@ static void alc_sku_unsol_event(struct 
                res >>= 26;
        switch (res) {
        case ALC880_HP_EVENT:
 -              alc_automute_pin(codec);
 +              alc_hp_automute(codec);
 +              break;
 +      case ALC880_FRONT_EVENT:
 +              alc_line_automute(codec);
                break;
        case ALC880_MIC_EVENT:
                alc_mic_automute(codec);
  
  static void alc_inithook(struct hda_codec *codec)
  {
 -      alc_automute_pin(codec);
 +      alc_hp_automute(codec);
 +      alc_line_automute(codec);
        alc_mic_automute(codec);
  }
  
@@@ -1329,43 -1236,6 +1329,43 @@@ static void set_eapd(struct hda_codec *
                                    on ? 2 : 0);
  }
  
 +/* turn on/off EAPD controls of the codec */
 +static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
 +{
 +      /* We currently only handle front, HP */
 +      switch (codec->vendor_id) {
 +      case 0x10ec0260:
 +              set_eapd(codec, 0x0f, on);
 +              set_eapd(codec, 0x10, on);
 +              break;
 +      case 0x10ec0262:
 +      case 0x10ec0267:
 +      case 0x10ec0268:
 +      case 0x10ec0269:
 +      case 0x10ec0270:
 +      case 0x10ec0272:
 +      case 0x10ec0660:
 +      case 0x10ec0662:
 +      case 0x10ec0663:
 +      case 0x10ec0665:
 +      case 0x10ec0862:
 +      case 0x10ec0889:
 +      case 0x10ec0892:
 +              set_eapd(codec, 0x14, on);
 +              set_eapd(codec, 0x15, on);
 +              break;
 +      }
 +}
 +
 +/* generic shutup callback;
 + * just turning off EPAD and a little pause for avoiding pop-noise
 + */
 +static void alc_eapd_shutup(struct hda_codec *codec)
 +{
 +      alc_auto_setup_eapd(codec, false);
 +      msleep(200);
 +}
 +
  static void alc_auto_init_amp(struct hda_codec *codec, int type)
  {
        unsigned int tmp;
                snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
                break;
        case ALC_INIT_DEFAULT:
 -              switch (codec->vendor_id) {
 -              case 0x10ec0260:
 -                      set_eapd(codec, 0x0f, 1);
 -                      set_eapd(codec, 0x10, 1);
 -                      break;
 -              case 0x10ec0262:
 -              case 0x10ec0267:
 -              case 0x10ec0268:
 -              case 0x10ec0269:
 -              case 0x10ec0270:
 -              case 0x10ec0272:
 -              case 0x10ec0660:
 -              case 0x10ec0662:
 -              case 0x10ec0663:
 -              case 0x10ec0665:
 -              case 0x10ec0862:
 -              case 0x10ec0889:
 -                      set_eapd(codec, 0x14, 1);
 -                      set_eapd(codec, 0x15, 1);
 -                      break;
 -              }
 +              alc_auto_setup_eapd(codec, true);
                switch (codec->vendor_id) {
                case 0x10ec0260:
                        snd_hda_codec_write(codec, 0x1a, 0,
        }
  }
  
 +static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
 +                                struct snd_ctl_elem_info *uinfo)
 +{
 +      struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 +      struct alc_spec *spec = codec->spec;
 +      static const char * const texts2[] = {
 +              "Disabled", "Enabled"
 +      };
 +      static const char * const texts3[] = {
 +              "Disabled", "Speaker Only", "Line-Out+Speaker"
 +      };
 +      const char * const *texts;
 +
 +      uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 +      uinfo->count = 1;
 +      if (spec->automute_hp_lo) {
 +              uinfo->value.enumerated.items = 3;
 +              texts = texts3;
 +      } else {
 +              uinfo->value.enumerated.items = 2;
 +              texts = texts2;
 +      }
 +      if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
 +              uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
 +      strcpy(uinfo->value.enumerated.name,
 +             texts[uinfo->value.enumerated.item]);
 +      return 0;
 +}
 +
 +static int alc_automute_mode_get(struct snd_kcontrol *kcontrol,
 +                               struct snd_ctl_elem_value *ucontrol)
 +{
 +      struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 +      struct alc_spec *spec = codec->spec;
 +      unsigned int val;
 +      if (!spec->automute)
 +              val = 0;
 +      else if (!spec->automute_lines)
 +              val = 1;
 +      else
 +              val = 2;
 +      ucontrol->value.enumerated.item[0] = val;
 +      return 0;
 +}
 +
 +static int alc_automute_mode_put(struct snd_kcontrol *kcontrol,
 +                               struct snd_ctl_elem_value *ucontrol)
 +{
 +      struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 +      struct alc_spec *spec = codec->spec;
 +
 +      switch (ucontrol->value.enumerated.item[0]) {
 +      case 0:
 +              if (!spec->automute)
 +                      return 0;
 +              spec->automute = 0;
 +              break;
 +      case 1:
 +              if (spec->automute && !spec->automute_lines)
 +                      return 0;
 +              spec->automute = 1;
 +              spec->automute_lines = 0;
 +              break;
 +      case 2:
 +              if (!spec->automute_hp_lo)
 +                      return -EINVAL;
 +              if (spec->automute && spec->automute_lines)
 +                      return 0;
 +              spec->automute = 1;
 +              spec->automute_lines = 1;
 +              break;
 +      default:
 +              return -EINVAL;
 +      }
 +      update_speakers(codec);
 +      return 1;
 +}
 +
 +static struct snd_kcontrol_new alc_automute_mode_enum = {
 +      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 +      .name = "Auto-Mute Mode",
 +      .info = alc_automute_mode_info,
 +      .get = alc_automute_mode_get,
 +      .put = alc_automute_mode_put,
 +};
 +
 +static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec);
 +
 +static int alc_add_automute_mode_enum(struct hda_codec *codec)
 +{
 +      struct alc_spec *spec = codec->spec;
 +      struct snd_kcontrol_new *knew;
 +
 +      knew = alc_kcontrol_new(spec);
 +      if (!knew)
 +              return -ENOMEM;
 +      *knew = alc_automute_mode_enum;
 +      knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL);
 +      if (!knew->name)
 +              return -ENOMEM;
 +      return 0;
 +}
 +
  static void alc_init_auto_hp(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
 +      int present = 0;
        int i;
  
 -      if (!cfg->hp_pins[0]) {
 -              if (cfg->line_out_type != AUTO_PIN_HP_OUT)
 -                      return;
 -      }
 +      if (cfg->hp_pins[0])
 +              present++;
 +      if (cfg->line_out_pins[0])
 +              present++;
 +      if (cfg->speaker_pins[0])
 +              present++;
 +      if (present < 2) /* need two different output types */
 +              return;
 +      if (present == 3)
 +              spec->automute_hp_lo = 1; /* both HP and LO automute */
  
        if (!cfg->speaker_pins[0]) {
 -              if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
 -                      return;
                memcpy(cfg->speaker_pins, cfg->line_out_pins,
                       sizeof(cfg->speaker_pins));
                cfg->speaker_outs = cfg->line_outs;
        }
  
        for (i = 0; i < cfg->hp_outs; i++) {
 +              hda_nid_t nid = cfg->hp_pins[i];
 +              if (!(snd_hda_query_pin_caps(codec, nid) &
 +                    AC_PINCAP_PRES_DETECT))
 +                      continue;
                snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
 -                          cfg->hp_pins[i]);
 -              snd_hda_codec_write_cache(codec, cfg->hp_pins[i], 0,
 +                          nid);
 +              snd_hda_codec_write_cache(codec, nid, 0,
                                  AC_VERB_SET_UNSOLICITED_ENABLE,
                                  AC_USRSP_EN | ALC880_HP_EVENT);
 +              spec->automute = 1;
 +              spec->automute_mode = ALC_AUTOMUTE_PIN;
 +      }
 +      if (spec->automute && cfg->line_out_pins[0] &&
 +          cfg->line_out_pins[0] != cfg->hp_pins[0] &&
 +          cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
 +              for (i = 0; i < cfg->line_outs; i++) {
 +                      hda_nid_t nid = cfg->line_out_pins[i];
 +                      if (!(snd_hda_query_pin_caps(codec, nid) &
 +                            AC_PINCAP_PRES_DETECT))
 +                              continue;
 +                      snd_printdd("realtek: Enable Line-Out auto-muting "
 +                                  "on NID 0x%x\n", nid);
 +                      snd_hda_codec_write_cache(codec, nid, 0,
 +                                      AC_VERB_SET_UNSOLICITED_ENABLE,
 +                                      AC_USRSP_EN | ALC880_FRONT_EVENT);
 +                      spec->detect_line = 1;
 +              }
 +              spec->automute_lines = 1;
 +      }
 +
 +      if (spec->automute) {
 +              /* create a control for automute mode */
 +              alc_add_automute_mode_enum(codec);
 +              spec->unsol_event = alc_sku_unsol_event;
        }
 -      spec->unsol_event = alc_sku_unsol_event;
  }
  
  static void alc_init_auto_mic(struct hda_codec *codec)
@@@ -1829,6 -1583,9 +1829,6 @@@ do_sku
                                return 1;
                spec->autocfg.hp_pins[0] = nid;
        }
 -
 -      alc_init_auto_hp(codec);
 -      alc_init_auto_mic(codec);
        return 1;
  }
  
@@@ -1841,10 -1598,9 +1841,10 @@@ static void alc_ssid_check(struct hda_c
                snd_printd("realtek: "
                           "Enable default setup for auto mode as fallback\n");
                spec->init_amp = ALC_INIT_DEFAULT;
 -              alc_init_auto_hp(codec);
 -              alc_init_auto_mic(codec);
        }
 +
 +      alc_init_auto_hp(codec);
 +      alc_init_auto_mic(codec);
  }
  
  /*
@@@ -2187,6 -1943,22 +2187,6 @@@ static struct hda_verb alc888_fujitsu_x
        {}
  };
  
 -static void alc_automute_amp(struct hda_codec *codec)
 -{
 -      alc_automute_speaker(codec, 0);
 -}
 -
 -static void alc_automute_amp_unsol_event(struct hda_codec *codec,
 -                                       unsigned int res)
 -{
 -      if (codec->vendor_id == 0x10ec0880)
 -              res >>= 28;
 -      else
 -              res >>= 26;
 -      if (res == ALC880_HP_EVENT)
 -              alc_automute_amp(codec);
 -}
 -
  static void alc889_automute_setup(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
        spec->autocfg.speaker_pins[2] = 0x17;
        spec->autocfg.speaker_pins[3] = 0x19;
        spec->autocfg.speaker_pins[4] = 0x1a;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc889_intel_init_hook(struct hda_codec *codec)
  {
        alc889_coef_init(codec);
 -      alc_automute_amp(codec);
 +      alc_hp_automute(codec);
  }
  
  static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
        spec->autocfg.hp_pins[1] = 0x1b; /* hp */
        spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
        spec->autocfg.speaker_pins[1] = 0x15; /* bass */
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  /*
@@@ -2499,8 -2267,6 +2499,8 @@@ static void alc888_acer_aspire_4930g_se
        spec->autocfg.speaker_pins[0] = 0x14;
        spec->autocfg.speaker_pins[1] = 0x16;
        spec->autocfg.speaker_pins[2] = 0x17;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
        spec->autocfg.speaker_pins[0] = 0x14;
        spec->autocfg.speaker_pins[1] = 0x16;
        spec->autocfg.speaker_pins[2] = 0x17;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
        spec->autocfg.speaker_pins[0] = 0x14;
        spec->autocfg.speaker_pins[1] = 0x16;
        spec->autocfg.speaker_pins[2] = 0x17;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
        spec->autocfg.speaker_pins[0] = 0x14;
        spec->autocfg.speaker_pins[1] = 0x16;
        spec->autocfg.speaker_pins[2] = 0x1b;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  /*
@@@ -3612,13 -3372,11 +3612,13 @@@ static void alc880_uniwill_setup(struc
        spec->autocfg.hp_pins[0] = 0x14;
        spec->autocfg.speaker_pins[0] = 0x15;
        spec->autocfg.speaker_pins[0] = 0x16;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc880_uniwill_init_hook(struct hda_codec *codec)
  {
 -      alc_automute_amp(codec);
 +      alc_hp_automute(codec);
        alc88x_simple_mic_automute(codec);
  }
  
@@@ -3633,7 -3391,7 +3633,7 @@@ static void alc880_uniwill_unsol_event(
                alc88x_simple_mic_automute(codec);
                break;
        default:
 -              alc_automute_amp_unsol_event(codec, res);
 +              alc_sku_unsol_event(codec, res);
                break;
        }
  }
@@@ -3644,8 -3402,6 +3644,8 @@@ static void alc880_uniwill_p53_setup(st
  
        spec->autocfg.hp_pins[0] = 0x14;
        spec->autocfg.speaker_pins[0] = 0x15;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
@@@ -3670,7 -3426,7 +3670,7 @@@ static void alc880_uniwill_p53_unsol_ev
        if ((res >> 28) == ALC880_DCVOL_EVENT)
                alc880_uniwill_p53_dcvol_automute(codec);
        else
 -              alc_automute_amp_unsol_event(codec, res);
 +              alc_sku_unsol_event(codec, res);
  }
  
  /*
@@@ -3914,8 -3670,6 +3914,8 @@@ static void alc880_lg_setup(struct hda_
  
        spec->autocfg.hp_pins[0] = 0x1b;
        spec->autocfg.speaker_pins[0] = 0x17;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  /*
@@@ -4000,8 -3754,6 +4000,8 @@@ static void alc880_lg_lw_setup(struct h
  
        spec->autocfg.hp_pins[0] = 0x1b;
        spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
@@@ -4049,7 -3801,7 +4049,7 @@@ static struct hda_verb alc880_medion_ri
  static void alc880_medion_rim_automute(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 -      alc_automute_amp(codec);
 +      alc_hp_automute(codec);
        /* toggle EAPD */
        if (spec->jack_present)
                snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
@@@ -4073,8 -3825,6 +4073,8 @@@ static void alc880_medion_rim_setup(str
  
        spec->autocfg.hp_pins[0] = 0x14;
        spec->autocfg.speaker_pins[0] = 0x1b;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  #ifdef CONFIG_SND_HDA_POWER_SAVE
@@@ -4443,10 -4193,6 +4443,10 @@@ static int alc_build_pcms(struct hda_co
  
  static inline void alc_shutup(struct hda_codec *codec)
  {
 +      struct alc_spec *spec = codec->spec;
 +
 +      if (spec && spec->shutup)
 +              spec->shutup(codec);
        snd_hda_shutup_pins(codec);
  }
  
@@@ -4480,7 -4226,28 +4480,7 @@@ static void alc_free(struct hda_codec *
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  static void alc_power_eapd(struct hda_codec *codec)
  {
 -      /* We currently only handle front, HP */
 -      switch (codec->vendor_id) {
 -      case 0x10ec0260:
 -              set_eapd(codec, 0x0f, 0);
 -              set_eapd(codec, 0x10, 0);
 -              break;
 -      case 0x10ec0262:
 -      case 0x10ec0267:
 -      case 0x10ec0268:
 -      case 0x10ec0269:
 -      case 0x10ec0270:
 -      case 0x10ec0272:
 -      case 0x10ec0660:
 -      case 0x10ec0662:
 -      case 0x10ec0663:
 -      case 0x10ec0665:
 -      case 0x10ec0862:
 -      case 0x10ec0889:
 -              set_eapd(codec, 0x14, 0);
 -              set_eapd(codec, 0x15, 0);
 -              break;
 -      }
 +      alc_auto_setup_eapd(codec, false);
  }
  
  static int alc_suspend(struct hda_codec *codec, pm_message_t state)
  #ifdef SND_HDA_NEEDS_RESUME
  static int alc_resume(struct hda_codec *codec)
  {
 +      msleep(150); /* to avoid pop noise */
        codec->patch_ops.init(codec);
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
@@@ -5028,7 -4794,7 +5028,7 @@@ static struct alc_config_preset alc880_
                .input_mux = &alc880_f1734_capture_source,
                .unsol_event = alc880_uniwill_p53_unsol_event,
                .setup = alc880_uniwill_p53_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC880_ASUS] = {
                .mixers = { alc880_asus_mixer },
                .input_mux = &alc880_capture_source,
                .unsol_event = alc880_uniwill_p53_unsol_event,
                .setup = alc880_uniwill_p53_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC880_FUJITSU] = {
                .mixers = { alc880_fujitsu_mixer },
                .input_mux = &alc880_capture_source,
                .unsol_event = alc880_uniwill_p53_unsol_event,
                .setup = alc880_uniwill_p53_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC880_CLEVO] = {
                .mixers = { alc880_three_stack_mixer },
                .channel_mode = alc880_lg_ch_modes,
                .need_dac_fix = 1,
                .input_mux = &alc880_lg_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc880_lg_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
  #ifdef CONFIG_SND_HDA_POWER_SAVE
                .loopbacks = alc880_lg_loopbacks,
  #endif
                .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
                .channel_mode = alc880_lg_lw_modes,
                .input_mux = &alc880_lg_lw_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc880_lg_lw_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC880_MEDION_RIM] = {
                .mixers = { alc880_medion_rim_mixer },
@@@ -5224,19 -4990,14 +5224,19 @@@ static struct snd_kcontrol_new alc880_c
        HDA_BIND_MUTE(NULL, 0, 0, 0),
  };
  
 +static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
 +{
 +      snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
 +      return snd_array_new(&spec->kctls);
 +}
 +
  /* add dynamic controls */
  static int add_control(struct alc_spec *spec, int type, const char *name,
                       int cidx, unsigned long val)
  {
        struct snd_kcontrol_new *knew;
  
 -      snd_array_init(&spec->kctls, sizeof(*knew), 32);
 -      knew = snd_array_new(&spec->kctls);
 +      knew = alc_kcontrol_new(spec);
        if (!knew)
                return -ENOMEM;
        *knew = alc880_control_templates[type];
@@@ -5317,13 -5078,10 +5317,13 @@@ static int alc880_auto_fill_dac_nids(st
        return 0;
  }
  
 -static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg,
 +static const char *alc_get_line_out_pfx(struct alc_spec *spec,
                                        bool can_be_master)
  {
 -      if (!cfg->hp_outs && !cfg->speaker_outs && can_be_master)
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
 +
 +      if (cfg->line_outs == 1 && !spec->multi_ios &&
 +          !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
                return "Master";
  
        switch (cfg->line_out_type) {
        case AUTO_PIN_HP_OUT:
                return "Headphone";
        default:
 -              if (cfg->line_outs == 1)
 +              if (cfg->line_outs == 1 && !spec->multi_ios)
                        return "PCM";
                break;
        }
@@@ -5348,15 -5106,11 +5348,15 @@@ static int alc880_auto_create_multi_out
        static const char * const chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
 -      const char *pfx = alc_get_line_out_pfx(cfg, false);
 +      const char *pfx = alc_get_line_out_pfx(spec, false);
        hda_nid_t nid;
 -      int i, err;
 +      int i, err, noutputs;
  
 -      for (i = 0; i < cfg->line_outs; i++) {
 +      noutputs = cfg->line_outs;
 +      if (spec->multi_ios > 0)
 +              noutputs += spec->multi_ios;
 +
 +      for (i = 0; i < noutputs; i++) {
                if (!spec->multiout.dac_nids[i])
                        continue;
                nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
@@@ -5622,8 -5376,6 +5622,8 @@@ static void alc880_auto_init_input_src(
        }
  }
  
 +static int alc_auto_add_multi_channel_mode(struct hda_codec *codec);
 +
  /* parse the BIOS configuration and set up the alc_spec */
  /* return 1 if successful, 0 if the proper config is not found,
   * or a negative error code
@@@ -5644,9 -5396,6 +5644,9 @@@ static int alc880_parse_auto_config(str
        err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
        if (err < 0)
                return err;
 +      err = alc_auto_add_multi_channel_mode(codec);
 +      if (err < 0)
 +              return err;
        err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
@@@ -5896,6 -5645,7 +5896,7 @@@ static void fillup_priv_adc_nids(struc
  static struct snd_pci_quirk beep_white_list[] = {
        SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
        SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
+       SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
        SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
        {}
  };
@@@ -6153,14 -5903,21 +6154,14 @@@ static struct snd_kcontrol_new alc260_i
  };
  
  /* update HP, line and mono out pins according to the master switch */
 -static void alc260_hp_master_update(struct hda_codec *codec,
 -                                  hda_nid_t hp, hda_nid_t line,
 -                                  hda_nid_t mono)
 +static void alc260_hp_master_update(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 -      unsigned int val = spec->master_sw ? PIN_HP : 0;
 -      /* change HP and line-out pins */
 -      snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 -                          val);
 -      snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 -                          val);
 -      /* mono (speaker) depending on the HP jack sense */
 -      val = (val && !spec->jack_present) ? PIN_OUT : 0;
 -      snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 -                          val);
 +
 +      /* change HP pins */
 +      do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
 +                  spec->autocfg.hp_pins, spec->master_mute, true);
 +      update_speakers(codec);
  }
  
  static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
  {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct alc_spec *spec = codec->spec;
 -      *ucontrol->value.integer.value = spec->master_sw;
 +      *ucontrol->value.integer.value = !spec->master_mute;
        return 0;
  }
  
@@@ -6177,12 -5934,16 +6178,12 @@@ static int alc260_hp_master_sw_put(stru
  {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct alc_spec *spec = codec->spec;
 -      int val = !!*ucontrol->value.integer.value;
 -      hda_nid_t hp, line, mono;
 +      int val = !*ucontrol->value.integer.value;
  
 -      if (val == spec->master_sw)
 +      if (val == spec->master_mute)
                return 0;
 -      spec->master_sw = val;
 -      hp = (kcontrol->private_value >> 16) & 0xff;
 -      line = (kcontrol->private_value >> 8) & 0xff;
 -      mono = kcontrol->private_value & 0xff;
 -      alc260_hp_master_update(codec, hp, line, mono);
 +      spec->master_mute = val;
 +      alc260_hp_master_update(codec);
        return 1;
  }
  
@@@ -6194,6 -5955,7 +6195,6 @@@ static struct snd_kcontrol_new alc260_h
                .info = snd_ctl_boolean_mono_info,
                .get = alc260_hp_master_sw_get,
                .put = alc260_hp_master_sw_put,
 -              .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
        },
        HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
@@@ -6210,15 -5972,18 +6211,15 @@@ static struct hda_verb alc260_hp_unsol_
        {},
  };
  
 -static void alc260_hp_automute(struct hda_codec *codec)
 +static void alc260_hp_setup(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
  
 -      spec->jack_present = snd_hda_jack_detect(codec, 0x10);
 -      alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
 -}
 -
 -static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
 -{
 -      if ((res >> 26) == ALC880_HP_EVENT)
 -              alc260_hp_automute(codec);
 +      spec->autocfg.hp_pins[0] = 0x0f;
 +      spec->autocfg.speaker_pins[0] = 0x10;
 +      spec->autocfg.speaker_pins[1] = 0x11;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_PIN;
  }
  
  static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
                .info = snd_ctl_boolean_mono_info,
                .get = alc260_hp_master_sw_get,
                .put = alc260_hp_master_sw_put,
 -              .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
        },
        HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
        { } /* end */
  };
  
 +static void alc260_hp_3013_setup(struct hda_codec *codec)
 +{
 +      struct alc_spec *spec = codec->spec;
 +
 +      spec->autocfg.hp_pins[0] = 0x15;
 +      spec->autocfg.speaker_pins[0] = 0x10;
 +      spec->autocfg.speaker_pins[1] = 0x11;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_PIN;
 +}
 +
  static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
        .ops = &snd_hda_bind_vol,
        .values = {
@@@ -6284,16 -6039,38 +6285,16 @@@ static struct hda_verb alc260_hp_3013_u
        {},
  };
  
 -static void alc260_hp_3013_automute(struct hda_codec *codec)
 +static void alc260_hp_3012_setup(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
  
 -      spec->jack_present = snd_hda_jack_detect(codec, 0x15);
 -      alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
 -}
 -
 -static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
 -                                     unsigned int res)
 -{
 -      if ((res >> 26) == ALC880_HP_EVENT)
 -              alc260_hp_3013_automute(codec);
 -}
 -
 -static void alc260_hp_3012_automute(struct hda_codec *codec)
 -{
 -      unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
 -
 -      snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 -                          bits);
 -      snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 -                          bits);
 -      snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
 -                          bits);
 -}
 -
 -static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
 -                                     unsigned int res)
 -{
 -      if ((res >> 26) == ALC880_HP_EVENT)
 -              alc260_hp_3012_automute(codec);
 +      spec->autocfg.hp_pins[0] = 0x10;
 +      spec->autocfg.speaker_pins[0] = 0x0f;
 +      spec->autocfg.speaker_pins[1] = 0x11;
 +      spec->autocfg.speaker_pins[2] = 0x15;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_PIN;
  }
  
  /* Fujitsu S702x series laptops.  ALC260 pin usage: Mic/Line jack = 0x12,
@@@ -7418,9 -7195,8 +7419,9 @@@ static struct alc_config_preset alc260_
                .num_channel_mode = ARRAY_SIZE(alc260_modes),
                .channel_mode = alc260_modes,
                .input_mux = &alc260_capture_source,
 -              .unsol_event = alc260_hp_unsol_event,
 -              .init_hook = alc260_hp_automute,
 +              .unsol_event = alc_sku_unsol_event,
 +              .setup = alc260_hp_setup,
 +              .init_hook = alc_inithook,
        },
        [ALC260_HP_DC7600] = {
                .mixers = { alc260_hp_dc7600_mixer,
                .num_channel_mode = ARRAY_SIZE(alc260_modes),
                .channel_mode = alc260_modes,
                .input_mux = &alc260_capture_source,
 -              .unsol_event = alc260_hp_3012_unsol_event,
 -              .init_hook = alc260_hp_3012_automute,
 +              .unsol_event = alc_sku_unsol_event,
 +              .setup = alc260_hp_3012_setup,
 +              .init_hook = alc_inithook,
        },
        [ALC260_HP_3013] = {
                .mixers = { alc260_hp_3013_mixer,
                .num_channel_mode = ARRAY_SIZE(alc260_modes),
                .channel_mode = alc260_modes,
                .input_mux = &alc260_capture_source,
 -              .unsol_event = alc260_hp_3013_unsol_event,
 -              .init_hook = alc260_hp_3013_automute,
 +              .unsol_event = alc_sku_unsol_event,
 +              .setup = alc260_hp_3013_setup,
 +              .init_hook = alc_inithook,
        },
        [ALC260_FUJITSU_S702X] = {
                .mixers = { alc260_fujitsu_mixer },
@@@ -7610,7 -7384,6 +7611,7 @@@ static int patch_alc260(struct hda_code
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC260_AUTO)
                spec->init_hook = alc260_auto_init;
 +      spec->shutup = alc_eapd_shutup;
  #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc260_loopbacks;
@@@ -8827,8 -8600,6 +8828,8 @@@ static void alc885_imac24_setup(struct 
        spec->autocfg.hp_pins[0] = 0x14;
        spec->autocfg.speaker_pins[0] = 0x18;
        spec->autocfg.speaker_pins[1] = 0x1a;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  #define alc885_mb5_setup      alc885_imac24_setup
@@@ -8841,8 -8612,6 +8842,8 @@@ static void alc885_mba21_setup(struct h
  
         spec->autocfg.hp_pins[0] = 0x14;
         spec->autocfg.speaker_pins[0] = 0x18;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  
@@@ -8853,8 -8622,6 +8854,8 @@@ static void alc885_mbp3_setup(struct hd
  
        spec->autocfg.hp_pins[0] = 0x15;
        spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc885_imac91_setup(struct hda_codec *codec)
        spec->autocfg.hp_pins[0] = 0x14;
        spec->autocfg.speaker_pins[0] = 0x18;
        spec->autocfg.speaker_pins[1] = 0x1a;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static struct hda_verb alc882_targa_verbs[] = {
  static void alc882_targa_automute(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 -      alc_automute_amp(codec);
 +      alc_hp_automute(codec);
        snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
                                  spec->jack_present ? 1 : 3);
  }
@@@ -8898,8 -8663,6 +8899,8 @@@ static void alc882_targa_setup(struct h
  
        spec->autocfg.hp_pins[0] = 0x14;
        spec->autocfg.speaker_pins[0] = 0x1b;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
@@@ -8987,7 -8750,7 +8988,7 @@@ static void alc885_macpro_init_hook(str
  static void alc885_imac24_init_hook(struct hda_codec *codec)
  {
        alc885_macpro_init_hook(codec);
 -      alc_automute_amp(codec);
 +      alc_hp_automute(codec);
  }
  
  /*
@@@ -9345,8 -9108,6 +9346,8 @@@ static void alc883_medion_wim2160_setup
  
        spec->autocfg.hp_pins[0] = 0x1a;
        spec->autocfg.speaker_pins[0] = 0x15;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
@@@ -9499,8 -9260,6 +9500,8 @@@ static void alc883_mitac_setup(struct h
        spec->autocfg.hp_pins[0] = 0x15;
        spec->autocfg.speaker_pins[0] = 0x14;
        spec->autocfg.speaker_pins[1] = 0x17;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static struct hda_verb alc883_mitac_verbs[] = {
@@@ -9665,8 -9424,6 +9666,8 @@@ static void alc888_3st_hp_setup(struct 
        spec->autocfg.speaker_pins[0] = 0x14;
        spec->autocfg.speaker_pins[1] = 0x16;
        spec->autocfg.speaker_pins[2] = 0x18;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static struct hda_verb alc888_3st_hp_verbs[] = {
@@@ -9719,15 -9476,33 +9720,15 @@@ static struct hda_channel_mode alc888_3
        { 6, alc888_3st_hp_6ch_init },
  };
  
 -/* toggle front-jack and RCA according to the hp-jack state */
 -static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
 +static void alc888_lenovo_ms7195_setup(struct hda_codec *codec)
  {
 -      unsigned int present = snd_hda_jack_detect(codec, 0x1b);
 -
 -      snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 -      snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 -}
 -
 -/* toggle RCA according to the front-jack state */
 -static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
 -{
 -      unsigned int present = snd_hda_jack_detect(codec, 0x14);
 -
 -      snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
 -}
 +      struct alc_spec *spec = codec->spec;
  
 -static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
 -                                           unsigned int res)
 -{
 -      if ((res >> 26) == ALC880_HP_EVENT)
 -              alc888_lenovo_ms7195_front_automute(codec);
 -      if ((res >> 26) == ALC880_FRONT_EVENT)
 -              alc888_lenovo_ms7195_rca_automute(codec);
 +      spec->autocfg.hp_pins[0] = 0x1b;
 +      spec->autocfg.line_out_pins[0] = 0x14;
 +      spec->autocfg.speaker_pins[0] = 0x15;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  /* toggle speaker-output according to the hp-jack state */
@@@ -9737,8 -9512,6 +9738,8 @@@ static void alc883_lenovo_nb0763_setup(
  
        spec->autocfg.hp_pins[0] = 0x14;
        spec->autocfg.speaker_pins[0] = 0x15;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  /* toggle speaker-output according to the hp-jack state */
@@@ -9751,13 -9524,11 +9752,13 @@@ static void alc883_clevo_m720_setup(str
  
        spec->autocfg.hp_pins[0] = 0x15;
        spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
  {
 -      alc_automute_amp(codec);
 +      alc_hp_automute(codec);
        alc88x_simple_mic_automute(codec);
  }
  
@@@ -9769,7 -9540,7 +9770,7 @@@ static void alc883_clevo_m720_unsol_eve
                alc88x_simple_mic_automute(codec);
                break;
        default:
 -              alc_automute_amp_unsol_event(codec, res);
 +              alc_sku_unsol_event(codec, res);
                break;
        }
  }
@@@ -9781,8 -9552,6 +9782,8 @@@ static void alc883_2ch_fujitsu_pi2515_s
  
        spec->autocfg.hp_pins[0] = 0x14;
        spec->autocfg.speaker_pins[0] = 0x15;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc883_haier_w66_setup(struct hda_codec *codec)
  
        spec->autocfg.hp_pins[0] = 0x1b;
        spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
 -static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
 +static void alc883_lenovo_101e_setup(struct hda_codec *codec)
  {
 -      int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
 -
 -      snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -}
 -
 -static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
 -{
 -      int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
 -
 -      snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -}
 +      struct alc_spec *spec = codec->spec;
  
 -static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
 -                                         unsigned int res)
 -{
 -      if ((res >> 26) == ALC880_HP_EVENT)
 -              alc883_lenovo_101e_all_automute(codec);
 -      if ((res >> 26) == ALC880_FRONT_EVENT)
 -              alc883_lenovo_101e_ispeaker_automute(codec);
 +      spec->autocfg.hp_pins[0] = 0x1b;
 +      spec->autocfg.line_out_pins[0] = 0x14;
 +      spec->autocfg.speaker_pins[0] = 0x15;
 +      spec->automute = 1;
 +      spec->detect_line = 1;
 +      spec->automute_lines = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  /* toggle speaker-output according to the hp-jack state */
@@@ -9816,8 -9597,6 +9817,8 @@@ static void alc883_acer_aspire_setup(st
        spec->autocfg.hp_pins[0] = 0x14;
        spec->autocfg.speaker_pins[0] = 0x15;
        spec->autocfg.speaker_pins[1] = 0x16;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static struct hda_verb alc883_acer_eapd_verbs[] = {
@@@ -9847,8 -9626,6 +9848,8 @@@ static void alc888_6st_dell_setup(struc
        spec->autocfg.speaker_pins[1] = 0x15;
        spec->autocfg.speaker_pins[2] = 0x16;
        spec->autocfg.speaker_pins[3] = 0x17;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc888_lenovo_sky_setup(struct hda_codec *codec)
        spec->autocfg.speaker_pins[2] = 0x16;
        spec->autocfg.speaker_pins[3] = 0x17;
        spec->autocfg.speaker_pins[4] = 0x1a;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc883_vaiott_setup(struct hda_codec *codec)
        spec->autocfg.hp_pins[0] = 0x15;
        spec->autocfg.speaker_pins[0] = 0x14;
        spec->autocfg.speaker_pins[1] = 0x17;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static struct hda_verb alc888_asus_m90v_verbs[] = {
@@@ -9899,8 -9672,6 +9900,8 @@@ static void alc883_mode2_setup(struct h
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.mux_idx = 1;
        spec->auto_mic = 1;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static struct hda_verb alc888_asus_eee1601_verbs[] = {
@@@ -9922,7 -9693,7 +9923,7 @@@ static void alc883_eee1601_inithook(str
  
        spec->autocfg.hp_pins[0] = 0x14;
        spec->autocfg.speaker_pins[0] = 0x1b;
 -      alc_automute_pin(codec);
 +      alc_hp_automute(codec);
  }
  
  static struct hda_verb alc889A_mb31_verbs[] = {
@@@ -10066,7 -9837,7 +10067,7 @@@ static struct snd_pci_quirk alc882_cfg_
  
        SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
  
-       SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
        SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
        SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
        SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
+       SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
  
        SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
        SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
@@@ -10243,9 -10015,9 +10245,9 @@@ static struct alc_config_preset alc882_
                        .channel_mode = alc885_mba21_ch_modes,
                        .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
                        .input_mux = &alc882_capture_source,
 -                      .unsol_event = alc_automute_amp_unsol_event,
 +                      .unsol_event = alc_sku_unsol_event,
                        .setup = alc885_mba21_setup,
 -                      .init_hook = alc_automute_amp,
 +                      .init_hook = alc_hp_automute,
         },
        [ALC885_MBP3] = {
                .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
                .input_mux = &alc882_capture_source,
                .dig_out_nid = ALC882_DIGOUT_NID,
                .dig_in_nid = ALC882_DIGIN_NID,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc885_mbp3_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC885_MB5] = {
                .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
                .input_mux = &mb5_capture_source,
                .dig_out_nid = ALC882_DIGOUT_NID,
                .dig_in_nid = ALC882_DIGIN_NID,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc885_mb5_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC885_MACMINI3] = {
                .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
                .input_mux = &macmini3_capture_source,
                .dig_out_nid = ALC882_DIGOUT_NID,
                .dig_in_nid = ALC882_DIGIN_NID,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc885_macmini3_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC885_MACPRO] = {
                .mixers = { alc882_macpro_mixer },
                .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
                .channel_mode = alc882_ch_modes,
                .input_mux = &alc882_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc885_imac24_setup,
                .init_hook = alc885_imac24_init_hook,
        },
                .input_mux = &alc889A_imac91_capture_source,
                .dig_out_nid = ALC882_DIGOUT_NID,
                .dig_in_nid = ALC882_DIGIN_NID,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc885_imac91_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC882_TARGA] = {
                .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
                .channel_mode = alc882_3ST_6ch_modes,
                .need_dac_fix = 1,
                .input_mux = &alc882_capture_source,
 -              .unsol_event = alc882_targa_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc882_targa_setup,
                .init_hook = alc882_targa_automute,
        },
                .capsrc_nids = alc889_capsrc_nids,
                .input_mux = &alc889_capture_source,
                .setup = alc889_automute_setup,
 -              .init_hook = alc_automute_amp,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .init_hook = alc_hp_automute,
 +              .unsol_event = alc_sku_unsol_event,
                .need_dac_fix = 1,
        },
        [ALC889_INTEL] = {
                .input_mux = &alc889_capture_source,
                .setup = alc889_automute_setup,
                .init_hook = alc889_intel_init_hook,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .need_dac_fix = 1,
        },
        [ALC883_6ST_DIG] = {
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc883_acer_aspire_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC888_ACER_ASPIRE_4930G] = {
                .mixers = { alc888_acer_aspire_4930g_mixer,
                .num_mux_defs =
                        ARRAY_SIZE(alc888_2_capture_sources),
                .input_mux = alc888_2_capture_sources,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc888_acer_aspire_4930g_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC888_ACER_ASPIRE_6530G] = {
                .mixers = { alc888_acer_aspire_6530_mixer },
                .num_mux_defs =
                        ARRAY_SIZE(alc888_2_capture_sources),
                .input_mux = alc888_acer_aspire_6530_sources,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc888_acer_aspire_6530g_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC888_ACER_ASPIRE_8930G] = {
                .mixers = { alc889_acer_aspire_8930g_mixer,
                .num_mux_defs =
                        ARRAY_SIZE(alc889_capture_sources),
                .input_mux = alc889_capture_sources,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc889_acer_aspire_8930g_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
  #ifdef CONFIG_SND_HDA_POWER_SAVE
                .power_hook = alc_power_eapd,
  #endif
                .need_dac_fix = 1,
                .const_channel_count = 6,
                .input_mux = &alc883_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc888_acer_aspire_7730g_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC883_MEDION] = {
                .mixers = { alc883_fivestack_mixer,
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc883_medion_wim2160_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC883_LAPTOP_EAPD] = {
                .mixers = { alc883_base_mixer },
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_lenovo_101e_capture_source,
 -              .unsol_event = alc883_lenovo_101e_unsol_event,
 -              .init_hook = alc883_lenovo_101e_all_automute,
 +              .setup = alc883_lenovo_101e_setup,
 +              .unsol_event = alc_sku_unsol_event,
 +              .init_hook = alc_inithook,
        },
        [ALC883_LENOVO_NB0763] = {
                .mixers = { alc883_lenovo_nb0763_mixer },
                .channel_mode = alc883_3ST_2ch_modes,
                .need_dac_fix = 1,
                .input_mux = &alc883_lenovo_nb0763_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc883_lenovo_nb0763_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC888_LENOVO_MS7195_DIG] = {
                .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
                .channel_mode = alc883_3ST_6ch_modes,
                .need_dac_fix = 1,
                .input_mux = &alc883_capture_source,
 -              .unsol_event = alc883_lenovo_ms7195_unsol_event,
 -              .init_hook = alc888_lenovo_ms7195_front_automute,
 +              .unsol_event = alc_sku_unsol_event,
 +              .setup = alc888_lenovo_ms7195_setup,
 +              .init_hook = alc_inithook,
        },
        [ALC883_HAIER_W66] = {
                .mixers = { alc883_targa_2ch_mixer},
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc883_haier_w66_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC888_3ST_HP] = {
                .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
                .channel_mode = alc888_3st_hp_modes,
                .need_dac_fix = 1,
                .input_mux = &alc883_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc888_3st_hp_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC888_6ST_DELL] = {
                .mixers = { alc883_base_mixer, alc883_chmode_mixer },
                .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
                .channel_mode = alc883_sixstack_modes,
                .input_mux = &alc883_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc888_6st_dell_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC883_MITAC] = {
                .mixers = { alc883_mitac_mixer },
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc883_mitac_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC883_FUJITSU_PI2515] = {
                .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_fujitsu_pi2515_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc883_2ch_fujitsu_pi2515_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC888_FUJITSU_XA3530] = {
                .mixers = { alc888_base_mixer, alc883_chmode_mixer },
                .num_mux_defs =
                        ARRAY_SIZE(alc888_2_capture_sources),
                .input_mux = alc888_2_capture_sources,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc888_fujitsu_xa3530_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC888_LENOVO_SKY] = {
                .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
                .channel_mode = alc883_sixstack_modes,
                .need_dac_fix = 1,
                .input_mux = &alc883_lenovo_sky_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc888_lenovo_sky_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC888_ASUS_M90V] = {
                .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
                .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc883_vaiott_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
  };
  
@@@ -10931,7 -10701,6 +10933,6 @@@ enum 
        PINFIX_LENOVO_Y530,
        PINFIX_PB_M5210,
        PINFIX_ACER_ASPIRE_7736,
-       PINFIX_GIGABYTE_880GM,
  };
  
  static const struct alc_fixup alc882_fixups[] = {
                .type = ALC_FIXUP_SKU,
                .v.sku = ALC_FIXUP_SKU_IGNORE,
        },
-       [PINFIX_GIGABYTE_880GM] = {
-               .type = ALC_FIXUP_PINS,
-               .v.pins = (const struct alc_pincfg[]) {
-                       { 0x14, 0x1114410 }, /* set as speaker */
-                       { }
-               }
-       },
  };
  
  static struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
        SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
        SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
-       SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte", PINFIX_GIGABYTE_880GM),
        {}
  };
  
@@@ -11081,11 -10842,6 +11074,11 @@@ static void alc882_auto_init_input_src(
                const struct hda_input_mux *imux;
                int conns, mute, idx, item;
  
 +              /* mute ADC */
 +              snd_hda_codec_write(codec, spec->adc_nids[c], 0,
 +                                  AC_VERB_SET_AMP_GAIN_MUTE,
 +                                  AMP_IN_MUTE(0));
 +
                conns = snd_hda_get_connections(codec, nid, conn_list,
                                                ARRAY_SIZE(conn_list));
                if (conns < 0)
@@@ -11178,9 -10934,6 +11171,9 @@@ static int alc882_parse_auto_config(str
        err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
        if (err < 0)
                return err;
 +      err = alc_auto_add_multi_channel_mode(codec);
 +      if (err < 0)
 +              return err;
        err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
@@@ -11410,30 -11163,71 +11403,30 @@@ static struct snd_kcontrol_new alc262_b
  };
  
  /* update HP, line and mono-out pins according to the master switch */
 -static void alc262_hp_master_update(struct hda_codec *codec)
 -{
 -      struct alc_spec *spec = codec->spec;
 -      int val = spec->master_sw;
 -
 -      /* HP & line-out */
 -      snd_hda_codec_write_cache(codec, 0x1b, 0,
 -                                AC_VERB_SET_PIN_WIDGET_CONTROL,
 -                                val ? PIN_HP : 0);
 -      snd_hda_codec_write_cache(codec, 0x15, 0,
 -                                AC_VERB_SET_PIN_WIDGET_CONTROL,
 -                                val ? PIN_HP : 0);
 -      /* mono (speaker) depending on the HP jack sense */
 -      val = val && !spec->jack_present;
 -      snd_hda_codec_write_cache(codec, 0x16, 0,
 -                                AC_VERB_SET_PIN_WIDGET_CONTROL,
 -                                val ? PIN_OUT : 0);
 -}
 +#define alc262_hp_master_update               alc260_hp_master_update
  
 -static void alc262_hp_bpc_automute(struct hda_codec *codec)
 +static void alc262_hp_bpc_setup(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
  
 -      spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
 -      alc262_hp_master_update(codec);
 -}
 -
 -static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
 -{
 -      if ((res >> 26) != ALC880_HP_EVENT)
 -              return;
 -      alc262_hp_bpc_automute(codec);
 +      spec->autocfg.hp_pins[0] = 0x1b;
 +      spec->autocfg.speaker_pins[0] = 0x16;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_PIN;
  }
  
 -static void alc262_hp_wildwest_automute(struct hda_codec *codec)
 +static void alc262_hp_wildwest_setup(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
  
 -      spec->jack_present = snd_hda_jack_detect(codec, 0x15);
 -      alc262_hp_master_update(codec);
 -}
 -
 -static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
 -                                         unsigned int res)
 -{
 -      if ((res >> 26) != ALC880_HP_EVENT)
 -              return;
 -      alc262_hp_wildwest_automute(codec);
 +      spec->autocfg.hp_pins[0] = 0x15;
 +      spec->autocfg.speaker_pins[0] = 0x16;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_PIN;
  }
  
  #define alc262_hp_master_sw_get               alc260_hp_master_sw_get
 -
 -static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
 -                                 struct snd_ctl_elem_value *ucontrol)
 -{
 -      struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 -      struct alc_spec *spec = codec->spec;
 -      int val = !!*ucontrol->value.integer.value;
 -
 -      if (val == spec->master_sw)
 -              return 0;
 -      spec->master_sw = val;
 -      alc262_hp_master_update(codec);
 -      return 1;
 -}
 +#define alc262_hp_master_sw_put               alc260_hp_master_sw_put
  
  #define ALC262_HP_MASTER_SWITCH                                       \
        {                                                       \
@@@ -11508,8 -11302,6 +11501,8 @@@ static void alc262_hp_t5735_setup(struc
  
        spec->autocfg.hp_pins[0] = 0x15;
        spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_PIN;
  }
  
  static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
@@@ -11563,9 -11355,44 +11556,9 @@@ static struct hda_input_mux alc262_hp_r
  };
  
  /* bind hp and internal speaker mute (with plug check) as master switch */
 -static void alc262_hippo_master_update(struct hda_codec *codec)
 -{
 -      struct alc_spec *spec = codec->spec;
 -      hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
 -      hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
 -      hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
 -      unsigned int mute;
 -
 -      /* HP */
 -      mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
 -      snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, mute);
 -      /* mute internal speaker per jack sense */
 -      if (spec->jack_present)
 -              mute = HDA_AMP_MUTE;
 -      if (line_nid)
 -              snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
 -                                       HDA_AMP_MUTE, mute);
 -      if (speaker_nid && speaker_nid != line_nid)
 -              snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
 -                                       HDA_AMP_MUTE, mute);
 -}
 -
 +#define alc262_hippo_master_update    alc262_hp_master_update
  #define alc262_hippo_master_sw_get    alc262_hp_master_sw_get
 -
 -static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
 -                                    struct snd_ctl_elem_value *ucontrol)
 -{
 -      struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 -      struct alc_spec *spec = codec->spec;
 -      int val = !!*ucontrol->value.integer.value;
 -
 -      if (val == spec->master_sw)
 -              return 0;
 -      spec->master_sw = val;
 -      alc262_hippo_master_update(codec);
 -      return 1;
 -}
 +#define alc262_hippo_master_sw_put    alc262_hp_master_sw_put
  
  #define ALC262_HIPPO_MASTER_SWITCH                            \
        {                                                       \
@@@ -11616,14 -11443,28 +11609,14 @@@ static struct snd_kcontrol_new alc262_h
  };
  
  /* mute/unmute internal speaker according to the hp jack and mute state */
 -static void alc262_hippo_automute(struct hda_codec *codec)
 -{
 -      struct alc_spec *spec = codec->spec;
 -      hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
 -
 -      spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
 -      alc262_hippo_master_update(codec);
 -}
 -
 -static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
 -{
 -      if ((res >> 26) != ALC880_HP_EVENT)
 -              return;
 -      alc262_hippo_automute(codec);
 -}
 -
  static void alc262_hippo_setup(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
  
        spec->autocfg.hp_pins[0] = 0x15;
        spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc262_hippo1_setup(struct hda_codec *codec)
  
        spec->autocfg.hp_pins[0] = 0x1b;
        spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  
@@@ -11696,8 -11535,6 +11689,8 @@@ static void alc262_tyan_setup(struct hd
  
        spec->autocfg.hp_pins[0] = 0x1b;
        spec->autocfg.speaker_pins[0] = 0x15;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  
@@@ -11841,8 -11678,6 +11834,8 @@@ static void alc262_toshiba_s06_setup(st
        spec->int_mic.pin = 0x12;
        spec->int_mic.mux_idx = 9;
        spec->auto_mic = 1;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_PIN;
  }
  
  /*
@@@ -11939,15 -11774,40 +11932,15 @@@ static struct hda_input_mux alc262_HP_D
        },
  };
  
 -/* mute/unmute internal speaker according to the hp jacks and mute state */
 -static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
 +static void alc262_fujitsu_setup(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 -      unsigned int mute;
 -
 -      if (force || !spec->sense_updated) {
 -              spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
 -                                   snd_hda_jack_detect(codec, 0x1b);
 -              spec->sense_updated = 1;
 -      }
 -      /* unmute internal speaker only if both HPs are unplugged and
 -       * master switch is on
 -       */
 -      if (spec->jack_present)
 -              mute = HDA_AMP_MUTE;
 -      else
 -              mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
 -      snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, mute);
 -}
 -
 -/* unsolicited event for HP jack sensing */
 -static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
 -                                     unsigned int res)
 -{
 -      if ((res >> 26) != ALC_HP_EVENT)
 -              return;
 -      alc262_fujitsu_automute(codec, 1);
 -}
  
 -static void alc262_fujitsu_init_hook(struct hda_codec *codec)
 -{
 -      alc262_fujitsu_automute(codec, 1);
 +      spec->autocfg.hp_pins[0] = 0x14;
 +      spec->autocfg.hp_pins[1] = 0x1b;
 +      spec->autocfg.speaker_pins[0] = 0x15;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  /* bind volumes of both NID 0x0c and 0x0d */
@@@ -11960,15 -11820,78 +11953,15 @@@ static struct hda_bind_ctls alc262_fuji
        },
  };
  
 -/* mute/unmute internal speaker according to the hp jack and mute state */
 -static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
 -{
 -      struct alc_spec *spec = codec->spec;
 -      unsigned int mute;
 -
 -      if (force || !spec->sense_updated) {
 -              spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
 -              spec->sense_updated = 1;
 -      }
 -      if (spec->jack_present) {
 -              /* mute internal speaker */
 -              snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
 -                                       HDA_AMP_MUTE, HDA_AMP_MUTE);
 -              snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
 -                                       HDA_AMP_MUTE, HDA_AMP_MUTE);
 -      } else {
 -              /* unmute internal speaker if necessary */
 -              mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
 -              snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
 -                                       HDA_AMP_MUTE, mute);
 -              snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
 -                                       HDA_AMP_MUTE, mute);
 -      }
 -}
 -
 -/* unsolicited event for HP jack sensing */
 -static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
 -                                     unsigned int res)
 -{
 -      if ((res >> 26) != ALC_HP_EVENT)
 -              return;
 -      alc262_lenovo_3000_automute(codec, 1);
 -}
 -
 -static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
 -                                int dir, int idx, long *valp)
 -{
 -      int i, change = 0;
 -
 -      for (i = 0; i < 2; i++, valp++)
 -              change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
 -                                                 HDA_AMP_MUTE,
 -                                                 *valp ? 0 : HDA_AMP_MUTE);
 -      return change;
 -}
 -
 -/* bind hp and internal speaker mute (with plug check) */
 -static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
 -                                       struct snd_ctl_elem_value *ucontrol)
 -{
 -      struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 -      long *valp = ucontrol->value.integer.value;
 -      int change;
 -
 -      change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
 -      change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
 -      if (change)
 -              alc262_fujitsu_automute(codec, 0);
 -      return change;
 -}
 -
  static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
        HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
 -              .subdevice = HDA_SUBDEV_AMP_FLAG,
 -              .info = snd_hda_mixer_amp_switch_info,
 -              .get = snd_hda_mixer_amp_switch_get,
 -              .put = alc262_fujitsu_master_sw_put,
 -              .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
 +              .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
 +              .info = snd_ctl_boolean_mono_info,
 +              .get = alc262_hp_master_sw_get,
 +              .put = alc262_hp_master_sw_put,
        },
        {
                .iface = NID_MAPPING,
        { } /* end */
  };
  
 -/* bind hp and internal speaker mute (with plug check) */
 -static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
 -                                       struct snd_ctl_elem_value *ucontrol)
 +static void alc262_lenovo_3000_setup(struct hda_codec *codec)
  {
 -      struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 -      long *valp = ucontrol->value.integer.value;
 -      int change;
 +      struct alc_spec *spec = codec->spec;
  
 -      change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
 -      if (change)
 -              alc262_lenovo_3000_automute(codec, 0);
 -      return change;
 +      spec->autocfg.hp_pins[0] = 0x1b;
 +      spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->autocfg.speaker_pins[1] = 0x16;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
 -              .subdevice = HDA_SUBDEV_AMP_FLAG,
 -              .info = snd_hda_mixer_amp_switch_info,
 -              .get = snd_hda_mixer_amp_switch_get,
 -              .put = alc262_lenovo_3000_master_sw_put,
 -              .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
 +              .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
 +              .info = snd_ctl_boolean_mono_info,
 +              .get = alc262_hp_master_sw_get,
 +              .put = alc262_hp_master_sw_put,
        },
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
@@@ -12223,7 -12150,7 +12216,7 @@@ static int alc262_auto_create_multi_out
        spec->multiout.dac_nids = spec->private_dac_nids;
        spec->multiout.dac_nids[0] = 2;
  
 -      pfx = alc_get_line_out_pfx(cfg, true);
 +      pfx = alc_get_line_out_pfx(spec, true);
        if (!pfx)
                pfx = "Front";
        for (i = 0; i < 2; i++) {
@@@ -12755,9 -12682,9 +12748,9 @@@ static struct alc_config_preset alc262_
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
 -              .unsol_event = alc262_hippo_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc262_hippo_setup,
 -              .init_hook = alc262_hippo_automute,
 +              .init_hook = alc_inithook,
        },
        [ALC262_HIPPO_1] = {
                .mixers = { alc262_hippo1_mixer },
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
 -              .unsol_event = alc262_hippo_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc262_hippo1_setup,
 -              .init_hook = alc262_hippo_automute,
 +              .init_hook = alc_inithook,
        },
        [ALC262_FUJITSU] = {
                .mixers = { alc262_fujitsu_mixer },
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_fujitsu_capture_source,
 -              .unsol_event = alc262_fujitsu_unsol_event,
 -              .init_hook = alc262_fujitsu_init_hook,
 +              .unsol_event = alc_sku_unsol_event,
 +              .setup = alc262_fujitsu_setup,
 +              .init_hook = alc_inithook,
        },
        [ALC262_HP_BPC] = {
                .mixers = { alc262_HP_BPC_mixer },
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_HP_capture_source,
 -              .unsol_event = alc262_hp_bpc_unsol_event,
 -              .init_hook = alc262_hp_bpc_automute,
 +              .unsol_event = alc_sku_unsol_event,
 +              .setup = alc262_hp_bpc_setup,
 +              .init_hook = alc_inithook,
        },
        [ALC262_HP_BPC_D7000_WF] = {
                .mixers = { alc262_HP_BPC_WildWest_mixer },
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_HP_D7000_capture_source,
 -              .unsol_event = alc262_hp_wildwest_unsol_event,
 -              .init_hook = alc262_hp_wildwest_automute,
 +              .unsol_event = alc_sku_unsol_event,
 +              .setup = alc262_hp_wildwest_setup,
 +              .init_hook = alc_inithook,
        },
        [ALC262_HP_BPC_D7000_WL] = {
                .mixers = { alc262_HP_BPC_WildWest_mixer,
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_HP_D7000_capture_source,
 -              .unsol_event = alc262_hp_wildwest_unsol_event,
 -              .init_hook = alc262_hp_wildwest_automute,
 +              .unsol_event = alc_sku_unsol_event,
 +              .setup = alc262_hp_wildwest_setup,
 +              .init_hook = alc_inithook,
        },
        [ALC262_HP_TC_T5735] = {
                .mixers = { alc262_hp_t5735_mixer },
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
 -              .unsol_event = alc262_hippo_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc262_hippo_setup,
 -              .init_hook = alc262_hippo_automute,
 +              .init_hook = alc_inithook,
        },
        [ALC262_BENQ_T31] = {
                .mixers = { alc262_benq_t31_mixer },
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
 -              .unsol_event = alc262_hippo_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc262_hippo_setup,
 -              .init_hook = alc262_hippo_automute,
 +              .init_hook = alc_inithook,
        },
        [ALC262_ULTRA] = {
                .mixers = { alc262_ultra_mixer },
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_fujitsu_capture_source,
 -              .unsol_event = alc262_lenovo_3000_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
 +              .setup = alc262_lenovo_3000_setup,
 +              .init_hook = alc_inithook,
        },
        [ALC262_NEC] = {
                .mixers = { alc262_nec_mixer },
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
 -              .unsol_event = alc262_hippo_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc262_hippo_setup,
 -              .init_hook = alc262_hippo_automute,
 +              .init_hook = alc_inithook,
        },
        [ALC262_TYAN] = {
                .mixers = { alc262_tyan_mixer },
                .num_channel_mode = ARRAY_SIZE(alc262_modes),
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc262_tyan_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
  };
  
@@@ -13090,7 -13011,6 +13083,7 @@@ static int patch_alc262(struct hda_code
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC262_AUTO)
                spec->init_hook = alc262_auto_init;
 +      spec->shutup = alc_eapd_shutup;
  
        alc_init_jacks(codec);
  #ifdef CONFIG_SND_HDA_POWER_SAVE
@@@ -13186,18 -13106,38 +13179,18 @@@ static struct hda_bind_ctls alc268_acer
        },
  };
  
 -/* mute/unmute internal speaker according to the hp jack and mute state */
 -static void alc268_acer_automute(struct hda_codec *codec, int force)
 +static void alc268_acer_setup(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 -      unsigned int mute;
  
 -      if (force || !spec->sense_updated) {
 -              spec->jack_present = snd_hda_jack_detect(codec, 0x14);
 -              spec->sense_updated = 1;
 -      }
 -      if (spec->jack_present)
 -              mute = HDA_AMP_MUTE; /* mute internal speaker */
 -      else /* unmute internal speaker if necessary */
 -              mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
 -      snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, mute);
 +      spec->autocfg.hp_pins[0] = 0x14;
 +      spec->autocfg.speaker_pins[0] = 0x15;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
 -
 -/* bind hp and internal speaker mute (with plug check) */
 -static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
 -                                   struct snd_ctl_elem_value *ucontrol)
 -{
 -      struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 -      long *valp = ucontrol->value.integer.value;
 -      int change;
 -
 -      change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
 -      if (change)
 -              alc268_acer_automute(codec, 0);
 -      return change;
 -}
 +#define alc268_acer_master_sw_get     alc262_hp_master_sw_get
 +#define alc268_acer_master_sw_put     alc262_hp_master_sw_put
  
  static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
        /* output mixer control */
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
 -              .subdevice = HDA_SUBDEV_AMP_FLAG,
 -              .info = snd_hda_mixer_amp_switch_info,
 -              .get = snd_hda_mixer_amp_switch_get,
 +              .subdevice = HDA_SUBDEV_NID_FLAG | 0x15,
 +              .info = snd_ctl_boolean_mono_info,
 +              .get = alc268_acer_master_sw_get,
                .put = alc268_acer_master_sw_put,
 -              .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
        },
        HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
        { }
@@@ -13220,10 -13161,11 +13213,10 @@@ static struct snd_kcontrol_new alc268_a
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
 -              .subdevice = HDA_SUBDEV_AMP_FLAG,
 -              .info = snd_hda_mixer_amp_switch_info,
 -              .get = snd_hda_mixer_amp_switch_get,
 +              .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
 +              .info = snd_ctl_boolean_mono_info,
 +              .get = alc268_acer_master_sw_get,
                .put = alc268_acer_master_sw_put,
 -              .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
        },
        HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
@@@ -13237,10 -13179,11 +13230,10 @@@ static struct snd_kcontrol_new alc268_a
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Master Playback Switch",
 -              .subdevice = HDA_SUBDEV_AMP_FLAG,
 -              .info = snd_hda_mixer_amp_switch_info,
 -              .get = snd_hda_mixer_amp_switch_get,
 +              .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
 +              .info = snd_ctl_boolean_mono_info,
 +              .get = alc268_acer_master_sw_get,
                .put = alc268_acer_master_sw_put,
 -              .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
        },
        HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
@@@ -13269,16 -13212,53 +13262,16 @@@ static struct hda_verb alc268_acer_verb
  };
  
  /* unsolicited event for HP jack sensing */
 -#define alc268_toshiba_unsol_event    alc262_hippo_unsol_event
  #define alc268_toshiba_setup          alc262_hippo_setup
 -#define alc268_toshiba_automute               alc262_hippo_automute
 -
 -static void alc268_acer_unsol_event(struct hda_codec *codec,
 -                                     unsigned int res)
 -{
 -      if ((res >> 26) != ALC880_HP_EVENT)
 -              return;
 -      alc268_acer_automute(codec, 1);
 -}
 -
 -static void alc268_acer_init_hook(struct hda_codec *codec)
 -{
 -      alc268_acer_automute(codec, 1);
 -}
 -
 -/* toggle speaker-output according to the hp-jack state */
 -static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
 -{
 -      unsigned int present;
 -      unsigned char bits;
 -
 -      present = snd_hda_jack_detect(codec, 0x15);
 -      bits = present ? HDA_AMP_MUTE : 0;
 -      snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
 -                               HDA_AMP_MUTE, bits);
 -}
 -
 -static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
 -                                  unsigned int res)
 -{
 -      switch (res >> 26) {
 -      case ALC880_HP_EVENT:
 -              alc268_aspire_one_speaker_automute(codec);
 -              break;
 -      case ALC880_MIC_EVENT:
 -              alc_mic_automute(codec);
 -              break;
 -      }
 -}
  
  static void alc268_acer_lc_setup(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 +      spec->autocfg.hp_pins[0] = 0x15;
 +      spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute_mixer_nid[0] = 0x0f;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_MIXER;
        spec->ext_mic.pin = 0x18;
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.pin = 0x12;
        spec->auto_mic = 1;
  }
  
 -static void alc268_acer_lc_init_hook(struct hda_codec *codec)
 -{
 -      alc268_aspire_one_speaker_automute(codec);
 -      alc_mic_automute(codec);
 -}
 -
  static struct snd_kcontrol_new alc268_dell_mixer[] = {
        /* output mixer control */
        HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
@@@ -13317,8 -13303,6 +13310,8 @@@ static void alc268_dell_setup(struct hd
        spec->int_mic.pin = 0x19;
        spec->int_mic.mux_idx = 1;
        spec->auto_mic = 1;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_PIN;
  }
  
  static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
@@@ -13349,8 -13333,6 +13342,8 @@@ static void alc267_quanta_il1_setup(str
        spec->int_mic.pin = 0x19;
        spec->int_mic.mux_idx = 1;
        spec->auto_mic = 1;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_PIN;
  }
  
  /*
@@@ -13892,9 -13874,9 +13885,9 @@@ static struct alc_config_preset alc268_
                .num_channel_mode = ARRAY_SIZE(alc268_modes),
                .channel_mode = alc268_modes,
                .input_mux = &alc268_capture_source,
 -              .unsol_event = alc268_toshiba_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc268_toshiba_setup,
 -              .init_hook = alc268_toshiba_automute,
 +              .init_hook = alc_inithook,
        },
        [ALC268_ACER] = {
                .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
                .num_channel_mode = ARRAY_SIZE(alc268_modes),
                .channel_mode = alc268_modes,
                .input_mux = &alc268_acer_capture_source,
 -              .unsol_event = alc268_acer_unsol_event,
 -              .init_hook = alc268_acer_init_hook,
 +              .unsol_event = alc_sku_unsol_event,
 +              .setup = alc268_acer_setup,
 +              .init_hook = alc_inithook,
        },
        [ALC268_ACER_DMIC] = {
                .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
                .num_channel_mode = ARRAY_SIZE(alc268_modes),
                .channel_mode = alc268_modes,
                .input_mux = &alc268_acer_dmic_capture_source,
 -              .unsol_event = alc268_acer_unsol_event,
 -              .init_hook = alc268_acer_init_hook,
 +              .unsol_event = alc_sku_unsol_event,
 +              .setup = alc268_acer_setup,
 +              .init_hook = alc_inithook,
        },
        [ALC268_ACER_ASPIRE_ONE] = {
                .mixers = { alc268_acer_aspire_one_mixer,
                .hp_nid = 0x03,
                .num_channel_mode = ARRAY_SIZE(alc268_modes),
                .channel_mode = alc268_modes,
 -              .unsol_event = alc268_acer_lc_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc268_acer_lc_setup,
 -              .init_hook = alc268_acer_lc_init_hook,
 +              .init_hook = alc_inithook,
        },
        [ALC268_DELL] = {
                .mixers = { alc268_dell_mixer, alc268_beep_mixer,
                .num_channel_mode = ARRAY_SIZE(alc268_modes),
                .channel_mode = alc268_modes,
                .input_mux = &alc268_capture_source,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc268_toshiba_setup,
 -              .init_hook = alc268_toshiba_automute,
 +              .init_hook = alc_inithook,
        },
  #ifdef CONFIG_SND_DEBUG
        [ALC268_TEST] = {
@@@ -14106,7 -14085,6 +14099,7 @@@ static int patch_alc268(struct hda_code
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC268_AUTO)
                spec->init_hook = alc268_auto_init;
 +      spec->shutup = alc_eapd_shutup;
  
        alc_init_jacks(codec);
  
@@@ -14289,7 -14267,15 +14282,7 @@@ static struct hda_verb alc269_lifebook_
  /* toggle speaker-output according to the hp-jack state */
  static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
  {
 -      unsigned int present;
 -      unsigned char bits;
 -
 -      present = snd_hda_jack_detect(codec, 0x15);
 -      bits = present ? HDA_AMP_MUTE : 0;
 -      snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
 -                               HDA_AMP_MUTE, bits);
 +      alc_hp_automute(codec);
  
        snd_hda_codec_write(codec, 0x20, 0,
                        AC_VERB_SET_COEF_INDEX, 0x0c);
                        AC_VERB_SET_PROC_COEF, 0x480);
  }
  
 -/* toggle speaker-output according to the hp-jacks state */
 -static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
 -{
 -      unsigned int present;
 -      unsigned char bits;
 -
 -      /* Check laptop headphone socket */
 -      present = snd_hda_jack_detect(codec, 0x15);
 -
 -      /* Check port replicator headphone socket */
 -      present |= snd_hda_jack_detect(codec, 0x1a);
 -
 -      bits = present ? HDA_AMP_MUTE : 0;
 -      snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
 -                               HDA_AMP_MUTE, bits);
 -
 -      snd_hda_codec_write(codec, 0x20, 0,
 -                      AC_VERB_SET_COEF_INDEX, 0x0c);
 -      snd_hda_codec_write(codec, 0x20, 0,
 -                      AC_VERB_SET_PROC_COEF, 0x680);
 -
 -      snd_hda_codec_write(codec, 0x20, 0,
 -                      AC_VERB_SET_COEF_INDEX, 0x0c);
 -      snd_hda_codec_write(codec, 0x20, 0,
 -                      AC_VERB_SET_PROC_COEF, 0x480);
 -}
 +#define alc269_lifebook_speaker_automute \
 +      alc269_quanta_fl1_speaker_automute
  
  static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
  {
@@@ -14352,9 -14364,6 +14345,9 @@@ static void alc269_quanta_fl1_setup(str
        struct alc_spec *spec = codec->spec;
        spec->autocfg.hp_pins[0] = 0x15;
        spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute_mixer_nid[0] = 0x0c;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_MIXER;
        spec->ext_mic.pin = 0x18;
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.pin = 0x19;
@@@ -14368,17 -14377,6 +14361,17 @@@ static void alc269_quanta_fl1_init_hook
        alc_mic_automute(codec);
  }
  
 +static void alc269_lifebook_setup(struct hda_codec *codec)
 +{
 +      struct alc_spec *spec = codec->spec;
 +      spec->autocfg.hp_pins[0] = 0x15;
 +      spec->autocfg.hp_pins[1] = 0x1a;
 +      spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute_mixer_nid[0] = 0x0c;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_MIXER;
 +}
 +
  static void alc269_lifebook_init_hook(struct hda_codec *codec)
  {
        alc269_lifebook_speaker_automute(codec);
@@@ -14442,14 -14440,42 +14435,14 @@@ static struct hda_verb alc271_acer_dmic
        { }
  };
  
 -/* toggle speaker-output according to the hp-jack state */
 -static void alc269_speaker_automute(struct hda_codec *codec)
 -{
 -      struct alc_spec *spec = codec->spec;
 -      unsigned int nid = spec->autocfg.hp_pins[0];
 -      unsigned int present;
 -      unsigned char bits;
 -
 -      present = snd_hda_jack_detect(codec, nid);
 -      bits = present ? HDA_AMP_MUTE : 0;
 -      snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_input_jack_report(codec, nid);
 -}
 -
 -/* unsolicited event for HP jack sensing */
 -static void alc269_laptop_unsol_event(struct hda_codec *codec,
 -                                   unsigned int res)
 -{
 -      switch (res >> 26) {
 -      case ALC880_HP_EVENT:
 -              alc269_speaker_automute(codec);
 -              break;
 -      case ALC880_MIC_EVENT:
 -              alc_mic_automute(codec);
 -              break;
 -      }
 -}
 -
  static void alc269_laptop_amic_setup(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
        spec->autocfg.hp_pins[0] = 0x15;
        spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute_mixer_nid[0] = 0x0c;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_MIXER;
        spec->ext_mic.pin = 0x18;
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.pin = 0x19;
@@@ -14462,9 -14488,6 +14455,9 @@@ static void alc269_laptop_dmic_setup(st
        struct alc_spec *spec = codec->spec;
        spec->autocfg.hp_pins[0] = 0x15;
        spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute_mixer_nid[0] = 0x0c;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_MIXER;
        spec->ext_mic.pin = 0x18;
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.pin = 0x12;
@@@ -14477,9 -14500,6 +14470,9 @@@ static void alc269vb_laptop_amic_setup(
        struct alc_spec *spec = codec->spec;
        spec->autocfg.hp_pins[0] = 0x21;
        spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute_mixer_nid[0] = 0x0c;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_MIXER;
        spec->ext_mic.pin = 0x18;
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.pin = 0x19;
@@@ -14492,9 -14512,6 +14485,9 @@@ static void alc269vb_laptop_dmic_setup(
        struct alc_spec *spec = codec->spec;
        spec->autocfg.hp_pins[0] = 0x21;
        spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute_mixer_nid[0] = 0x0c;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_MIXER;
        spec->ext_mic.pin = 0x18;
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.pin = 0x12;
        spec->auto_mic = 1;
  }
  
 -static void alc269_laptop_inithook(struct hda_codec *codec)
 -{
 -      alc269_speaker_automute(codec);
 -      alc_mic_automute(codec);
 -}
 -
  /*
   * generic initialization of ADC, input mixers and output mixers
   */
@@@ -14773,6 -14796,7 +14766,6 @@@ static void alc269_auto_init(struct hda
                alc_inithook(codec);
  }
  
 -#ifdef SND_HDA_NEEDS_RESUME
  static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
  {
        int val = alc_read_coef_idx(codec, 0x04);
        alc_write_coef_idx(codec, 0x04, val);
  }
  
 -#ifdef CONFIG_SND_HDA_POWER_SAVE
 -static int alc269_suspend(struct hda_codec *codec, pm_message_t state)
 +static void alc269_shutup(struct hda_codec *codec)
  {
 -      struct alc_spec *spec = codec->spec;
 -
        if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
                alc269_toggle_power_output(codec, 0);
        if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
                alc269_toggle_power_output(codec, 0);
                msleep(150);
        }
 -
 -      alc_shutup(codec);
 -      if (spec && spec->power_hook)
 -              spec->power_hook(codec);
 -      return 0;
  }
 -#endif /* CONFIG_SND_HDA_POWER_SAVE */
  
 +#ifdef SND_HDA_NEEDS_RESUME
  static int alc269_resume(struct hda_codec *codec)
  {
        if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
@@@ -15038,9 -15070,9 +15031,9 @@@ static struct alc_config_preset alc269_
                .hp_nid = 0x03,
                .num_channel_mode = ARRAY_SIZE(alc269_modes),
                .channel_mode = alc269_modes,
 -              .unsol_event = alc269_laptop_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc269_laptop_amic_setup,
 -              .init_hook = alc269_laptop_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC269_DMIC] = {
                .mixers = { alc269_laptop_mixer },
                .hp_nid = 0x03,
                .num_channel_mode = ARRAY_SIZE(alc269_modes),
                .channel_mode = alc269_modes,
 -              .unsol_event = alc269_laptop_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc269_laptop_dmic_setup,
 -              .init_hook = alc269_laptop_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC269VB_AMIC] = {
                .mixers = { alc269vb_laptop_mixer },
                .hp_nid = 0x03,
                .num_channel_mode = ARRAY_SIZE(alc269_modes),
                .channel_mode = alc269_modes,
 -              .unsol_event = alc269_laptop_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc269vb_laptop_amic_setup,
 -              .init_hook = alc269_laptop_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC269VB_DMIC] = {
                .mixers = { alc269vb_laptop_mixer },
                .hp_nid = 0x03,
                .num_channel_mode = ARRAY_SIZE(alc269_modes),
                .channel_mode = alc269_modes,
 -              .unsol_event = alc269_laptop_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc269vb_laptop_dmic_setup,
 -              .init_hook = alc269_laptop_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC269_FUJITSU] = {
                .mixers = { alc269_fujitsu_mixer },
                .hp_nid = 0x03,
                .num_channel_mode = ARRAY_SIZE(alc269_modes),
                .channel_mode = alc269_modes,
 -              .unsol_event = alc269_laptop_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc269_laptop_dmic_setup,
 -              .init_hook = alc269_laptop_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC269_LIFEBOOK] = {
                .mixers = { alc269_lifebook_mixer },
                .channel_mode = alc269_modes,
                .input_mux = &alc269_capture_source,
                .unsol_event = alc269_lifebook_unsol_event,
 +              .setup = alc269_lifebook_setup,
                .init_hook = alc269_lifebook_init_hook,
        },
        [ALC271_ACER] = {
@@@ -15282,12 -15313,14 +15275,12 @@@ static int patch_alc269(struct hda_code
        spec->vmaster_nid = 0x02;
  
        codec->patch_ops = alc_patch_ops;
 -#ifdef CONFIG_SND_HDA_POWER_SAVE
 -      codec->patch_ops.suspend = alc269_suspend;
 -#endif
  #ifdef SND_HDA_NEEDS_RESUME
        codec->patch_ops.resume = alc269_resume;
  #endif
        if (board_config == ALC269_AUTO)
                spec->init_hook = alc269_auto_init;
 +      spec->shutup = alc269_shutup;
  
        alc_init_jacks(codec);
  #ifdef CONFIG_SND_HDA_POWER_SAVE
@@@ -15981,15 -16014,11 +15974,15 @@@ static int alc861_auto_create_multi_out
        static const char * const chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
 -      const char *pfx = alc_get_line_out_pfx(cfg, true);
 +      const char *pfx = alc_get_line_out_pfx(spec, true);
        hda_nid_t nid;
 -      int i, err;
 +      int i, err, noutputs;
  
 -      for (i = 0; i < cfg->line_outs; i++) {
 +      noutputs = cfg->line_outs;
 +      if (spec->multi_ios > 0)
 +              noutputs += spec->multi_ios;
 +
 +      for (i = 0; i < noutputs; i++) {
                nid = spec->multiout.dac_nids[i];
                if (!nid)
                        continue;
@@@ -16134,9 -16163,6 +16127,9 @@@ static int alc861_parse_auto_config(str
        err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
        if (err < 0)
                return err;
 +      err = alc_auto_add_multi_channel_mode(codec);
 +      if (err < 0)
 +              return err;
        err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
@@@ -16809,13 -16835,11 +16802,13 @@@ static void alc861vd_lenovo_setup(struc
        struct alc_spec *spec = codec->spec;
        spec->autocfg.hp_pins[0] = 0x1b;
        spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
  {
 -      alc_automute_amp(codec);
 +      alc_hp_automute(codec);
        alc88x_simple_mic_automute(codec);
  }
  
@@@ -16827,7 -16851,7 +16820,7 @@@ static void alc861vd_lenovo_unsol_event
                alc88x_simple_mic_automute(codec);
                break;
        default:
 -              alc_automute_amp_unsol_event(codec, res);
 +              alc_sku_unsol_event(codec, res);
                break;
        }
  }
@@@ -16884,8 -16908,6 +16877,8 @@@ static void alc861vd_dallas_setup(struc
  
        spec->autocfg.hp_pins[0] = 0x15;
        spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  #ifdef CONFIG_SND_HDA_POWER_SAVE
@@@ -17010,9 -17032,9 +17003,9 @@@ static struct alc_config_preset alc861v
                .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
                .channel_mode = alc861vd_3stack_2ch_modes,
                .input_mux = &alc861vd_dallas_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc861vd_dallas_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC861VD_HP] = {
                .mixers = { alc861vd_hp_mixer },
                .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
                .channel_mode = alc861vd_3stack_2ch_modes,
                .input_mux = &alc861vd_hp_capture_source,
 -              .unsol_event = alc_automute_amp_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc861vd_dallas_setup,
 -              .init_hook = alc_automute_amp,
 +              .init_hook = alc_hp_automute,
        },
        [ALC660VD_ASUS_V1S] = {
                .mixers = { alc861vd_lenovo_mixer },
@@@ -17124,15 -17146,11 +17117,15 @@@ static int alc861vd_auto_create_multi_o
        static const char * const chname[4] = {
                "Front", "Surround", "CLFE", "Side"
        };
 -      const char *pfx = alc_get_line_out_pfx(cfg, true);
 +      const char *pfx = alc_get_line_out_pfx(spec, true);
        hda_nid_t nid_v, nid_s;
 -      int i, err;
 +      int i, err, noutputs;
  
 -      for (i = 0; i < cfg->line_outs; i++) {
 +      noutputs = cfg->line_outs;
 +      if (spec->multi_ios > 0)
 +              noutputs += spec->multi_ios;
 +
 +      for (i = 0; i < noutputs; i++) {
                if (!spec->multiout.dac_nids[i])
                        continue;
                nid_v = alc861vd_idx_to_mixer_vol(
@@@ -17257,9 -17275,6 +17250,9 @@@ static int alc861vd_parse_auto_config(s
        err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
        if (err < 0)
                return err;
 +      err = alc_auto_add_multi_channel_mode(codec);
 +      if (err < 0)
 +              return err;
        err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
@@@ -17411,7 -17426,6 +17404,7 @@@ static int patch_alc861vd(struct hda_co
  
        if (board_config == ALC861VD_AUTO)
                spec->init_hook = alc861vd_auto_init;
 +      spec->shutup = alc_eapd_shutup;
  #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc861vd_loopbacks;
  #define ALC662_DIGOUT_NID     0x06
  #define ALC662_DIGIN_NID      0x0a
  
 -static hda_nid_t alc662_dac_nids[4] = {
 -      /* front, rear, clfe, rear_surr */
 +static hda_nid_t alc662_dac_nids[3] = {
 +      /* front, rear, clfe */
        0x02, 0x03, 0x04
  };
  
@@@ -17924,13 -17938,32 +17917,13 @@@ static struct hda_verb alc662_init_verb
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
  
        { }
  };
  
 -static struct hda_verb alc663_init_verbs[] = {
 -      {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 -      {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 -      {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 -      {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 -      {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 -      {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 -      { }
 -};
 -
 -static struct hda_verb alc272_init_verbs[] = {
 -      {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
 -      {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
 -      {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 -      {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 -      {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 -      {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
 -      {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 -      {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 +static struct hda_verb alc662_eapd_init_verbs[] = {
 +      /* always trun on EAPD */
 +      {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
 +      {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
        { }
  };
  
@@@ -18146,17 -18179,49 +18139,17 @@@ static struct snd_kcontrol_new alc272_a
        { } /* end */
  };
  
 -static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
 +static void alc662_lenovo_101e_setup(struct hda_codec *codec)
  {
 -      unsigned int present;
 -      unsigned char bits;
 -
 -      present = snd_hda_jack_detect(codec, 0x14);
 -      bits = present ? HDA_AMP_MUTE : 0;
 -
 -      snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -}
 -
 -static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
 -{
 -      unsigned int present;
 -      unsigned char bits;
 -
 -      present = snd_hda_jack_detect(codec, 0x1b);
 -      bits = present ? HDA_AMP_MUTE : 0;
 -
 -      snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -}
 -
 -static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
 -                                         unsigned int res)
 -{
 -      if ((res >> 26) == ALC880_HP_EVENT)
 -              alc662_lenovo_101e_all_automute(codec);
 -      if ((res >> 26) == ALC880_FRONT_EVENT)
 -              alc662_lenovo_101e_ispeaker_automute(codec);
 -}
 +      struct alc_spec *spec = codec->spec;
  
 -/* unsolicited event for HP jack sensing */
 -static void alc662_eeepc_unsol_event(struct hda_codec *codec,
 -                                   unsigned int res)
 -{
 -      if ((res >> 26) == ALC880_MIC_EVENT)
 -              alc_mic_automute(codec);
 -      else
 -              alc262_hippo_unsol_event(codec, res);
 +      spec->autocfg.hp_pins[0] = 0x1b;
 +      spec->autocfg.line_out_pins[0] = 0x14;
 +      spec->autocfg.speaker_pins[0] = 0x15;
 +      spec->automute = 1;
 +      spec->detect_line = 1;
 +      spec->automute_lines = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc662_eeepc_setup(struct hda_codec *codec)
        spec->auto_mic = 1;
  }
  
 -static void alc662_eeepc_inithook(struct hda_codec *codec)
 -{
 -      alc262_hippo_automute(codec);
 -      alc_mic_automute(codec);
 -}
 -
  static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
  
        spec->autocfg.hp_pins[0] = 0x14;
        spec->autocfg.speaker_pins[0] = 0x1b;
 -}
 -
 -#define alc662_eeepc_ep20_inithook    alc262_hippo_master_update
 -
 -static void alc663_m51va_speaker_automute(struct hda_codec *codec)
 -{
 -      unsigned int present;
 -      unsigned char bits;
 -
 -      present = snd_hda_jack_detect(codec, 0x21);
 -      bits = present ? HDA_AMP_MUTE : 0;
 -      snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
 -                               HDA_AMP_MUTE, bits);
 -}
 -
 -static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
 -{
 -      unsigned int present;
 -      unsigned char bits;
 -
 -      present = snd_hda_jack_detect(codec, 0x21);
 -      bits = present ? HDA_AMP_MUTE : 0;
 -      snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
 -                               HDA_AMP_MUTE, bits);
 -}
 -
 -static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
 -{
 -      unsigned int present;
 -      unsigned char bits;
 -
 -      present = snd_hda_jack_detect(codec, 0x15);
 -      bits = present ? HDA_AMP_MUTE : 0;
 -      snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
 -                               HDA_AMP_MUTE, bits);
 -}
 -
 -static void alc662_f5z_speaker_automute(struct hda_codec *codec)
 -{
 -      unsigned int present;
 -      unsigned char bits;
 -
 -      present = snd_hda_jack_detect(codec, 0x1b);
 -      bits = present ? 0 : PIN_OUT;
 -      snd_hda_codec_write(codec, 0x14, 0,
 -                       AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
 -}
 -
 -static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
 -{
 -      unsigned int present1, present2;
 -
 -      present1 = snd_hda_jack_detect(codec, 0x21);
 -      present2 = snd_hda_jack_detect(codec, 0x15);
 -
 -      if (present1 || present2) {
 -              snd_hda_codec_write_cache(codec, 0x14, 0,
 -                      AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
 -      } else {
 -              snd_hda_codec_write_cache(codec, 0x14, 0,
 -                      AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
 -      }
 -}
 -
 -static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
 -{
 -      unsigned int present1, present2;
 -
 -      present1 = snd_hda_jack_detect(codec, 0x1b);
 -      present2 = snd_hda_jack_detect(codec, 0x15);
 -
 -      if (present1 || present2) {
 -              snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
 -                                       HDA_AMP_MUTE, HDA_AMP_MUTE);
 -              snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
 -                                       HDA_AMP_MUTE, HDA_AMP_MUTE);
 -      } else {
 -              snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
 -                                       HDA_AMP_MUTE, 0);
 -              snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
 -                                       HDA_AMP_MUTE, 0);
 -      }
 -}
 -
 -static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
 -{
 -      unsigned int present1, present2;
 -
 -      present1 = snd_hda_codec_read(codec, 0x1b, 0,
 -                      AC_VERB_GET_PIN_SENSE, 0)
 -                      & AC_PINSENSE_PRESENCE;
 -      present2 = snd_hda_codec_read(codec, 0x21, 0,
 -                      AC_VERB_GET_PIN_SENSE, 0)
 -                      & AC_PINSENSE_PRESENCE;
 -
 -      if (present1 || present2) {
 -              snd_hda_codec_write_cache(codec, 0x14, 0,
 -                      AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
 -              snd_hda_codec_write_cache(codec, 0x17, 0,
 -                      AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
 -      } else {
 -              snd_hda_codec_write_cache(codec, 0x14, 0,
 -                      AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
 -              snd_hda_codec_write_cache(codec, 0x17, 0,
 -                      AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
 -      }
 -}
 -
 -static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
 -{
 -      unsigned int present1, present2;
 -
 -      present1 = snd_hda_codec_read(codec, 0x21, 0,
 -                      AC_VERB_GET_PIN_SENSE, 0)
 -                      & AC_PINSENSE_PRESENCE;
 -      present2 = snd_hda_codec_read(codec, 0x15, 0,
 -                      AC_VERB_GET_PIN_SENSE, 0)
 -                      & AC_PINSENSE_PRESENCE;
 -
 -      if (present1 || present2) {
 -              snd_hda_codec_write_cache(codec, 0x14, 0,
 -                      AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
 -              snd_hda_codec_write_cache(codec, 0x17, 0,
 -                      AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
 -      } else {
 -              snd_hda_codec_write_cache(codec, 0x14, 0,
 -                      AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
 -              snd_hda_codec_write_cache(codec, 0x17, 0,
 -                      AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
 -      }
 -}
 -
 -static void alc663_m51va_unsol_event(struct hda_codec *codec,
 -                                         unsigned int res)
 -{
 -      switch (res >> 26) {
 -      case ALC880_HP_EVENT:
 -              alc663_m51va_speaker_automute(codec);
 -              break;
 -      case ALC880_MIC_EVENT:
 -              alc_mic_automute(codec);
 -              break;
 -      }
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc663_m51va_setup(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 +      spec->autocfg.hp_pins[0] = 0x21;
 +      spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute_mixer_nid[0] = 0x0c;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_MIXER;
        spec->ext_mic.pin = 0x18;
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.pin = 0x12;
        spec->auto_mic = 1;
  }
  
 -static void alc663_m51va_inithook(struct hda_codec *codec)
 -{
 -      alc663_m51va_speaker_automute(codec);
 -      alc_mic_automute(codec);
 -}
 -
  /* ***************** Mode1 ******************************/
  static void alc663_mode1_setup(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 +      spec->autocfg.hp_pins[0] = 0x21;
 +      spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute_mixer_nid[0] = 0x0c;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_MIXER;
        spec->ext_mic.pin = 0x18;
        spec->ext_mic.mux_idx = 0;
        spec->int_mic.pin = 0x19;
        spec->auto_mic = 1;
  }
  
 -#define alc663_mode1_inithook         alc663_m51va_inithook
 -
  /* ***************** Mode2 ******************************/
 -static void alc662_mode2_unsol_event(struct hda_codec *codec,
 -                                         unsigned int res)
 +static void alc662_mode2_setup(struct hda_codec *codec)
  {
 -      switch (res >> 26) {
 -      case ALC880_HP_EVENT:
 -              alc662_f5z_speaker_automute(codec);
 -              break;
 -      case ALC880_MIC_EVENT:
 -              alc_mic_automute(codec);
 -              break;
 -      }
 +      struct alc_spec *spec = codec->spec;
 +      spec->autocfg.hp_pins[0] = 0x1b;
 +      spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_PIN;
 +      spec->ext_mic.pin = 0x18;
 +      spec->ext_mic.mux_idx = 0;
 +      spec->int_mic.pin = 0x19;
 +      spec->int_mic.mux_idx = 1;
 +      spec->auto_mic = 1;
  }
  
 -#define alc662_mode2_setup    alc663_mode1_setup
 -
 -static void alc662_mode2_inithook(struct hda_codec *codec)
 -{
 -      alc662_f5z_speaker_automute(codec);
 -      alc_mic_automute(codec);
 -}
  /* ***************** Mode3 ******************************/
 -static void alc663_mode3_unsol_event(struct hda_codec *codec,
 -                                         unsigned int res)
 +static void alc663_mode3_setup(struct hda_codec *codec)
  {
 -      switch (res >> 26) {
 -      case ALC880_HP_EVENT:
 -              alc663_two_hp_m1_speaker_automute(codec);
 -              break;
 -      case ALC880_MIC_EVENT:
 -              alc_mic_automute(codec);
 -              break;
 -      }
 +      struct alc_spec *spec = codec->spec;
 +      spec->autocfg.hp_pins[0] = 0x21;
 +      spec->autocfg.hp_pins[0] = 0x15;
 +      spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_PIN;
 +      spec->ext_mic.pin = 0x18;
 +      spec->ext_mic.mux_idx = 0;
 +      spec->int_mic.pin = 0x19;
 +      spec->int_mic.mux_idx = 1;
 +      spec->auto_mic = 1;
  }
  
 -#define alc663_mode3_setup    alc663_mode1_setup
 -
 -static void alc663_mode3_inithook(struct hda_codec *codec)
 -{
 -      alc663_two_hp_m1_speaker_automute(codec);
 -      alc_mic_automute(codec);
 -}
  /* ***************** Mode4 ******************************/
 -static void alc663_mode4_unsol_event(struct hda_codec *codec,
 -                                         unsigned int res)
 +static void alc663_mode4_setup(struct hda_codec *codec)
  {
 -      switch (res >> 26) {
 -      case ALC880_HP_EVENT:
 -              alc663_21jd_two_speaker_automute(codec);
 -              break;
 -      case ALC880_MIC_EVENT:
 -              alc_mic_automute(codec);
 -              break;
 -      }
 +      struct alc_spec *spec = codec->spec;
 +      spec->autocfg.hp_pins[0] = 0x21;
 +      spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->autocfg.speaker_pins[1] = 0x16;
 +      spec->automute_mixer_nid[0] = 0x0c;
 +      spec->automute_mixer_nid[1] = 0x0e;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_MIXER;
 +      spec->ext_mic.pin = 0x18;
 +      spec->ext_mic.mux_idx = 0;
 +      spec->int_mic.pin = 0x19;
 +      spec->int_mic.mux_idx = 1;
 +      spec->auto_mic = 1;
  }
  
 -#define alc663_mode4_setup    alc663_mode1_setup
 -
 -static void alc663_mode4_inithook(struct hda_codec *codec)
 -{
 -      alc663_21jd_two_speaker_automute(codec);
 -      alc_mic_automute(codec);
 -}
  /* ***************** Mode5 ******************************/
 -static void alc663_mode5_unsol_event(struct hda_codec *codec,
 -                                         unsigned int res)
 +static void alc663_mode5_setup(struct hda_codec *codec)
  {
 -      switch (res >> 26) {
 -      case ALC880_HP_EVENT:
 -              alc663_15jd_two_speaker_automute(codec);
 -              break;
 -      case ALC880_MIC_EVENT:
 -              alc_mic_automute(codec);
 -              break;
 -      }
 +      struct alc_spec *spec = codec->spec;
 +      spec->autocfg.hp_pins[0] = 0x15;
 +      spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->autocfg.speaker_pins[1] = 0x16;
 +      spec->automute_mixer_nid[0] = 0x0c;
 +      spec->automute_mixer_nid[1] = 0x0e;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_MIXER;
 +      spec->ext_mic.pin = 0x18;
 +      spec->ext_mic.mux_idx = 0;
 +      spec->int_mic.pin = 0x19;
 +      spec->int_mic.mux_idx = 1;
 +      spec->auto_mic = 1;
  }
  
 -#define alc663_mode5_setup    alc663_mode1_setup
 -
 -static void alc663_mode5_inithook(struct hda_codec *codec)
 -{
 -      alc663_15jd_two_speaker_automute(codec);
 -      alc_mic_automute(codec);
 -}
  /* ***************** Mode6 ******************************/
 -static void alc663_mode6_unsol_event(struct hda_codec *codec,
 -                                         unsigned int res)
 +static void alc663_mode6_setup(struct hda_codec *codec)
  {
 -      switch (res >> 26) {
 -      case ALC880_HP_EVENT:
 -              alc663_two_hp_m2_speaker_automute(codec);
 -              break;
 -      case ALC880_MIC_EVENT:
 -              alc_mic_automute(codec);
 -              break;
 -      }
 -}
 -
 -#define alc663_mode6_setup    alc663_mode1_setup
 -
 -static void alc663_mode6_inithook(struct hda_codec *codec)
 -{
 -      alc663_two_hp_m2_speaker_automute(codec);
 -      alc_mic_automute(codec);
 +      struct alc_spec *spec = codec->spec;
 +      spec->autocfg.hp_pins[0] = 0x1b;
 +      spec->autocfg.hp_pins[0] = 0x15;
 +      spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute_mixer_nid[0] = 0x0c;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_MIXER;
 +      spec->ext_mic.pin = 0x18;
 +      spec->ext_mic.mux_idx = 0;
 +      spec->int_mic.pin = 0x19;
 +      spec->int_mic.mux_idx = 1;
 +      spec->auto_mic = 1;
  }
  
  /* ***************** Mode7 ******************************/
 -static void alc663_mode7_unsol_event(struct hda_codec *codec,
 -                                         unsigned int res)
 +static void alc663_mode7_setup(struct hda_codec *codec)
  {
 -      switch (res >> 26) {
 -      case ALC880_HP_EVENT:
 -              alc663_two_hp_m7_speaker_automute(codec);
 -              break;
 -      case ALC880_MIC_EVENT:
 -              alc_mic_automute(codec);
 -              break;
 -      }
 -}
 -
 -#define alc663_mode7_setup    alc663_mode1_setup
 -
 -static void alc663_mode7_inithook(struct hda_codec *codec)
 -{
 -      alc663_two_hp_m7_speaker_automute(codec);
 -      alc_mic_automute(codec);
 +      struct alc_spec *spec = codec->spec;
 +      spec->autocfg.hp_pins[0] = 0x1b;
 +      spec->autocfg.hp_pins[0] = 0x21;
 +      spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->autocfg.speaker_pins[0] = 0x17;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_PIN;
 +      spec->ext_mic.pin = 0x18;
 +      spec->ext_mic.mux_idx = 0;
 +      spec->int_mic.pin = 0x19;
 +      spec->int_mic.mux_idx = 1;
 +      spec->auto_mic = 1;
  }
  
  /* ***************** Mode8 ******************************/
 -static void alc663_mode8_unsol_event(struct hda_codec *codec,
 -                                         unsigned int res)
 -{
 -      switch (res >> 26) {
 -      case ALC880_HP_EVENT:
 -              alc663_two_hp_m8_speaker_automute(codec);
 -              break;
 -      case ALC880_MIC_EVENT:
 -              alc_mic_automute(codec);
 -              break;
 -      }
 -}
 -
 -#define alc663_mode8_setup    alc663_m51va_setup
 -
 -static void alc663_mode8_inithook(struct hda_codec *codec)
 -{
 -      alc663_two_hp_m8_speaker_automute(codec);
 -      alc_mic_automute(codec);
 -}
 -
 -static void alc663_g71v_hp_automute(struct hda_codec *codec)
 -{
 -      unsigned int present;
 -      unsigned char bits;
 -
 -      present = snd_hda_jack_detect(codec, 0x21);
 -      bits = present ? HDA_AMP_MUTE : 0;
 -      snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -      snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -}
 -
 -static void alc663_g71v_front_automute(struct hda_codec *codec)
 -{
 -      unsigned int present;
 -      unsigned char bits;
 -
 -      present = snd_hda_jack_detect(codec, 0x15);
 -      bits = present ? HDA_AMP_MUTE : 0;
 -      snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
 -                               HDA_AMP_MUTE, bits);
 -}
 -
 -static void alc663_g71v_unsol_event(struct hda_codec *codec,
 -                                         unsigned int res)
 -{
 -      switch (res >> 26) {
 -      case ALC880_HP_EVENT:
 -              alc663_g71v_hp_automute(codec);
 -              break;
 -      case ALC880_FRONT_EVENT:
 -              alc663_g71v_front_automute(codec);
 -              break;
 -      case ALC880_MIC_EVENT:
 -              alc_mic_automute(codec);
 -              break;
 -      }
 -}
 -
 -#define alc663_g71v_setup     alc663_m51va_setup
 -
 -static void alc663_g71v_inithook(struct hda_codec *codec)
 +static void alc663_mode8_setup(struct hda_codec *codec)
  {
 -      alc663_g71v_front_automute(codec);
 -      alc663_g71v_hp_automute(codec);
 -      alc_mic_automute(codec);
 +      struct alc_spec *spec = codec->spec;
 +      spec->autocfg.hp_pins[0] = 0x21;
 +      spec->autocfg.hp_pins[1] = 0x15;
 +      spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->autocfg.speaker_pins[0] = 0x17;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_PIN;
 +      spec->ext_mic.pin = 0x18;
 +      spec->ext_mic.mux_idx = 0;
 +      spec->int_mic.pin = 0x12;
 +      spec->int_mic.mux_idx = 9;
 +      spec->auto_mic = 1;
  }
  
 -static void alc663_g50v_unsol_event(struct hda_codec *codec,
 -                                         unsigned int res)
 +static void alc663_g71v_setup(struct hda_codec *codec)
  {
 -      switch (res >> 26) {
 -      case ALC880_HP_EVENT:
 -              alc663_m51va_speaker_automute(codec);
 -              break;
 -      case ALC880_MIC_EVENT:
 -              alc_mic_automute(codec);
 -              break;
 -      }
 +      struct alc_spec *spec = codec->spec;
 +      spec->autocfg.hp_pins[0] = 0x21;
 +      spec->autocfg.line_out_pins[0] = 0x15;
 +      spec->autocfg.speaker_pins[0] = 0x14;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
 +      spec->detect_line = 1;
 +      spec->automute_lines = 1;
 +      spec->ext_mic.pin = 0x18;
 +      spec->ext_mic.mux_idx = 0;
 +      spec->int_mic.pin = 0x12;
 +      spec->int_mic.mux_idx = 9;
 +      spec->auto_mic = 1;
  }
  
  #define alc663_g50v_setup     alc663_m51va_setup
  
 -static void alc663_g50v_inithook(struct hda_codec *codec)
 -{
 -      alc663_m51va_speaker_automute(codec);
 -      alc_mic_automute(codec);
 -}
 -
  static struct snd_kcontrol_new alc662_ecs_mixer[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
        ALC262_HIPPO_MASTER_SWITCH,
@@@ -18398,7 -18707,7 +18391,7 @@@ static const char * const alc662_models
        [ALC662_3ST_2ch_DIG]    = "3stack-dig",
        [ALC662_3ST_6ch_DIG]    = "3stack-6ch-dig",
        [ALC662_3ST_6ch]        = "3stack-6ch",
 -      [ALC662_5ST_DIG]        = "6stack-dig",
 +      [ALC662_5ST_DIG]        = "5stack-dig",
        [ALC662_LENOVO_101E]    = "lenovo-101e",
        [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
        [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
@@@ -18489,6 -18798,8 +18482,8 @@@ static struct snd_pci_quirk alc662_cfg_
                      ALC662_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
        SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
+       SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
+                     ALC662_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
        SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
        SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
  static struct alc_config_preset alc662_presets[] = {
        [ALC662_3ST_2ch_DIG] = {
                .mixers = { alc662_3ST_2ch_mixer },
 -              .init_verbs = { alc662_init_verbs },
 +              .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .dig_out_nid = ALC662_DIGOUT_NID,
        },
        [ALC662_3ST_6ch_DIG] = {
                .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
 -              .init_verbs = { alc662_init_verbs },
 +              .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .dig_out_nid = ALC662_DIGOUT_NID,
        },
        [ALC662_3ST_6ch] = {
                .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
 -              .init_verbs = { alc662_init_verbs },
 +              .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
        },
        [ALC662_5ST_DIG] = {
                .mixers = { alc662_base_mixer, alc662_chmode_mixer },
 -              .init_verbs = { alc662_init_verbs },
 +              .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .dig_out_nid = ALC662_DIGOUT_NID,
        },
        [ALC662_LENOVO_101E] = {
                .mixers = { alc662_lenovo_101e_mixer },
 -              .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
 +              .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
 +                              alc662_sue_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
                .input_mux = &alc662_lenovo_101e_capture_source,
 -              .unsol_event = alc662_lenovo_101e_unsol_event,
 -              .init_hook = alc662_lenovo_101e_all_automute,
 +              .unsol_event = alc_sku_unsol_event,
 +              .setup = alc662_lenovo_101e_setup,
 +              .init_hook = alc_inithook,
        },
        [ALC662_ASUS_EEEPC_P701] = {
                .mixers = { alc662_eeepc_p701_mixer },
                .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
                                alc662_eeepc_sue_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc662_eeepc_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc662_eeepc_setup,
 -              .init_hook = alc662_eeepc_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC662_ASUS_EEEPC_EP20] = {
                .mixers = { alc662_eeepc_ep20_mixer,
                            alc662_chmode_mixer },
                .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
                                alc662_eeepc_ep20_sue_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
                .channel_mode = alc662_3ST_6ch_modes,
                .input_mux = &alc662_lenovo_101e_capture_source,
 -              .unsol_event = alc662_eeepc_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc662_eeepc_ep20_setup,
 -              .init_hook = alc662_eeepc_ep20_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC662_ECS] = {
                .mixers = { alc662_ecs_mixer },
                .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
                                alc662_ecs_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc662_eeepc_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc662_eeepc_setup,
 -              .init_hook = alc662_eeepc_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC663_ASUS_M51VA] = {
                .mixers = { alc663_m51va_mixer },
 -              .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
 +              .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
 +                              alc663_m51va_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .dig_out_nid = ALC662_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc663_m51va_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc663_m51va_setup,
 -              .init_hook = alc663_m51va_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC663_ASUS_G71V] = {
                .mixers = { alc663_g71v_mixer },
 -              .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
 +              .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
 +                              alc663_g71v_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .dig_out_nid = ALC662_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc663_g71v_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc663_g71v_setup,
 -              .init_hook = alc663_g71v_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC663_ASUS_H13] = {
                .mixers = { alc663_m51va_mixer },
 -              .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
 +              .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
 +                              alc663_m51va_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc663_m51va_unsol_event,
 -              .init_hook = alc663_m51va_inithook,
 +              .setup = alc663_m51va_setup,
 +              .unsol_event = alc_sku_unsol_event,
 +              .init_hook = alc_inithook,
        },
        [ALC663_ASUS_G50V] = {
                .mixers = { alc663_g50v_mixer },
 -              .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
 +              .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
 +                              alc663_g50v_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .dig_out_nid = ALC662_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
                .channel_mode = alc662_3ST_6ch_modes,
                .input_mux = &alc663_capture_source,
 -              .unsol_event = alc663_g50v_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc663_g50v_setup,
 -              .init_hook = alc663_g50v_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC663_ASUS_MODE1] = {
                .mixers = { alc663_m51va_mixer },
                .cap_mixer = alc662_auto_capture_mixer,
                .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
                                alc663_21jd_amic_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .hp_nid = 0x03,
                .dig_out_nid = ALC662_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc663_mode1_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc663_mode1_setup,
 -              .init_hook = alc663_mode1_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC662_ASUS_MODE2] = {
                .mixers = { alc662_1bjd_mixer },
                .cap_mixer = alc662_auto_capture_mixer,
                .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
                                alc662_1bjd_amic_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .dac_nids = alc662_dac_nids,
                .dig_out_nid = ALC662_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc662_mode2_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc662_mode2_setup,
 -              .init_hook = alc662_mode2_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC663_ASUS_MODE3] = {
                .mixers = { alc663_two_hp_m1_mixer },
                .cap_mixer = alc662_auto_capture_mixer,
                .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
                                alc663_two_hp_amic_m1_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .hp_nid = 0x03,
                .dig_out_nid = ALC662_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc663_mode3_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc663_mode3_setup,
 -              .init_hook = alc663_mode3_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC663_ASUS_MODE4] = {
                .mixers = { alc663_asus_21jd_clfe_mixer },
                .cap_mixer = alc662_auto_capture_mixer,
                .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
                                alc663_21jd_amic_init_verbs},
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .hp_nid = 0x03,
                .dig_out_nid = ALC662_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc663_mode4_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc663_mode4_setup,
 -              .init_hook = alc663_mode4_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC663_ASUS_MODE5] = {
                .mixers = { alc663_asus_15jd_clfe_mixer },
                .cap_mixer = alc662_auto_capture_mixer,
                .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
                                alc663_15jd_amic_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .hp_nid = 0x03,
                .dig_out_nid = ALC662_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc663_mode5_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc663_mode5_setup,
 -              .init_hook = alc663_mode5_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC663_ASUS_MODE6] = {
                .mixers = { alc663_two_hp_m2_mixer },
                .cap_mixer = alc662_auto_capture_mixer,
                .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
                                alc663_two_hp_amic_m2_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .hp_nid = 0x03,
                .dig_out_nid = ALC662_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc663_mode6_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc663_mode6_setup,
 -              .init_hook = alc663_mode6_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC663_ASUS_MODE7] = {
                .mixers = { alc663_mode7_mixer },
                .cap_mixer = alc662_auto_capture_mixer,
                .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
                                alc663_mode7_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .hp_nid = 0x03,
                .dig_out_nid = ALC662_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc663_mode7_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc663_mode7_setup,
 -              .init_hook = alc663_mode7_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC663_ASUS_MODE8] = {
                .mixers = { alc663_mode8_mixer },
                .cap_mixer = alc662_auto_capture_mixer,
                .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
                                alc663_mode8_init_verbs },
                .num_dacs = ARRAY_SIZE(alc662_dac_nids),
                .hp_nid = 0x03,
                .dig_out_nid = ALC662_DIGOUT_NID,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc663_mode8_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc663_mode8_setup,
 -              .init_hook = alc663_mode8_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC272_DELL] = {
                .mixers = { alc663_m51va_mixer },
                .cap_mixer = alc272_auto_capture_mixer,
 -              .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
 +              .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
 +                              alc272_dell_init_verbs },
                .num_dacs = ARRAY_SIZE(alc272_dac_nids),
 -              .dac_nids = alc662_dac_nids,
 +              .dac_nids = alc272_dac_nids,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .adc_nids = alc272_adc_nids,
                .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
                .capsrc_nids = alc272_capsrc_nids,
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc663_m51va_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc663_m51va_setup,
 -              .init_hook = alc663_m51va_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC272_DELL_ZM1] = {
                .mixers = { alc663_m51va_mixer },
                .cap_mixer = alc662_auto_capture_mixer,
 -              .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
 +              .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
 +                              alc272_dell_zm1_init_verbs },
                .num_dacs = ARRAY_SIZE(alc272_dac_nids),
 -              .dac_nids = alc662_dac_nids,
 +              .dac_nids = alc272_dac_nids,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .adc_nids = alc662_adc_nids,
                .num_adc_nids = 1,
                .capsrc_nids = alc662_capsrc_nids,
                .channel_mode = alc662_3ST_2ch_modes,
 -              .unsol_event = alc663_m51va_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc663_m51va_setup,
 -              .init_hook = alc663_m51va_inithook,
 +              .init_hook = alc_inithook,
        },
        [ALC272_SAMSUNG_NC10] = {
                .mixers = { alc272_nc10_mixer },
                .init_verbs = { alc662_init_verbs,
 +                              alc662_eapd_init_verbs,
                                alc663_21jd_amic_init_verbs },
                .num_dacs = ARRAY_SIZE(alc272_dac_nids),
                .dac_nids = alc272_dac_nids,
                .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
                .channel_mode = alc662_3ST_2ch_modes,
                /*.input_mux = &alc272_nc10_capture_source,*/
 -              .unsol_event = alc663_mode4_unsol_event,
 +              .unsol_event = alc_sku_unsol_event,
                .setup = alc663_mode4_setup,
 -              .init_hook = alc663_mode4_inithook,
 +              .init_hook = alc_inithook,
        },
  };
  
   */
  
  /* convert from MIX nid to DAC */
 -static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
 -{
 -      if (nid == 0x0f)
 -              return 0x02;
 -      else if (nid >= 0x0c && nid <= 0x0e)
 -              return nid - 0x0c + 0x02;
 -      else if (nid == 0x26) /* ALC887-VD has this DAC too */
 -              return 0x25;
 -      else
 -              return 0;
 +static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
 +{
 +      hda_nid_t list[5];
 +      int i, num;
 +
 +      num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
 +      for (i = 0; i < num; i++) {
 +              if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
 +                      return list[i];
 +      }
 +      return 0;
 +}
 +
 +/* go down to the selector widget before the mixer */
 +static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
 +{
 +      hda_nid_t srcs[5];
 +      int num = snd_hda_get_connections(codec, pin, srcs,
 +                                        ARRAY_SIZE(srcs));
 +      if (num != 1 ||
 +          get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
 +              return pin;
 +      return srcs[0];
  }
  
  /* get MIX nid connected to the given pin targeted to DAC */
 -static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
 +static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
                                   hda_nid_t dac)
  {
        hda_nid_t mix[5];
        int i, num;
  
 +      pin = alc_go_down_to_selector(codec, pin);
        num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
        for (i = 0; i < num; i++) {
 -              if (alc662_mix_to_dac(mix[i]) == dac)
 +              if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
                        return mix[i];
        }
        return 0;
  }
  
 +/* select the connection from pin to DAC if needed */
 +static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
 +                             hda_nid_t dac)
 +{
 +      hda_nid_t mix[5];
 +      int i, num;
 +
 +      pin = alc_go_down_to_selector(codec, pin);
 +      num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
 +      if (num < 2)
 +              return 0;
 +      for (i = 0; i < num; i++) {
 +              if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
 +                      snd_hda_codec_update_cache(codec, pin, 0,
 +                                                 AC_VERB_SET_CONNECT_SEL, i);
 +                      return 0;
 +              }
 +      }
 +      return 0;
 +}
 +
  /* look for an empty DAC slot */
 -static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
 +static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
  {
        struct alc_spec *spec = codec->spec;
        hda_nid_t srcs[5];
        int i, j, num;
  
 +      pin = alc_go_down_to_selector(codec, pin);
        num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
 -      if (num < 0)
 -              return 0;
        for (i = 0; i < num; i++) {
 -              hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
 +              hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
                if (!nid)
                        continue;
                for (j = 0; j < spec->multiout.num_dacs; j++)
@@@ -18934,7 -19183,7 +18929,7 @@@ static int alc662_auto_fill_dac_nids(st
  
        spec->multiout.dac_nids = spec->private_dac_nids;
        for (i = 0; i < cfg->line_outs; i++) {
 -              dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
 +              dac = alc_auto_look_for_dac(codec, cfg->line_out_pins[i]);
                if (!dac)
                        continue;
                spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
@@@ -18973,23 -19222,15 +18968,23 @@@ static int alc662_auto_create_multi_out
        static const char * const chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
 -      const char *pfx = alc_get_line_out_pfx(cfg, true);
 -      hda_nid_t nid, mix;
 -      int i, err;
 +      const char *pfx = alc_get_line_out_pfx(spec, true);
 +      hda_nid_t nid, mix, pin;
 +      int i, err, noutputs;
  
 -      for (i = 0; i < cfg->line_outs; i++) {
 +      noutputs = cfg->line_outs;
 +      if (spec->multi_ios > 0)
 +              noutputs += spec->multi_ios;
 +
 +      for (i = 0; i < noutputs; i++) {
                nid = spec->multiout.dac_nids[i];
                if (!nid)
                        continue;
 -              mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
 +              if (i >= cfg->line_outs)
 +                      pin = spec->multi_io[i - 1].pin;
 +              else
 +                      pin = cfg->line_out_pins[i];
 +              mix = alc_auto_dac_to_mix(codec, pin, nid);
                if (!mix)
                        continue;
                if (!pfx && i == 2) {
@@@ -19035,7 -19276,7 +19030,7 @@@ static int alc662_auto_create_extra_out
  
        if (!pin)
                return 0;
 -      nid = alc662_look_for_dac(codec, pin);
 +      nid = alc_auto_look_for_dac(codec, pin);
        if (!nid) {
                /* the corresponding DAC is already occupied */
                if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
                                   HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
        }
  
 -      mix = alc662_dac_to_mix(codec, pin, nid);
 +      mix = alc_auto_dac_to_mix(codec, pin, nid);
        if (!mix)
                return 0;
        err = alc662_add_vol_ctl(spec, pfx, nid, 3);
@@@ -19069,21 -19310,14 +19064,21 @@@ static void alc662_auto_set_output_and_
        hda_nid_t srcs[HDA_MAX_CONNECTIONS];
  
        alc_set_pin_output(codec, nid, pin_type);
 -      /* need the manual connection? */
        num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
 -      if (num <= 1)
 -              return;
        for (i = 0; i < num; i++) {
 -              if (alc662_mix_to_dac(srcs[i]) != dac)
 +              if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
                        continue;
 -              snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
 +              /* need the manual connection? */
 +              if (num > 1)
 +                      snd_hda_codec_write(codec, nid, 0,
 +                                          AC_VERB_SET_CONNECT_SEL, i);
 +              /* unmute mixer widget inputs */
 +              snd_hda_codec_write(codec, srcs[i], 0,
 +                                  AC_VERB_SET_AMP_GAIN_MUTE,
 +                                  AMP_IN_UNMUTE(0));
 +              snd_hda_codec_write(codec, srcs[i], 0,
 +                                  AC_VERB_SET_AMP_GAIN_MUTE,
 +                                  AMP_IN_UNMUTE(1));
                return;
        }
  }
@@@ -19140,159 -19374,6 +19135,159 @@@ static void alc662_auto_init_analog_inp
  
  #define alc662_auto_init_input_src    alc882_auto_init_input_src
  
 +/*
 + * multi-io helper
 + */
 +static int alc_auto_fill_multi_ios(struct hda_codec *codec,
 +                                 unsigned int location)
 +{
 +      struct alc_spec *spec = codec->spec;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
 +      int type, i, num_pins = 0;
 +
 +      for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
 +              for (i = 0; i < cfg->num_inputs; i++) {
 +                      hda_nid_t nid = cfg->inputs[i].pin;
 +                      hda_nid_t dac;
 +                      unsigned int defcfg, caps;
 +                      if (cfg->inputs[i].type != type)
 +                              continue;
 +                      defcfg = snd_hda_codec_get_pincfg(codec, nid);
 +                      if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
 +                              continue;
 +                      if (location && get_defcfg_location(defcfg) != location)
 +                              continue;
 +                      caps = snd_hda_query_pin_caps(codec, nid);
 +                      if (!(caps & AC_PINCAP_OUT))
 +                              continue;
 +                      dac = alc_auto_look_for_dac(codec, nid);
 +                      if (!dac)
 +                              continue;
 +                      spec->multi_io[num_pins].pin = nid;
 +                      spec->multi_io[num_pins].dac = dac;
 +                      num_pins++;
 +                      spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
 +              }
 +      }
 +      spec->multiout.num_dacs = 1;
 +      if (num_pins < 2)
 +              return 0;
 +      return num_pins;
 +}
 +
 +static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
 +                               struct snd_ctl_elem_info *uinfo)
 +{
 +      struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 +      struct alc_spec *spec = codec->spec;
 +
 +      uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 +      uinfo->count = 1;
 +      uinfo->value.enumerated.items = spec->multi_ios + 1;
 +      if (uinfo->value.enumerated.item > spec->multi_ios)
 +              uinfo->value.enumerated.item = spec->multi_ios;
 +      sprintf(uinfo->value.enumerated.name, "%dch",
 +              (uinfo->value.enumerated.item + 1) * 2);
 +      return 0;
 +}
 +
 +static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
 +                              struct snd_ctl_elem_value *ucontrol)
 +{
 +      struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 +      struct alc_spec *spec = codec->spec;
 +      ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
 +      return 0;
 +}
 +
 +static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
 +{
 +      struct alc_spec *spec = codec->spec;
 +      hda_nid_t nid = spec->multi_io[idx].pin;
 +
 +      if (!spec->multi_io[idx].ctl_in)
 +              spec->multi_io[idx].ctl_in =
 +                      snd_hda_codec_read(codec, nid, 0,
 +                                         AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
 +      if (output) {
 +              snd_hda_codec_update_cache(codec, nid, 0,
 +                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
 +                                         PIN_OUT);
 +              if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
 +                      snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
 +                                               HDA_AMP_MUTE, 0);
 +              alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
 +      } else {
 +              if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
 +                      snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
 +                                               HDA_AMP_MUTE, HDA_AMP_MUTE);
 +              snd_hda_codec_update_cache(codec, nid, 0,
 +                                         AC_VERB_SET_PIN_WIDGET_CONTROL,
 +                                         spec->multi_io[idx].ctl_in);
 +      }
 +      return 0;
 +}
 +
 +static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
 +                              struct snd_ctl_elem_value *ucontrol)
 +{
 +      struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 +      struct alc_spec *spec = codec->spec;
 +      int i, ch;
 +
 +      ch = ucontrol->value.enumerated.item[0];
 +      if (ch < 0 || ch > spec->multi_ios)
 +              return -EINVAL;
 +      if (ch == (spec->ext_channel_count - 1) / 2)
 +              return 0;
 +      spec->ext_channel_count = (ch + 1) * 2;
 +      for (i = 0; i < spec->multi_ios; i++)
 +              alc_set_multi_io(codec, i, i < ch);
 +      spec->multiout.max_channels = spec->ext_channel_count;
 +      return 1;
 +}
 +
 +static struct snd_kcontrol_new alc_auto_channel_mode_enum = {
 +      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 +      .name = "Channel Mode",
 +      .info = alc_auto_ch_mode_info,
 +      .get = alc_auto_ch_mode_get,
 +      .put = alc_auto_ch_mode_put,
 +};
 +
 +static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
 +{
 +      struct alc_spec *spec = codec->spec;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
 +      unsigned int location, defcfg;
 +      int num_pins;
 +
 +      if (cfg->line_outs != 1 ||
 +          cfg->line_out_type != AUTO_PIN_LINE_OUT)
 +              return 0;
 +
 +      defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
 +      location = get_defcfg_location(defcfg);
 +
 +      num_pins = alc_auto_fill_multi_ios(codec, location);
 +      if (num_pins > 0) {
 +              struct snd_kcontrol_new *knew;
 +
 +              knew = alc_kcontrol_new(spec);
 +              if (!knew)
 +                      return -ENOMEM;
 +              *knew = alc_auto_channel_mode_enum;
 +              knew->name = kstrdup("Channel Mode", GFP_KERNEL);
 +              if (!knew->name)
 +                      return -ENOMEM;
 +
 +              spec->multi_ios = num_pins;
 +              spec->ext_channel_count = 2;
 +              spec->multiout.num_dacs = num_pins + 1;
 +      }
 +      return 0;
 +}
 +
  static int alc662_parse_auto_config(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
        err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
        if (err < 0)
                return err;
 +      err = alc_auto_add_multi_channel_mode(codec);
 +      if (err < 0)
 +              return err;
        err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
        spec->num_mux_defs = 1;
        spec->input_mux = &spec->private_imux[0];
  
 -      add_verb(spec, alc662_init_verbs);
 -      if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
 -          codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
 -              add_verb(spec, alc663_init_verbs);
 -
 -      if (codec->vendor_id == 0x10ec0272)
 -              add_verb(spec, alc272_init_verbs);
 -
        err = alc_auto_add_mic_boost(codec);
        if (err < 0)
                return err;
@@@ -19387,7 -19473,7 +19382,7 @@@ enum 
        ALC662_FIXUP_IDEAPAD,
        ALC272_FIXUP_MARIO,
        ALC662_FIXUP_CZC_P10T,
-       ALC662_FIXUP_GIGABYTE,
+       ALC662_FIXUP_SKU_IGNORE,
  };
  
  static const struct alc_fixup alc662_fixups[] = {
                        {}
                }
        },
-       [ALC662_FIXUP_GIGABYTE] = {
-               .type = ALC_FIXUP_PINS,
-               .v.pins = (const struct alc_pincfg[]) {
-                       { 0x14, 0x1114410 }, /* set as speaker */
-                       { }
-               }
+       [ALC662_FIXUP_SKU_IGNORE] = {
+               .type = ALC_FIXUP_SKU,
+               .v.sku = ALC_FIXUP_SKU_IGNORE,
        },
  };
  
  static struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
        SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
-       SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte", ALC662_FIXUP_GIGABYTE),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
@@@ -19543,7 -19626,6 +19535,7 @@@ static int patch_alc662(struct hda_code
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC662_AUTO)
                spec->init_hook = alc662_auto_init;
 +      spec->shutup = alc_eapd_shutup;
  
        alc_init_jacks(codec);
  
@@@ -19742,22 -19824,20 +19734,22 @@@ static void alc680_base_setup(struct hd
        spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
        spec->autocfg.inputs[1].pin = 0x19;
        spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
 +      spec->automute = 1;
 +      spec->automute_mode = ALC_AUTOMUTE_AMP;
  }
  
  static void alc680_unsol_event(struct hda_codec *codec,
                                           unsigned int res)
  {
        if ((res >> 26) == ALC880_HP_EVENT)
 -              alc_automute_amp(codec);
 +              alc_hp_automute(codec);
        if ((res >> 26) == ALC880_MIC_EVENT)
                alc680_rec_autoswitch(codec);
  }
  
  static void alc680_inithook(struct hda_codec *codec)
  {
 -      alc_automute_amp(codec);
 +      alc_hp_automute(codec);
        alc680_rec_autoswitch(codec);
  }
  
@@@ -2475,7 -2475,7 +2475,7 @@@ static int stac92xx_hp_switch_put(struc
   
        spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0;
  
-       /* check to be sure that the ports are upto date with
+       /* check to be sure that the ports are up to date with
         * switch changes
         */
        stac_issue_unsol_event(codec, nid);
@@@ -5729,6 -5729,15 +5729,6 @@@ again
        if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
                snd_hda_sequence_write_cache(codec, unmute_init);
  
 -      /* Some HP machines seem to have unstable codec communications
 -       * especially with ATI fglrx driver.  For recovering from the
 -       * CORB/RIRB stall, allow the BUS reset and keep always sync
 -       */
 -      if (spec->board_config == STAC_HP_DV5) {
 -              codec->bus->sync_write = 1;
 -              codec->bus->allow_bus_reset = 1;
 -      }
 -
        spec->aloopback_ctl = stac92hd71bxx_loopback;
        spec->aloopback_mask = 0x50;
        spec->aloopback_shift = 0;
@@@ -98,15 -98,9 +98,15 @@@ enum VIA_HDA_CODEC 
        VT1716S,
        VT2002P,
        VT1812,
 +      VT1802,
        CODEC_TYPES,
  };
  
 +#define VT2002P_COMPATIBLE(spec) \
 +      ((spec)->codec_type == VT2002P ||\
 +       (spec)->codec_type == VT1812 ||\
 +       (spec)->codec_type == VT1802)
 +
  struct via_spec {
        /* codec parameterization */
        struct snd_kcontrol_new *mixers[6];
        struct delayed_work vt1708_hp_work;
        int vt1708_jack_detectect;
        int vt1708_hp_present;
 +
 +      void (*set_widgets_power_state)(struct hda_codec *codec);
 +
  #ifdef CONFIG_SND_HDA_POWER_SAVE
        struct hda_loopback_check loopback;
  #endif
@@@ -227,19 -218,17 +227,19 @@@ static enum VIA_HDA_CODEC get_codec_typ
                codec_type = VT1812;
        else if (dev_id == 0x0440)
                codec_type = VT1708S;
 +      else if ((dev_id & 0xfff) == 0x446)
 +              codec_type = VT1802;
        else
                codec_type = UNKNOWN;
        return codec_type;
  };
  
 +#define VIA_JACK_EVENT                0x20
  #define VIA_HP_EVENT          0x01
  #define VIA_GPIO_EVENT                0x02
 -#define VIA_JACK_EVENT                0x04
 -#define VIA_MONO_EVENT                0x08
 -#define VIA_SPEAKER_EVENT     0x10
 -#define VIA_BIND_HP_EVENT     0x20
 +#define VIA_MONO_EVENT                0x03
 +#define VIA_SPEAKER_EVENT     0x04
 +#define VIA_BIND_HP_EVENT     0x05
  
  enum {
        VIA_CTL_WIDGET_VOL,
@@@ -256,6 -245,7 +256,6 @@@ enum 
  };
  
  static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
 -static void set_jack_power_state(struct hda_codec *codec);
  static int is_aa_path_mute(struct hda_codec *codec);
  
  static void vt1708_start_hp_work(struct via_spec *spec)
@@@ -281,12 -271,6 +281,12 @@@ static void vt1708_stop_hp_work(struct 
        cancel_delayed_work_sync(&spec->vt1708_hp_work);
  }
  
 +static void set_widgets_power_state(struct hda_codec *codec)
 +{
 +      struct via_spec *spec = codec->spec;
 +      if (spec->set_widgets_power_state)
 +              spec->set_widgets_power_state(codec);
 +}
  
  static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
                                   struct snd_ctl_elem_value *ucontrol)
        int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
  
 -      set_jack_power_state(codec);
 +      set_widgets_power_state(codec);
        analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
        if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
                if (is_aa_path_mute(codec))
@@@ -618,6 -602,482 +618,6 @@@ static void set_pin_power_state(struct 
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm);
  }
  
 -static void set_jack_power_state(struct hda_codec *codec)
 -{
 -      struct via_spec *spec = codec->spec;
 -      int imux_is_smixer;
 -      unsigned int parm;
 -
 -      if (spec->codec_type == VT1702) {
 -              imux_is_smixer = snd_hda_codec_read(
 -                      codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
 -              /* inputs */
 -              /* PW 1/2/5 (14h/15h/18h) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x14, &parm);
 -              set_pin_power_state(codec, 0x15, &parm);
 -              set_pin_power_state(codec, 0x18, &parm);
 -              if (imux_is_smixer)
 -                      parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */
 -              /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
 -              snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -
 -              /* outputs */
 -              /* PW 3/4 (16h/17h) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x16, &parm);
 -              set_pin_power_state(codec, 0x17, &parm);
 -              /* MW0 (1ah), AOW 0/1 (10h/1dh) */
 -              snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
 -                                  imux_is_smixer ? AC_PWRST_D0 : parm);
 -              snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -      } else if (spec->codec_type == VT1708B_8CH
 -                 || spec->codec_type == VT1708B_4CH
 -                 || spec->codec_type == VT1708S) {
 -              /* SW0 (17h) = stereo mixer */
 -              int is_8ch = spec->codec_type != VT1708B_4CH;
 -              imux_is_smixer = snd_hda_codec_read(
 -                      codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
 -                      == ((spec->codec_type == VT1708S)  ? 5 : 0);
 -              /* inputs */
 -              /* PW 1/2/5 (1ah/1bh/1eh) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x1a, &parm);
 -              set_pin_power_state(codec, 0x1b, &parm);
 -              set_pin_power_state(codec, 0x1e, &parm);
 -              if (imux_is_smixer)
 -                      parm = AC_PWRST_D0;
 -              /* SW0 (17h), AIW 0/1 (13h/14h) */
 -              snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -
 -              /* outputs */
 -              /* PW0 (19h), SW1 (18h), AOW1 (11h) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x19, &parm);
 -              if (spec->smart51_enabled)
 -                      parm = AC_PWRST_D0;
 -              snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -
 -              /* PW6 (22h), SW2 (26h), AOW2 (24h) */
 -              if (is_8ch) {
 -                      parm = AC_PWRST_D3;
 -                      set_pin_power_state(codec, 0x22, &parm);
 -                      if (spec->smart51_enabled)
 -                              parm = AC_PWRST_D0;
 -                      snd_hda_codec_write(codec, 0x26, 0,
 -                                          AC_VERB_SET_POWER_STATE, parm);
 -                      snd_hda_codec_write(codec, 0x24, 0,
 -                                          AC_VERB_SET_POWER_STATE, parm);
 -              }
 -
 -              /* PW 3/4/7 (1ch/1dh/23h) */
 -              parm = AC_PWRST_D3;
 -              /* force to D0 for internal Speaker */
 -              set_pin_power_state(codec, 0x1c, &parm);
 -              set_pin_power_state(codec, 0x1d, &parm);
 -              if (is_8ch)
 -                      set_pin_power_state(codec, 0x23, &parm);
 -              /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
 -              snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
 -                                  imux_is_smixer ? AC_PWRST_D0 : parm);
 -              snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              if (is_8ch) {
 -                      snd_hda_codec_write(codec, 0x25, 0,
 -                                          AC_VERB_SET_POWER_STATE, parm);
 -                      snd_hda_codec_write(codec, 0x27, 0,
 -                                          AC_VERB_SET_POWER_STATE, parm);
 -              }
 -      }  else if (spec->codec_type == VT1718S) {
 -              /* MUX6 (1eh) = stereo mixer */
 -              imux_is_smixer = snd_hda_codec_read(
 -                      codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
 -              /* inputs */
 -              /* PW 5/6/7 (29h/2ah/2bh) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x29, &parm);
 -              set_pin_power_state(codec, 0x2a, &parm);
 -              set_pin_power_state(codec, 0x2b, &parm);
 -              if (imux_is_smixer)
 -                      parm = AC_PWRST_D0;
 -              /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
 -              snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -
 -              /* outputs */
 -              /* PW3 (27h), MW2 (1ah), AOW3 (bh) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x27, &parm);
 -              snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -
 -              /* PW2 (26h), AOW2 (ah) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x26, &parm);
 -              snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -
 -              /* PW0/1 (24h/25h) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x24, &parm);
 -              set_pin_power_state(codec, 0x25, &parm);
 -              if (!spec->hp_independent_mode) /* check for redirected HP */
 -                      set_pin_power_state(codec, 0x28, &parm);
 -              snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
 -              snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
 -                                  imux_is_smixer ? AC_PWRST_D0 : parm);
 -              if (spec->hp_independent_mode) {
 -                      /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
 -                      parm = AC_PWRST_D3;
 -                      set_pin_power_state(codec, 0x28, &parm);
 -                      snd_hda_codec_write(codec, 0x1b, 0,
 -                                          AC_VERB_SET_POWER_STATE, parm);
 -                      snd_hda_codec_write(codec, 0x34, 0,
 -                                          AC_VERB_SET_POWER_STATE, parm);
 -                      snd_hda_codec_write(codec, 0xc, 0,
 -                                          AC_VERB_SET_POWER_STATE, parm);
 -              }
 -      } else if (spec->codec_type == VT1716S) {
 -              unsigned int mono_out, present;
 -              /* SW0 (17h) = stereo mixer */
 -              imux_is_smixer = snd_hda_codec_read(
 -                      codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) ==  5;
 -              /* inputs */
 -              /* PW 1/2/5 (1ah/1bh/1eh) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x1a, &parm);
 -              set_pin_power_state(codec, 0x1b, &parm);
 -              set_pin_power_state(codec, 0x1e, &parm);
 -              if (imux_is_smixer)
 -                      parm = AC_PWRST_D0;
 -              /* SW0 (17h), AIW0(13h) */
 -              snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x1e, &parm);
 -              /* PW11 (22h) */
 -              if (spec->dmic_enabled)
 -                      set_pin_power_state(codec, 0x22, &parm);
 -              else
 -                      snd_hda_codec_write(
 -                              codec, 0x22, 0,
 -                              AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 -
 -              /* SW2(26h), AIW1(14h) */
 -              snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -
 -              /* outputs */
 -              /* PW0 (19h), SW1 (18h), AOW1 (11h) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x19, &parm);
 -              /* Smart 5.1 PW2(1bh) */
 -              if (spec->smart51_enabled)
 -                      set_pin_power_state(codec, 0x1b, &parm);
 -              snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -
 -              /* PW7 (23h), SW3 (27h), AOW3 (25h) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x23, &parm);
 -              /* Smart 5.1 PW1(1ah) */
 -              if (spec->smart51_enabled)
 -                      set_pin_power_state(codec, 0x1a, &parm);
 -              snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -
 -              /* Smart 5.1 PW5(1eh) */
 -              if (spec->smart51_enabled)
 -                      set_pin_power_state(codec, 0x1e, &parm);
 -              snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -
 -              /* Mono out */
 -              /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
 -              present = snd_hda_jack_detect(codec, 0x1c);
 -              if (present)
 -                      mono_out = 0;
 -              else {
 -                      present = snd_hda_jack_detect(codec, 0x1d);
 -                      if (!spec->hp_independent_mode && present)
 -                              mono_out = 0;
 -                      else
 -                              mono_out = 1;
 -              }
 -              parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
 -              snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -              snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE,
 -                                  parm);
 -
 -              /* PW 3/4 (1ch/1dh) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x1c, &parm);
 -              set_pin_power_state(codec, 0x1d, &parm);
 -              /* HP Independent Mode, power on AOW3 */
 -              if (spec->hp_independent_mode)
 -                      snd_hda_codec_write(codec, 0x25, 0,
 -                                          AC_VERB_SET_POWER_STATE, parm);
 -
 -              /* force to D0 for internal Speaker */
 -              /* MW0 (16h), AOW0 (10h) */
 -              snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
 -                                  imux_is_smixer ? AC_PWRST_D0 : parm);
 -              snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
 -                                  mono_out ? AC_PWRST_D0 : parm);
 -      } else if (spec->codec_type == VT2002P) {
 -              unsigned int present;
 -              /* MUX9 (1eh) = stereo mixer */
 -              imux_is_smixer = snd_hda_codec_read(
 -                      codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
 -              /* inputs */
 -              /* PW 5/6/7 (29h/2ah/2bh) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x29, &parm);
 -              set_pin_power_state(codec, 0x2a, &parm);
 -              set_pin_power_state(codec, 0x2b, &parm);
 -              if (imux_is_smixer)
 -                      parm = AC_PWRST_D0;
 -              /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
 -              snd_hda_codec_write(codec, 0x1e, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -              snd_hda_codec_write(codec, 0x1f, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -              snd_hda_codec_write(codec, 0x10, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -              snd_hda_codec_write(codec, 0x11, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -
 -              /* outputs */
 -              /* AOW0 (8h)*/
 -              snd_hda_codec_write(codec, 0x8, 0,
 -                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 -
 -              /* PW4 (26h), MW4 (1ch), MUX4(37h) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x26, &parm);
 -              snd_hda_codec_write(codec, 0x1c, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -              snd_hda_codec_write(codec, 0x37,
 -                                  0, AC_VERB_SET_POWER_STATE, parm);
 -
 -              /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x25, &parm);
 -              snd_hda_codec_write(codec, 0x19, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -              snd_hda_codec_write(codec, 0x35, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -              if (spec->hp_independent_mode)  {
 -                      snd_hda_codec_write(codec, 0x9, 0,
 -                                          AC_VERB_SET_POWER_STATE, parm);
 -              }
 -
 -              /* Class-D */
 -              /* PW0 (24h), MW0(18h), MUX0(34h) */
 -              present = snd_hda_jack_detect(codec, 0x25);
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x24, &parm);
 -              if (present) {
 -                      snd_hda_codec_write(
 -                              codec, 0x18, 0,
 -                              AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 -                      snd_hda_codec_write(
 -                              codec, 0x34, 0,
 -                              AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 -              } else {
 -                      snd_hda_codec_write(
 -                              codec, 0x18, 0,
 -                              AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 -                      snd_hda_codec_write(
 -                              codec, 0x34, 0,
 -                              AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 -              }
 -
 -              /* Mono Out */
 -              /* PW15 (31h), MW8(17h), MUX8(3bh) */
 -              present = snd_hda_jack_detect(codec, 0x26);
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x31, &parm);
 -              if (present) {
 -                      snd_hda_codec_write(
 -                              codec, 0x17, 0,
 -                              AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 -                      snd_hda_codec_write(
 -                              codec, 0x3b, 0,
 -                              AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 -              } else {
 -                      snd_hda_codec_write(
 -                              codec, 0x17, 0,
 -                              AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 -                      snd_hda_codec_write(
 -                              codec, 0x3b, 0,
 -                              AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 -              }
 -
 -              /* MW9 (21h) */
 -              if (imux_is_smixer || !is_aa_path_mute(codec))
 -                      snd_hda_codec_write(
 -                              codec, 0x21, 0,
 -                              AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 -              else
 -                      snd_hda_codec_write(
 -                              codec, 0x21, 0,
 -                              AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 -      } else if (spec->codec_type == VT1812) {
 -              unsigned int present;
 -              /* MUX10 (1eh) = stereo mixer */
 -              imux_is_smixer = snd_hda_codec_read(
 -                      codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
 -              /* inputs */
 -              /* PW 5/6/7 (29h/2ah/2bh) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x29, &parm);
 -              set_pin_power_state(codec, 0x2a, &parm);
 -              set_pin_power_state(codec, 0x2b, &parm);
 -              if (imux_is_smixer)
 -                      parm = AC_PWRST_D0;
 -              /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
 -              snd_hda_codec_write(codec, 0x1e, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -              snd_hda_codec_write(codec, 0x1f, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -              snd_hda_codec_write(codec, 0x10, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -              snd_hda_codec_write(codec, 0x11, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -
 -              /* outputs */
 -              /* AOW0 (8h)*/
 -              snd_hda_codec_write(codec, 0x8, 0,
 -                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 -
 -              /* PW4 (28h), MW4 (18h), MUX4(38h) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x28, &parm);
 -              snd_hda_codec_write(codec, 0x18, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -              snd_hda_codec_write(codec, 0x38, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -
 -              /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x25, &parm);
 -              snd_hda_codec_write(codec, 0x15, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -              snd_hda_codec_write(codec, 0x35, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -              if (spec->hp_independent_mode)  {
 -                      snd_hda_codec_write(codec, 0x9, 0,
 -                                          AC_VERB_SET_POWER_STATE, parm);
 -              }
 -
 -              /* Internal Speaker */
 -              /* PW0 (24h), MW0(14h), MUX0(34h) */
 -              present = snd_hda_jack_detect(codec, 0x25);
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x24, &parm);
 -              if (present) {
 -                      snd_hda_codec_write(codec, 0x14, 0,
 -                                          AC_VERB_SET_POWER_STATE,
 -                                          AC_PWRST_D3);
 -                      snd_hda_codec_write(codec, 0x34, 0,
 -                                          AC_VERB_SET_POWER_STATE,
 -                                          AC_PWRST_D3);
 -              } else {
 -                      snd_hda_codec_write(codec, 0x14, 0,
 -                                          AC_VERB_SET_POWER_STATE,
 -                                          AC_PWRST_D0);
 -                      snd_hda_codec_write(codec, 0x34, 0,
 -                                          AC_VERB_SET_POWER_STATE,
 -                                          AC_PWRST_D0);
 -              }
 -              /* Mono Out */
 -              /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */
 -              present = snd_hda_jack_detect(codec, 0x28);
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x31, &parm);
 -              if (present) {
 -                      snd_hda_codec_write(codec, 0x1c, 0,
 -                                          AC_VERB_SET_POWER_STATE,
 -                                          AC_PWRST_D3);
 -                      snd_hda_codec_write(codec, 0x3c, 0,
 -                                          AC_VERB_SET_POWER_STATE,
 -                                          AC_PWRST_D3);
 -                      snd_hda_codec_write(codec, 0x3e, 0,
 -                                          AC_VERB_SET_POWER_STATE,
 -                                          AC_PWRST_D3);
 -              } else {
 -                      snd_hda_codec_write(codec, 0x1c, 0,
 -                                          AC_VERB_SET_POWER_STATE,
 -                                          AC_PWRST_D0);
 -                      snd_hda_codec_write(codec, 0x3c, 0,
 -                                          AC_VERB_SET_POWER_STATE,
 -                                          AC_PWRST_D0);
 -                      snd_hda_codec_write(codec, 0x3e, 0,
 -                                          AC_VERB_SET_POWER_STATE,
 -                                          AC_PWRST_D0);
 -              }
 -
 -              /* PW15 (33h), MW15 (1dh), MUX15(3dh) */
 -              parm = AC_PWRST_D3;
 -              set_pin_power_state(codec, 0x33, &parm);
 -              snd_hda_codec_write(codec, 0x1d, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -              snd_hda_codec_write(codec, 0x3d, 0,
 -                                  AC_VERB_SET_POWER_STATE, parm);
 -
 -              /* MW9 (21h) */
 -              if (imux_is_smixer || !is_aa_path_mute(codec))
 -                      snd_hda_codec_write(
 -                              codec, 0x21, 0,
 -                              AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 -              else
 -                      snd_hda_codec_write(
 -                              codec, 0x21, 0,
 -                              AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 -      }
 -}
 -
  /*
   * input MUX handling
   */
@@@ -660,7 -1120,7 +660,7 @@@ static int via_mux_enum_put(struct snd_
                                     spec->mux_nids[adc_idx],
                                     &spec->cur_mux[adc_idx]);
        /* update jack power state */
 -      set_jack_power_state(codec);
 +      set_widgets_power_state(codec);
  
        return ret;
  }
@@@ -708,9 -1168,6 +708,9 @@@ static hda_nid_t side_mute_channel(stru
        case VT1709_10CH:       return 0x29;
        case VT1708B_8CH:       /* fall thru */
        case VT1708S:           return 0x27;
 +      case VT2002P:           return 0x19;
 +      case VT1802:            return 0x15;
 +      case VT1812:            return 0x15;
        default:                return 0;
        }
  }
@@@ -719,22 -1176,13 +719,22 @@@ static int update_side_mute_status(stru
  {
        /* mute side channel */
        struct via_spec *spec = codec->spec;
 -      unsigned int parm = spec->hp_independent_mode
 -              ? AMP_OUT_MUTE : AMP_OUT_UNMUTE;
 +      unsigned int parm;
        hda_nid_t sw3 = side_mute_channel(spec);
  
 -      if (sw3)
 -              snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE,
 -                                  parm);
 +      if (sw3) {
 +              if (VT2002P_COMPATIBLE(spec))
 +                      parm = spec->hp_independent_mode ?
 +                             AMP_IN_MUTE(1) : AMP_IN_UNMUTE(1);
 +              else
 +                      parm = spec->hp_independent_mode ?
 +                             AMP_OUT_MUTE : AMP_OUT_UNMUTE;
 +              snd_hda_codec_write(codec, sw3, 0,
 +                                  AC_VERB_SET_AMP_GAIN_MUTE, parm);
 +              if (spec->codec_type == VT1812)
 +                      snd_hda_codec_write(codec, 0x1d, 0,
 +                                          AC_VERB_SET_AMP_GAIN_MUTE, parm);
 +      }
        return 0;
  }
  
@@@ -769,14 -1217,15 +769,14 @@@ static int via_independent_hp_put(struc
            || spec->codec_type == VT1702
            || spec->codec_type == VT1718S
            || spec->codec_type == VT1716S
 -          || spec->codec_type == VT2002P
 -          || spec->codec_type == VT1812) {
 +          || VT2002P_COMPATIBLE(spec)) {
                activate_ctl(codec, "Headphone Playback Volume",
                             spec->hp_independent_mode);
                activate_ctl(codec, "Headphone Playback Switch",
                             spec->hp_independent_mode);
        }
        /* update jack power state */
 -      set_jack_power_state(codec);
 +      set_widgets_power_state(codec);
        return 0;
  }
  
@@@ -807,7 -1256,6 +807,7 @@@ static int via_hp_build(struct hda_code
                nid = 0x34;
                break;
        case VT2002P:
 +      case VT1802:
                nid = 0x35;
                break;
        case VT1812:
@@@ -844,14 -1292,18 +844,18 @@@ static void notify_aa_path_ctls(struct 
  {
        int i;
        struct snd_ctl_elem_id id;
-       const char *labels[] = {"Mic", "Front Mic", "Line"};
+       const char *labels[] = {"Mic", "Front Mic", "Line", "Rear Mic"};
+       struct snd_kcontrol *ctl;
  
        memset(&id, 0, sizeof(id));
        id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
        for (i = 0; i < ARRAY_SIZE(labels); i++) {
                sprintf(id.name, "%s Playback Volume", labels[i]);
-               snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
-                              &id);
+               ctl = snd_hda_find_mixer_ctl(codec, id.name);
+               if (ctl)
+                       snd_ctl_notify(codec->bus->card,
+                                       SNDRV_CTL_EVENT_MASK_VALUE,
+                                       &ctl->id);
        }
  }
  
@@@ -995,7 -1447,7 +999,7 @@@ static int via_smart51_put(struct snd_k
                }
        }
        spec->smart51_enabled = *ucontrol->value.integer.value;
 -      set_jack_power_state(codec);
 +      set_widgets_power_state(codec);
        return 1;
  }
  
@@@ -1021,11 -1473,6 +1025,11 @@@ static int via_smart51_build(struct via
        hda_nid_t nid;
        int i;
  
 +      if (!cfg)
 +              return 0;
 +      if (cfg->line_outs > 2)
 +              return 0;
 +
        knew = via_clone_control(spec, &via_smart51_mixer[0]);
        if (knew == NULL)
                return -ENOMEM;
@@@ -1096,7 -1543,6 +1100,7 @@@ static int is_aa_path_mute(struct hda_c
                break;
        case VT2002P:
        case VT1812:
 +      case VT1802:
                nid_mixer = 0x21;
                start_idx = 0;
                end_idx = 2;
@@@ -1161,7 -1607,6 +1165,7 @@@ static void analog_low_current_mode(str
                break;
        case VT2002P:
        case VT1812:
 +      case VT1802:
                verb = 0xf93;
                parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
                break;
@@@ -1205,8 -1650,6 +1209,8 @@@ static struct hda_verb vt1708_volume_in
        {0x20, AC_VERB_SET_CONNECT_SEL, 0},
        /* PW9 Output enable */
        {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
 +      /* power down jack detect function */
 +      {0x1, 0xf81, 0x1},
        { }
  };
  
@@@ -1528,7 -1971,7 +1532,7 @@@ static int via_build_controls(struct hd
        }
  
        /* init power states */
 -      set_jack_power_state(codec);
 +      set_widgets_power_state(codec);
        analog_low_current_mode(codec, 1);
  
        via_free_kctls(codec); /* no longer needed */
@@@ -1692,7 -2135,7 +1696,7 @@@ static void via_speaker_automute(struc
        unsigned int hp_present;
        struct via_spec *spec = codec->spec;
  
 -      if (spec->codec_type != VT2002P && spec->codec_type != VT1812)
 +      if (!VT2002P_COMPATIBLE(spec))
                return;
  
        hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
@@@ -1751,21 -2194,17 +1755,21 @@@ static void via_unsol_event(struct hda_
                                  unsigned int res)
  {
        res >>= 26;
 -      if (res & VIA_HP_EVENT)
 +
 +      if (res & VIA_JACK_EVENT)
 +              set_widgets_power_state(codec);
 +
 +      res &= ~VIA_JACK_EVENT;
 +
 +      if (res == VIA_HP_EVENT)
                via_hp_automute(codec);
 -      if (res & VIA_GPIO_EVENT)
 +      else if (res == VIA_GPIO_EVENT)
                via_gpio_control(codec);
 -      if (res & VIA_JACK_EVENT)
 -              set_jack_power_state(codec);
 -      if (res & VIA_MONO_EVENT)
 +      else if (res == VIA_MONO_EVENT)
                via_mono_automute(codec);
 -      if (res & VIA_SPEAKER_EVENT)
 +      else if (res == VIA_SPEAKER_EVENT)
                via_speaker_automute(codec);
 -      if (res & VIA_BIND_HP_EVENT)
 +      else if (res == VIA_BIND_HP_EVENT)
                via_hp_bind_automute(codec);
  }
  
@@@ -2184,8 -2623,7 +2188,8 @@@ static int via_auto_init(struct hda_cod
        via_auto_init_multi_out(codec);
        via_auto_init_hp_out(codec);
        via_auto_init_analog_input(codec);
 -      if (spec->codec_type == VT2002P || spec->codec_type == VT1812) {
 +
 +      if (VT2002P_COMPATIBLE(spec)) {
                via_hp_bind_automute(codec);
        } else {
                via_hp_automute(codec);
@@@ -3208,87 -3646,6 +3212,87 @@@ static struct hda_amp_list vt1708B_loop
        { } /* end */
  };
  #endif
 +
 +static void set_widgets_power_state_vt1708B(struct hda_codec *codec)
 +{
 +      struct via_spec *spec = codec->spec;
 +      int imux_is_smixer;
 +      unsigned int parm;
 +      int is_8ch = 0;
 +      if ((spec->codec_type != VT1708B_4CH) &&
 +          (codec->vendor_id != 0x11064397))
 +              is_8ch = 1;
 +
 +      /* SW0 (17h) = stereo mixer */
 +      imux_is_smixer =
 +      (snd_hda_codec_read(codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00)
 +       == ((spec->codec_type == VT1708S) ? 5 : 0));
 +      /* inputs */
 +      /* PW 1/2/5 (1ah/1bh/1eh) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x1a, &parm);
 +      set_pin_power_state(codec, 0x1b, &parm);
 +      set_pin_power_state(codec, 0x1e, &parm);
 +      if (imux_is_smixer)
 +              parm = AC_PWRST_D0;
 +      /* SW0 (17h), AIW 0/1 (13h/14h) */
 +      snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* outputs */
 +      /* PW0 (19h), SW1 (18h), AOW1 (11h) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x19, &parm);
 +      if (spec->smart51_enabled)
 +              set_pin_power_state(codec, 0x1b, &parm);
 +      snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* PW6 (22h), SW2 (26h), AOW2 (24h) */
 +      if (is_8ch) {
 +              parm = AC_PWRST_D3;
 +              set_pin_power_state(codec, 0x22, &parm);
 +              if (spec->smart51_enabled)
 +                      set_pin_power_state(codec, 0x1a, &parm);
 +              snd_hda_codec_write(codec, 0x26, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +              snd_hda_codec_write(codec, 0x24, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +      } else if (codec->vendor_id == 0x11064397) {
 +              /* PW7(23h), SW2(27h), AOW2(25h) */
 +              parm = AC_PWRST_D3;
 +              set_pin_power_state(codec, 0x23, &parm);
 +              if (spec->smart51_enabled)
 +                      set_pin_power_state(codec, 0x1a, &parm);
 +              snd_hda_codec_write(codec, 0x27, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +              snd_hda_codec_write(codec, 0x25, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +      }
 +
 +      /* PW 3/4/7 (1ch/1dh/23h) */
 +      parm = AC_PWRST_D3;
 +      /* force to D0 for internal Speaker */
 +      set_pin_power_state(codec, 0x1c, &parm);
 +      set_pin_power_state(codec, 0x1d, &parm);
 +      if (is_8ch)
 +              set_pin_power_state(codec, 0x23, &parm);
 +
 +      /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */
 +      snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
 +                          imux_is_smixer ? AC_PWRST_D0 : parm);
 +      snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
 +      if (is_8ch) {
 +              snd_hda_codec_write(codec, 0x25, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +              snd_hda_codec_write(codec, 0x27, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +      } else if (codec->vendor_id == 0x11064397 && spec->hp_independent_mode)
 +              snd_hda_codec_write(codec, 0x25, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +}
 +
  static int patch_vt1708S(struct hda_codec *codec);
  static int patch_vt1708B_8ch(struct hda_codec *codec)
  {
        spec->loopback.amplist = vt1708B_loopbacks;
  #endif
  
 +      spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
 +
        return 0;
  }
  
@@@ -3391,8 -3746,6 +3395,8 @@@ static int patch_vt1708B_4ch(struct hda
        spec->loopback.amplist = vt1708B_loopbacks;
  #endif
  
 +      spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
 +
        return 0;
  }
  
@@@ -3461,18 -3814,6 +3465,18 @@@ static struct hda_verb vt1708S_uniwill_
        { }
  };
  
 +static struct hda_verb vt1705_uniwill_init_verbs[] = {
 +      {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE,
 +       AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT},
 +      {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 +      {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 +      {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 +      {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 +      {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 +      {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 +      { }
 +};
 +
  static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
        .substreams = 2,
        .channels_min = 2,
        },
  };
  
 +static struct hda_pcm_stream vt1705_pcm_analog_playback = {
 +      .substreams = 2,
 +      .channels_min = 2,
 +      .channels_max = 6,
 +      .nid = 0x10, /* NID to query formats and rates */
 +      .ops = {
 +              .open = via_playback_pcm_open,
 +              .prepare = via_playback_multi_pcm_prepare,
 +              .cleanup = via_playback_multi_pcm_cleanup,
 +              .close = via_pcm_open_close
 +      },
 +};
 +
  static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
        .substreams = 2,
        .channels_min = 2,
@@@ -3545,10 -3873,7 +3549,10 @@@ static int vt1708S_auto_fill_dac_nids(s
                                spec->multiout.dac_nids[i] = 0x10;
                                break;
                        case AUTO_SEQ_CENLFE:
 -                              spec->multiout.dac_nids[i] = 0x24;
 +                              if (spec->codec->vendor_id == 0x11064397)
 +                                      spec->multiout.dac_nids[i] = 0x25;
 +                              else
 +                                      spec->multiout.dac_nids[i] = 0x24;
                                break;
                        case AUTO_SEQ_SURROUND:
                                spec->multiout.dac_nids[i] = 0x11;
        if (cfg->line_outs == 1) {
                spec->multiout.num_dacs = 3;
                spec->multiout.dac_nids[AUTO_SEQ_SURROUND] = 0x11;
 -              spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x24;
 +              if (spec->codec->vendor_id == 0x11064397)
 +                      spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x25;
 +              else
 +                      spec->multiout.dac_nids[AUTO_SEQ_CENLFE] = 0x24;
        }
  
        return 0;
  }
  
  /* add playback controls from the parsed DAC table */
 -static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
 +static int vt1708S_auto_create_multi_out_ctls(struct hda_codec *codec,
                                             const struct auto_pin_cfg *cfg)
  {
 +      struct via_spec *spec = codec->spec;
        char name[32];
        static const char * const chname[4] = {
                "Front", "Surround", "C/LFE", "Side"
        };
 -      hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
 -      hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
 +      hda_nid_t nid_vols[2][4] = { {0x10, 0x11, 0x24, 0x25},
 +                                   {0x10, 0x11, 0x25, 0} };
 +      hda_nid_t nid_mutes[2][4] = { {0x1C, 0x18, 0x26, 0x27},
 +                                    {0x1C, 0x18, 0x27, 0} };
        hda_nid_t nid, nid_vol, nid_mute;
        int i, err;
  
                if (!nid && i > AUTO_SEQ_CENLFE)
                        continue;
  
 -              nid_vol = nid_vols[i];
 -              nid_mute = nid_mutes[i];
 +              if (codec->vendor_id == 0x11064397) {
 +                      nid_vol = nid_vols[1][i];
 +                      nid_mute = nid_mutes[1][i];
 +              } else {
 +                      nid_vol = nid_vols[0][i];
 +                      nid_mute = nid_mutes[0][i];
 +              }
 +              if (!nid_vol && !nid_mute)
 +                      continue;
  
                if (i == AUTO_SEQ_CENLFE) {
                        /* Center/LFE */
@@@ -3758,7 -4070,7 +3762,7 @@@ static int vt1708S_parse_auto_config(st
        if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
                return 0; /* can't find valid BIOS pin config */
  
 -      err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
 +      err = vt1708S_auto_create_multi_out_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
        err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
@@@ -3825,29 -4137,17 +3829,29 @@@ static int patch_vt1708S(struct hda_cod
        }
  
        spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs;
 -      spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs;
 +      if (codec->vendor_id == 0x11064397)
 +              spec->init_verbs[spec->num_iverbs++] =
 +                      vt1705_uniwill_init_verbs;
 +      else
 +              spec->init_verbs[spec->num_iverbs++] =
 +                      vt1708S_uniwill_init_verbs;
  
        if (codec->vendor_id == 0x11060440)
                spec->stream_name_analog = "VT1818S Analog";
 +      else if (codec->vendor_id == 0x11064397)
 +              spec->stream_name_analog = "VT1705 Analog";
        else
                spec->stream_name_analog = "VT1708S Analog";
 -      spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
 +      if (codec->vendor_id == 0x11064397)
 +              spec->stream_analog_playback = &vt1705_pcm_analog_playback;
 +      else
 +              spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
        spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
  
        if (codec->vendor_id == 0x11060440)
                spec->stream_name_digital = "VT1818S Digital";
 +      else if (codec->vendor_id == 0x11064397)
 +              spec->stream_name_digital = "VT1705 Digital";
        else
                spec->stream_name_digital = "VT1708S Digital";
        spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
                spec->stream_name_analog = "VT1818S Analog";
                spec->stream_name_digital = "VT1818S Digital";
        }
 +      /* correct names for VT1705 */
 +      if (codec->vendor_id == 0x11064397)     {
 +              kfree(codec->chip_name);
 +              codec->chip_name = kstrdup("VT1705", GFP_KERNEL);
 +              snprintf(codec->bus->card->mixername,
 +                       sizeof(codec->bus->card->mixername),
 +                       "%s %s", codec->vendor_name, codec->chip_name);
 +      }
 +      spec->set_widgets_power_state =  set_widgets_power_state_vt1708B;
        return 0;
  }
  
@@@ -4151,37 -4442,6 +4155,37 @@@ static struct hda_amp_list vt1702_loopb
  };
  #endif
  
 +static void set_widgets_power_state_vt1702(struct hda_codec *codec)
 +{
 +      int imux_is_smixer =
 +      snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
 +      unsigned int parm;
 +      /* inputs */
 +      /* PW 1/2/5 (14h/15h/18h) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x14, &parm);
 +      set_pin_power_state(codec, 0x15, &parm);
 +      set_pin_power_state(codec, 0x18, &parm);
 +      if (imux_is_smixer)
 +              parm = AC_PWRST_D0; /* SW0 (13h) = stereo mixer (idx 3) */
 +      /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */
 +      snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* outputs */
 +      /* PW 3/4 (16h/17h) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x17, &parm);
 +      set_pin_power_state(codec, 0x16, &parm);
 +      /* MW0 (1ah), AOW 0/1 (10h/1dh) */
 +      snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE,
 +                          imux_is_smixer ? AC_PWRST_D0 : parm);
 +      snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm);
 +}
 +
  static int patch_vt1702(struct hda_codec *codec)
  {
        struct via_spec *spec;
        spec->loopback.amplist = vt1702_loopbacks;
  #endif
  
 +      spec->set_widgets_power_state =  set_widgets_power_state_vt1702;
        return 0;
  }
  
@@@ -4264,8 -4523,7 +4268,8 @@@ static struct hda_verb vt1718S_volume_i
        {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
  
 -
 +      /* Enable MW0 adjust Gain 5 */
 +      {0x1, 0xfb2, 0x10},
        /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
         * mixer widget
         */
        {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
        {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
        {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
 -      {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
 +      {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
  
        /* Setup default input of Front HP to MW9 */
        {0x28, AC_VERB_SET_CONNECT_SEL, 0x1},
@@@ -4571,72 -4829,6 +4575,72 @@@ static struct hda_amp_list vt1718S_loop
  };
  #endif
  
 +static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
 +{
 +      struct via_spec *spec = codec->spec;
 +      int imux_is_smixer;
 +      unsigned int parm;
 +      /* MUX6 (1eh) = stereo mixer */
 +      imux_is_smixer =
 +      snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
 +      /* inputs */
 +      /* PW 5/6/7 (29h/2ah/2bh) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x29, &parm);
 +      set_pin_power_state(codec, 0x2a, &parm);
 +      set_pin_power_state(codec, 0x2b, &parm);
 +      if (imux_is_smixer)
 +              parm = AC_PWRST_D0;
 +      /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */
 +      snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* outputs */
 +      /* PW3 (27h), MW2 (1ah), AOW3 (bh) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x27, &parm);
 +      snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* PW2 (26h), AOW2 (ah) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x26, &parm);
 +      if (spec->smart51_enabled)
 +              set_pin_power_state(codec, 0x2b, &parm);
 +      snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* PW0 (24h), AOW0 (8h) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x24, &parm);
 +      if (!spec->hp_independent_mode) /* check for redirected HP */
 +              set_pin_power_state(codec, 0x28, &parm);
 +      snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm);
 +      /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
 +      snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
 +                          imux_is_smixer ? AC_PWRST_D0 : parm);
 +
 +      /* PW1 (25h), AOW1 (9h) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x25, &parm);
 +      if (spec->smart51_enabled)
 +              set_pin_power_state(codec, 0x2a, &parm);
 +      snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      if (spec->hp_independent_mode) {
 +              /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */
 +              parm = AC_PWRST_D3;
 +              set_pin_power_state(codec, 0x28, &parm);
 +              snd_hda_codec_write(codec, 0x1b, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +              snd_hda_codec_write(codec, 0x34, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +              snd_hda_codec_write(codec, 0xc, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +      }
 +}
 +
  static int patch_vt1718S(struct hda_codec *codec)
  {
        struct via_spec *spec;
        spec->loopback.amplist = vt1718S_loopbacks;
  #endif
  
 +      spec->set_widgets_power_state =  set_widgets_power_state_vt1718S;
 +
        return 0;
  }
  
@@@ -4739,7 -4929,8 +4743,7 @@@ static int vt1716s_dmic_put(struct snd_
        snd_hda_codec_write(codec, 0x26, 0,
                                               AC_VERB_SET_CONNECT_SEL, index);
        spec->dmic_enabled = index;
 -      set_jack_power_state(codec);
 -
 +      set_widgets_power_state(codec);
        return 1;
  }
  
@@@ -5098,99 -5289,6 +5102,99 @@@ static struct hda_amp_list vt1716S_loop
  };
  #endif
  
 +static void set_widgets_power_state_vt1716S(struct hda_codec *codec)
 +{
 +      struct via_spec *spec = codec->spec;
 +      int imux_is_smixer;
 +      unsigned int parm;
 +      unsigned int mono_out, present;
 +      /* SW0 (17h) = stereo mixer */
 +      imux_is_smixer =
 +      (snd_hda_codec_read(codec, 0x17, 0,
 +                          AC_VERB_GET_CONNECT_SEL, 0x00) ==  5);
 +      /* inputs */
 +      /* PW 1/2/5 (1ah/1bh/1eh) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x1a, &parm);
 +      set_pin_power_state(codec, 0x1b, &parm);
 +      set_pin_power_state(codec, 0x1e, &parm);
 +      if (imux_is_smixer)
 +              parm = AC_PWRST_D0;
 +      /* SW0 (17h), AIW0(13h) */
 +      snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x1e, &parm);
 +      /* PW11 (22h) */
 +      if (spec->dmic_enabled)
 +              set_pin_power_state(codec, 0x22, &parm);
 +      else
 +              snd_hda_codec_write(codec, 0x22, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 +
 +      /* SW2(26h), AIW1(14h) */
 +      snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* outputs */
 +      /* PW0 (19h), SW1 (18h), AOW1 (11h) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x19, &parm);
 +      /* Smart 5.1 PW2(1bh) */
 +      if (spec->smart51_enabled)
 +              set_pin_power_state(codec, 0x1b, &parm);
 +      snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* PW7 (23h), SW3 (27h), AOW3 (25h) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x23, &parm);
 +      /* Smart 5.1 PW1(1ah) */
 +      if (spec->smart51_enabled)
 +              set_pin_power_state(codec, 0x1a, &parm);
 +      snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* Smart 5.1 PW5(1eh) */
 +      if (spec->smart51_enabled)
 +              set_pin_power_state(codec, 0x1e, &parm);
 +      snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* Mono out */
 +      /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/
 +      present = snd_hda_jack_detect(codec, 0x1c);
 +
 +      if (present)
 +              mono_out = 0;
 +      else {
 +              present = snd_hda_jack_detect(codec, 0x1d);
 +              if (!spec->hp_independent_mode && present)
 +                      mono_out = 0;
 +              else
 +                      mono_out = 1;
 +      }
 +      parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3;
 +      snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* PW 3/4 (1ch/1dh) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x1c, &parm);
 +      set_pin_power_state(codec, 0x1d, &parm);
 +      /* HP Independent Mode, power on AOW3 */
 +      if (spec->hp_independent_mode)
 +              snd_hda_codec_write(codec, 0x25, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* force to D0 for internal Speaker */
 +      /* MW0 (16h), AOW0 (10h) */
 +      snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE,
 +                          imux_is_smixer ? AC_PWRST_D0 : parm);
 +      snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE,
 +                          mono_out ? AC_PWRST_D0 : parm);
 +}
 +
  static int patch_vt1716S(struct hda_codec *codec)
  {
        struct via_spec *spec;
        spec->loopback.amplist = vt1716S_loopbacks;
  #endif
  
 +      spec->set_widgets_power_state = set_widgets_power_state_vt1716S;
        return 0;
  }
  
@@@ -5276,10 -5373,6 +5280,10 @@@ static struct snd_kcontrol_new vt2002P_
  };
  
  static struct hda_verb vt2002P_volume_init_verbs[] = {
 +      /* Class-D speaker related verbs */
 +      {0x1, 0xfe0, 0x4},
 +      {0x1, 0xfe9, 0x80},
 +      {0x1, 0xfe2, 0x22},
        /*
         * Unmute ADC0-1 and set the default input to mic-in
         */
        {0x1, 0xfb8, 0x88},
        { }
  };
 +static struct hda_verb vt1802_volume_init_verbs[] = {
 +      /*
 +       * Unmute ADC0-1 and set the default input to mic-in
 +       */
 +      {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 +      {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 +
 +
 +      /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
 +       * mixer widget
 +       */
 +      /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
 +      {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 +      {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
 +      {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
 +      {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
 +      {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
 +
 +      /* MUX Indices: Mic = 0 */
 +      {0x1e, AC_VERB_SET_CONNECT_SEL, 0},
 +      {0x1f, AC_VERB_SET_CONNECT_SEL, 0},
 +
 +      /* PW9 Output enable */
 +      {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN},
 +
 +      /* Enable Boost Volume backdoor */
 +      {0x1, 0xfb9, 0x24},
 +
 +      /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */
 +      {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 +      {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 +      {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 +      {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
 +      {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 +      {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 +      {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 +      {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
 +
 +      /* set MUX0/1/4/8 = 0 (AOW0) */
 +      {0x34, AC_VERB_SET_CONNECT_SEL, 0},
 +      {0x35, AC_VERB_SET_CONNECT_SEL, 0},
 +      {0x38, AC_VERB_SET_CONNECT_SEL, 0},
 +      {0x3c, AC_VERB_SET_CONNECT_SEL, 0},
 +
 +      /* set PW0 index=0 (MW0) */
 +      {0x24, AC_VERB_SET_CONNECT_SEL, 0},
 +
 +      /* Enable AOW0 to MW9 */
 +      {0x1, 0xfb8, 0x88},
 +      { }
 +};
  
  
  static struct hda_verb vt2002P_uniwill_init_verbs[] = {
        {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
        { }
  };
 +static struct hda_verb vt1802_uniwill_init_verbs[] = {
 +      {0x25, AC_VERB_SET_UNSOLICITED_ENABLE,
 +       AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
 +      {0x28, AC_VERB_SET_UNSOLICITED_ENABLE,
 +       AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT},
 +      {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 +      {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 +      {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT},
 +      { }
 +};
  
  static struct hda_pcm_stream vt2002P_pcm_analog_playback = {
        .substreams = 2,
@@@ -5459,15 -5491,10 +5463,15 @@@ static int vt2002P_auto_create_multi_ou
                                             const struct auto_pin_cfg *cfg)
  {
        int err;
 +      hda_nid_t sw_nid;
  
        if (!cfg->line_out_pins[0])
                return -1;
  
 +      if (spec->codec_type == VT1802)
 +              sw_nid = 0x28;
 +      else
 +              sw_nid = 0x26;
  
        /* Line-Out: PortE */
        err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
                return err;
        err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE,
                              "Master Front Playback Switch",
 -                            HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT));
 +                            HDA_COMPOSE_AMP_VAL(sw_nid, 3, 0, HDA_OUTPUT));
        if (err < 0)
                return err;
  
@@@ -5586,116 -5613,6 +5590,116 @@@ static struct hda_amp_list vt2002P_loop
  };
  #endif
  
 +static void set_widgets_power_state_vt2002P(struct hda_codec *codec)
 +{
 +      struct via_spec *spec = codec->spec;
 +      int imux_is_smixer;
 +      unsigned int parm;
 +      unsigned int present;
 +      /* MUX9 (1eh) = stereo mixer */
 +      imux_is_smixer =
 +      snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
 +      /* inputs */
 +      /* PW 5/6/7 (29h/2ah/2bh) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x29, &parm);
 +      set_pin_power_state(codec, 0x2a, &parm);
 +      set_pin_power_state(codec, 0x2b, &parm);
 +      parm = AC_PWRST_D0;
 +      /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */
 +      snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* outputs */
 +      /* AOW0 (8h)*/
 +      snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      if (spec->codec_type == VT1802) {
 +              /* PW4 (28h), MW4 (18h), MUX4(38h) */
 +              parm = AC_PWRST_D3;
 +              set_pin_power_state(codec, 0x28, &parm);
 +              snd_hda_codec_write(codec, 0x18, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +              snd_hda_codec_write(codec, 0x38, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +      } else {
 +              /* PW4 (26h), MW4 (1ch), MUX4(37h) */
 +              parm = AC_PWRST_D3;
 +              set_pin_power_state(codec, 0x26, &parm);
 +              snd_hda_codec_write(codec, 0x1c, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +              snd_hda_codec_write(codec, 0x37, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +      }
 +
 +      if (spec->codec_type == VT1802) {
 +              /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
 +              parm = AC_PWRST_D3;
 +              set_pin_power_state(codec, 0x25, &parm);
 +              snd_hda_codec_write(codec, 0x15, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +              snd_hda_codec_write(codec, 0x35, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +      } else {
 +              /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */
 +              parm = AC_PWRST_D3;
 +              set_pin_power_state(codec, 0x25, &parm);
 +              snd_hda_codec_write(codec, 0x19, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +              snd_hda_codec_write(codec, 0x35, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +      }
 +
 +      if (spec->hp_independent_mode)
 +              snd_hda_codec_write(codec, 0x9, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 +
 +      /* Class-D */
 +      /* PW0 (24h), MW0(18h/14h), MUX0(34h) */
 +      present = snd_hda_jack_detect(codec, 0x25);
 +
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x24, &parm);
 +      parm = present ? AC_PWRST_D3 : AC_PWRST_D0;
 +      if (spec->codec_type == VT1802)
 +              snd_hda_codec_write(codec, 0x14, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +      else
 +              snd_hda_codec_write(codec, 0x18, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* Mono Out */
 +      present = snd_hda_jack_detect(codec, 0x26);
 +
 +      parm = present ? AC_PWRST_D3 : AC_PWRST_D0;
 +      if (spec->codec_type == VT1802) {
 +              /* PW15 (33h), MW8(1ch), MUX8(3ch) */
 +              snd_hda_codec_write(codec, 0x33, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +              snd_hda_codec_write(codec, 0x1c, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +              snd_hda_codec_write(codec, 0x3c, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +      } else {
 +              /* PW15 (31h), MW8(17h), MUX8(3bh) */
 +              snd_hda_codec_write(codec, 0x31, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +              snd_hda_codec_write(codec, 0x17, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +              snd_hda_codec_write(codec, 0x3b, 0,
 +                                  AC_VERB_SET_POWER_STATE, parm);
 +      }
 +      /* MW9 (21h) */
 +      if (imux_is_smixer || !is_aa_path_mute(codec))
 +              snd_hda_codec_write(codec, 0x21, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 +      else
 +              snd_hda_codec_write(codec, 0x21, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 +}
  
  /* patch for vt2002P */
  static int patch_vt2002P(struct hda_codec *codec)
                       "from BIOS.  Using genenic mode...\n");
        }
  
 -      spec->init_verbs[spec->num_iverbs++]  = vt2002P_volume_init_verbs;
 -      spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs;
 +      if (spec->codec_type == VT1802)
 +              spec->init_verbs[spec->num_iverbs++]  =
 +                      vt1802_volume_init_verbs;
 +      else
 +              spec->init_verbs[spec->num_iverbs++]  =
 +                      vt2002P_volume_init_verbs;
 +
 +      if (spec->codec_type == VT1802)
 +              spec->init_verbs[spec->num_iverbs++] =
 +                      vt1802_uniwill_init_verbs;
 +      else
 +              spec->init_verbs[spec->num_iverbs++] =
 +                      vt2002P_uniwill_init_verbs;
  
 -      spec->stream_name_analog = "VT2002P Analog";
 +      if (spec->codec_type == VT1802)
 +              spec->stream_name_analog = "VT1802 Analog";
 +      else
 +              spec->stream_name_analog = "VT2002P Analog";
        spec->stream_analog_playback = &vt2002P_pcm_analog_playback;
        spec->stream_analog_capture = &vt2002P_pcm_analog_capture;
  
 -      spec->stream_name_digital = "VT2002P Digital";
 +      if (spec->codec_type == VT1802)
 +              spec->stream_name_digital = "VT1802 Digital";
 +      else
 +              spec->stream_name_digital = "VT2002P Digital";
        spec->stream_digital_playback = &vt2002P_pcm_digital_playback;
  
        if (!spec->adc_nids && spec->input_mux) {
        spec->loopback.amplist = vt2002P_loopbacks;
  #endif
  
 +      spec->set_widgets_power_state =  set_widgets_power_state_vt2002P;
        return 0;
  }
  
@@@ -6036,97 -5935,6 +6040,97 @@@ static struct hda_amp_list vt1812_loopb
  };
  #endif
  
 +static void set_widgets_power_state_vt1812(struct hda_codec *codec)
 +{
 +      struct via_spec *spec = codec->spec;
 +      int imux_is_smixer =
 +      snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3;
 +      unsigned int parm;
 +      unsigned int present;
 +      /* MUX10 (1eh) = stereo mixer */
 +      imux_is_smixer =
 +      snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
 +      /* inputs */
 +      /* PW 5/6/7 (29h/2ah/2bh) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x29, &parm);
 +      set_pin_power_state(codec, 0x2a, &parm);
 +      set_pin_power_state(codec, 0x2b, &parm);
 +      parm = AC_PWRST_D0;
 +      /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */
 +      snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* outputs */
 +      /* AOW0 (8h)*/
 +      snd_hda_codec_write(codec, 0x8, 0,
 +                          AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 +
 +      /* PW4 (28h), MW4 (18h), MUX4(38h) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x28, &parm);
 +      snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x38, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +      /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x25, &parm);
 +      snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x35, 0, AC_VERB_SET_POWER_STATE, parm);
 +      if (spec->hp_independent_mode)
 +              snd_hda_codec_write(codec, 0x9, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 +
 +      /* Internal Speaker */
 +      /* PW0 (24h), MW0(14h), MUX0(34h) */
 +      present = snd_hda_jack_detect(codec, 0x25);
 +
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x24, &parm);
 +      if (present) {
 +              snd_hda_codec_write(codec, 0x14, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 +              snd_hda_codec_write(codec, 0x34, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 +      } else {
 +              snd_hda_codec_write(codec, 0x14, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 +              snd_hda_codec_write(codec, 0x34, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 +      }
 +
 +
 +      /* Mono Out */
 +      /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */
 +      present = snd_hda_jack_detect(codec, 0x28);
 +
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x31, &parm);
 +      if (present) {
 +              snd_hda_codec_write(codec, 0x1c, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 +              snd_hda_codec_write(codec, 0x3c, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 +              snd_hda_codec_write(codec, 0x3e, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
 +      } else {
 +              snd_hda_codec_write(codec, 0x1c, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 +              snd_hda_codec_write(codec, 0x3c, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 +              snd_hda_codec_write(codec, 0x3e, 0,
 +                                  AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
 +      }
 +
 +      /* PW15 (33h), MW15 (1dh), MUX15(3dh) */
 +      parm = AC_PWRST_D3;
 +      set_pin_power_state(codec, 0x33, &parm);
 +      snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, parm);
 +      snd_hda_codec_write(codec, 0x3d, 0, AC_VERB_SET_POWER_STATE, parm);
 +
 +}
  
  /* patch for vt1812 */
  static int patch_vt1812(struct hda_codec *codec)
        spec->loopback.amplist = vt1812_loopbacks;
  #endif
  
 +      spec->set_widgets_power_state =  set_widgets_power_state_vt1812;
        return 0;
  }
  
@@@ -6232,7 -6039,7 +6236,7 @@@ static struct hda_codec_preset snd_hda_
          .patch = patch_vt1708S},
        { .id = 0x11063397, .name = "VT1708S",
          .patch = patch_vt1708S},
 -      { .id = 0x11064397, .name = "VT1708S",
 +      { .id = 0x11064397, .name = "VT1705",
          .patch = patch_vt1708S},
        { .id = 0x11065397, .name = "VT1708S",
          .patch = patch_vt1708S},
        { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812},
        { .id = 0x11060440, .name = "VT1818S",
          .patch = patch_vt1708S},
 +      { .id = 0x11060446, .name = "VT1802",
 +              .patch = patch_vt2002P},
 +      { .id = 0x11068446, .name = "VT1802",
 +              .patch = patch_vt2002P},
        {} /* terminator */
  };