]> git.openfabrics.org - ~shefty/rdma-dev.git/commitdiff
Merge branch 'fix/hda' into topic/hda
authorTakashi Iwai <tiwai@suse.de>
Wed, 8 Sep 2010 06:42:26 +0000 (08:42 +0200)
committerTakashi Iwai <tiwai@suse.de>
Wed, 8 Sep 2010 06:42:26 +0000 (08:42 +0200)
1  2 
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_realtek.c

index ee1aea7296eb261bf1e85226c86b965304536160,488fd9ade1ba2bf7b306bf6e48ae106ef823294b..6adfc562528100e11465995d0283e8fd5a031470
@@@ -329,7 -329,7 +329,7 @@@ static int is_ext_mic(struct hda_codec 
  {
        struct cs_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
 -      hda_nid_t pin = cfg->input_pins[idx];
 +      hda_nid_t pin = cfg->inputs[idx].pin;
        unsigned int val = snd_hda_query_pin_caps(codec, pin);
        if (!(val & AC_PINCAP_PRES_DETECT))
                return 0;
@@@ -424,8 -424,10 +424,8 @@@ static int parse_input(struct hda_code
        struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
  
 -      for (i = 0; i < AUTO_PIN_LAST; i++) {
 -              hda_nid_t pin = cfg->input_pins[i];
 -              if (!pin)
 -                      continue;
 +      for (i = 0; i < cfg->num_inputs; i++) {
 +              hda_nid_t pin = cfg->inputs[i].pin;
                spec->input_idx[spec->num_inputs] = i;
                spec->capsrc_idx[i] = spec->num_inputs++;
                spec->cur_input = i;
  
        /* check whether the automatic mic switch is available */
        if (spec->num_inputs == 2 &&
 -          spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) {
 -              if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) {
 -                      if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
 +          cfg->inputs[0].type <= AUTO_PIN_FRONT_MIC &&
 +          cfg->inputs[1].type == AUTO_PIN_FRONT_MIC) {
 +              if (is_ext_mic(codec, cfg->inputs[0].pin)) {
 +                      if (!is_ext_mic(codec, cfg->inputs[1].pin)) {
                                spec->mic_detect = 1;
 -                              spec->automic_idx = AUTO_PIN_FRONT_MIC;
 +                              spec->automic_idx = 0;
                        }
                } else {
 -                      if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
 +                      if (is_ext_mic(codec, cfg->inputs[1].pin)) {
                                spec->mic_detect = 1;
 -                              spec->automic_idx = AUTO_PIN_MIC;
 +                              spec->automic_idx = 1;
                        }
                }
        }
@@@ -852,12 -853,15 +852,12 @@@ static void cs_automic(struct hda_code
        hda_nid_t nid;
        unsigned int present;
        
 -      nid = cfg->input_pins[spec->automic_idx];
 +      nid = cfg->inputs[spec->automic_idx].pin;
        present = snd_hda_jack_detect(codec, nid);
        if (present)
                change_cur_input(codec, spec->automic_idx, 0);
 -      else {
 -              unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ?
 -                      AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC;
 -              change_cur_input(codec, imic, 0);
 -      }
 +      else
 +              change_cur_input(codec, !spec->automic_idx, 0);
  }
  
  /*
@@@ -914,14 -918,14 +914,14 @@@ static void init_input(struct hda_code
        unsigned int coef;
        int i;
  
 -      for (i = 0; i < AUTO_PIN_LAST; i++) {
 +      for (i = 0; i < cfg->num_inputs; i++) {
                unsigned int ctl;
 -              hda_nid_t pin = cfg->input_pins[i];
 -              if (!pin || !spec->adc_nid[i])
 +              hda_nid_t pin = cfg->inputs[i].pin;
 +              if (!spec->adc_nid[i])
                        continue;
                /* set appropriate pin control and mute first */
                ctl = PIN_IN;
 -              if (i <= AUTO_PIN_FRONT_MIC) {
 +              if (cfg->inputs[i].type <= AUTO_PIN_FRONT_MIC) {
                        unsigned int caps = snd_hda_query_pin_caps(codec, pin);
                        caps >>= AC_PINCAP_VREF_SHIFT;
                        if (caps & AC_PINCAP_VREF_80)
@@@ -968,6 -972,53 +968,53 @@@ static struct hda_verb cs_coef_init_ver
        {} /* terminator */
  };
  
+ /* Errata: CS4207 rev C0/C1/C2 Silicon
+  *
+  * http://www.cirrus.com/en/pubs/errata/ER880C3.pdf
+  *
+  * 6. At high temperature (TA > +85°C), the digital supply current (IVD)
+  * may be excessive (up to an additional 200 μA), which is most easily
+  * observed while the part is being held in reset (RESET# active low).
+  *
+  * Root Cause: At initial powerup of the device, the logic that drives
+  * the clock and write enable to the S/PDIF SRC RAMs is not properly
+  * initialized.
+  * Certain random patterns will cause a steady leakage current in those
+  * RAM cells. The issue will resolve once the SRCs are used (turned on).
+  *
+  * Workaround: The following verb sequence briefly turns on the S/PDIF SRC
+  * blocks, which will alleviate the issue.
+  */
+ static struct hda_verb cs_errata_init_verbs[] = {
+       {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */
+       {0x11, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
+       {0x11, AC_VERB_SET_COEF_INDEX, 0x0008},
+       {0x11, AC_VERB_SET_PROC_COEF, 0x9999},
+       {0x11, AC_VERB_SET_COEF_INDEX, 0x0017},
+       {0x11, AC_VERB_SET_PROC_COEF, 0xa412},
+       {0x11, AC_VERB_SET_COEF_INDEX, 0x0001},
+       {0x11, AC_VERB_SET_PROC_COEF, 0x0009},
+       {0x07, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Rx: D0 */
+       {0x08, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Tx: D0 */
+       {0x11, AC_VERB_SET_COEF_INDEX, 0x0017},
+       {0x11, AC_VERB_SET_PROC_COEF, 0x2412},
+       {0x11, AC_VERB_SET_COEF_INDEX, 0x0008},
+       {0x11, AC_VERB_SET_PROC_COEF, 0x0000},
+       {0x11, AC_VERB_SET_COEF_INDEX, 0x0001},
+       {0x11, AC_VERB_SET_PROC_COEF, 0x0008},
+       {0x11, AC_VERB_SET_PROC_STATE, 0x00},
+       {0x07, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Rx: D3 */
+       {0x08, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Tx: D3 */
+       /*{0x01, AC_VERB_SET_POWER_STATE, 0x03},*/ /* AFG: D3 This is already handled */
+       {} /* terminator */
+ };
  /* SPDIF setup */
  static void init_digital(struct hda_codec *codec)
  {
@@@ -987,6 -1038,9 +1034,9 @@@ static int cs_init(struct hda_codec *co
  {
        struct cs_spec *spec = codec->spec;
  
+       /* init_verb sequence for C0/C1/C2 errata*/
+       snd_hda_sequence_write(codec, cs_errata_init_verbs);
        snd_hda_sequence_write(codec, cs_coef_init_verbs);
  
        if (spec->gpio_mask) {
index 3e0f4816aed786006550d64db10d136046e75b0b,bcbf9160ed81af7a805007f152067908f9970840..81e4b1d957c5236c155c518d01e5d2e439d3fa35
@@@ -1265,14 -1265,16 +1265,14 @@@ static void alc_init_auto_mic(struct hd
        int i;
  
        /* there must be only two mic inputs exclusively */
 -      for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++)
 -              if (cfg->input_pins[i])
 +      for (i = 0; i < cfg->num_inputs; i++)
 +              if (cfg->inputs[i].type >= AUTO_PIN_LINE)
                        return;
  
        fixed = ext = 0;
 -      for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) {
 -              hda_nid_t nid = cfg->input_pins[i];
 +      for (i = 0; i < cfg->num_inputs; i++) {
 +              hda_nid_t nid = cfg->inputs[i].pin;
                unsigned int defcfg;
 -              if (!nid)
 -                      return;
                defcfg = snd_hda_codec_get_pincfg(codec, nid);
                switch (get_defcfg_connect(defcfg)) {
                case AC_JACK_PORT_FIXED:
@@@ -4717,7 -4719,7 +4717,7 @@@ static struct snd_kcontrol_new alc880_c
  
  /* add dynamic controls */
  static int add_control(struct alc_spec *spec, int type, const char *name,
 -                     unsigned long val)
 +                     int cidx, unsigned long val)
  {
        struct snd_kcontrol_new *knew;
  
        knew->name = kstrdup(name, GFP_KERNEL);
        if (!knew->name)
                return -ENOMEM;
 +      knew->index = cidx;
        if (get_amp_nid_(val))
                knew->subdevice = HDA_SUBDEV_AMP_FLAG;
        knew->private_value = val;
  
  static int add_control_with_pfx(struct alc_spec *spec, int type,
                                const char *pfx, const char *dir,
 -                              const char *sfx, unsigned long val)
 +                              const char *sfx, int cidx, unsigned long val)
  {
        char name[32];
        snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
 -      return add_control(spec, type, name, val);
 +      return add_control(spec, type, name, cidx, val);
  }
  
 -#define add_pb_vol_ctrl(spec, type, pfx, val) \
 -      add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val)
 -#define add_pb_sw_ctrl(spec, type, pfx, val) \
 -      add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val)
 +#define add_pb_vol_ctrl(spec, type, pfx, val)                 \
 +      add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
 +#define add_pb_sw_ctrl(spec, type, pfx, val)                  \
 +      add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
 +#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val)                 \
 +      add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
 +#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val)                  \
 +      add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
  
  #define alc880_is_fixed_pin(nid)      ((nid) >= 0x14 && (nid) <= 0x17)
  #define alc880_fixed_pin_idx(nid)     ((nid) - 0x14)
@@@ -4905,16 -4902,16 +4905,16 @@@ static int alc880_auto_create_extra_out
  
  /* create input playback/capture controls for the given pin */
  static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
 -                          const char *ctlname,
 +                          const char *ctlname, int ctlidx,
                            int idx, hda_nid_t mix_nid)
  {
        int err;
  
 -      err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
 +      err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
                          HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
 -      err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
 +      err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
                          HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
@@@ -4935,26 -4932,21 +4935,26 @@@ static int alc_auto_create_input_ctls(s
  {
        struct alc_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux[0];
 -      int i, err, idx;
 +      int i, err, idx, type, type_idx = 0;
  
 -      for (i = 0; i < AUTO_PIN_LAST; i++) {
 +      for (i = 0; i < cfg->num_inputs; i++) {
                hda_nid_t pin;
  
 -              pin = cfg->input_pins[i];
 +              pin = cfg->inputs[i].pin;
                if (!alc_is_input_pin(codec, pin))
                        continue;
  
 +              type = cfg->inputs[i].type;
 +              if (i > 0 && type == cfg->inputs[i - 1].type)
 +                      type_idx++;
 +              else
 +                      type_idx = 0;
                if (mixer) {
                        idx = get_connection_index(codec, mixer, pin);
                        if (idx >= 0) {
                                err = new_analog_input(spec, pin,
 -                                                     auto_pin_cfg_labels[i],
 -                                                     idx, mixer);
 +                                                     auto_pin_cfg_labels[type],
 +                                                     type_idx, idx, mixer);
                                if (err < 0)
                                        return err;
                        }
                        idx = get_connection_index(codec, cap2, pin);
                if (idx >= 0) {
                        imux->items[imux->num_items].label =
 -                              auto_pin_cfg_labels[i];
 +                              snd_hda_get_input_pin_label(cfg, i);
                        imux->items[imux->num_items].index = idx;
                        imux->num_items++;
                }
@@@ -5042,11 -5034,10 +5042,11 @@@ static void alc880_auto_init_extra_out(
  static void alc880_auto_init_analog_input(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
  
 -      for (i = 0; i < AUTO_PIN_LAST; i++) {
 -              hda_nid_t nid = spec->autocfg.input_pins[i];
 +      for (i = 0; i < cfg->num_inputs; i++) {
 +              hda_nid_t nid = cfg->inputs[i].pin;
                if (alc_is_input_pin(codec, nid)) {
                        alc_set_input_pin(codec, nid, i);
                        if (nid != ALC880_PIN_CD_NID &&
@@@ -5213,13 -5204,19 +5213,13 @@@ static int init_capsrc_for_pin(struct h
  static void fixup_single_adc(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 -      hda_nid_t pin = 0;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
  
        /* search for the input pin; there must be only one */
 -      for (i = 0; i < AUTO_PIN_LAST; i++) {
 -              if (spec->autocfg.input_pins[i]) {
 -                      pin = spec->autocfg.input_pins[i];
 -                      break;
 -              }
 -      }
 -      if (!pin)
 +      if (cfg->num_inputs != 1)
                return;
 -      i = init_capsrc_for_pin(codec, pin);
 +      i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
        if (i >= 0) {
                /* use only this ADC */
                if (spec->capsrc_nids)
@@@ -5272,7 -5269,6 +5272,7 @@@ static void fillup_priv_adc_nids(struc
                                 int num_nids)
  {
        struct alc_spec *spec = codec->spec;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
        int n;
        hda_nid_t fallback_adc = 0, fallback_cap = 0;
  
                        fallback_adc = adc;
                        fallback_cap = cap;
                }
 -              for (i = 0; i < AUTO_PIN_LAST; i++) {
 -                      hda_nid_t nid = spec->autocfg.input_pins[i];
 -                      if (!nid)
 -                              continue;
 +              for (i = 0; i < cfg->num_inputs; i++) {
 +                      hda_nid_t nid = cfg->inputs[i].pin;
                        for (j = 0; j < nconns; j++) {
                                if (conn[j] == nid)
                                        break;
                        if (j >= nconns)
                                break;
                }
 -              if (i >= AUTO_PIN_LAST) {
 +              if (i >= cfg->num_inputs) {
                        int num_adcs = spec->num_adc_nids;
                        spec->private_adc_nids[num_adcs] = adc;
                        spec->private_capsrc_nids[num_adcs] = cap;
  
  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(0x8086, 0xd613, "Intel", 1),
        {}
  };
@@@ -6674,11 -6673,10 +6675,11 @@@ static void alc260_auto_init_multi_out(
  static void alc260_auto_init_analog_input(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
  
 -      for (i = 0; i < AUTO_PIN_LAST; i++) {
 -              hda_nid_t nid = spec->autocfg.input_pins[i];
 +      for (i = 0; i < cfg->num_inputs; i++) {
 +              hda_nid_t nid = cfg->inputs[i].pin;
                if (nid >= 0x12) {
                        alc_set_input_pin(codec, nid, i);
                        if (nid != ALC260_PIN_CD_NID &&
@@@ -6802,12 -6800,14 +6803,12 @@@ enum 
        PINFIX_HP_DC5750,
  };
  
 -static struct alc_pincfg alc260_hp_dc5750_pinfix[] = {
 -      { 0x11, 0x90130110 }, /* speaker */
 -      { }
 -};
 -
  static const struct alc_fixup alc260_fixups[] = {
        [PINFIX_HP_DC5750] = {
 -              .pins = alc260_hp_dc5750_pinfix
 +              .pins = (const struct alc_pincfg[]) {
 +                      { 0x11, 0x90130110 }, /* speaker */
 +                      { }
 +              }
        },
  };
  
@@@ -10453,20 -10453,24 +10454,20 @@@ enum 
        PINFIX_PB_M5210,
  };
  
 -static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
 -      { 0x15, 0x01080104 }, /* side */
 -      { 0x16, 0x01011012 }, /* rear */
 -      { 0x17, 0x01016011 }, /* clfe */
 -      { }
 -};
 -
 -static const struct hda_verb pb_m5210_verbs[] = {
 -      { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
 -      {}
 -};
 -
  static const struct alc_fixup alc882_fixups[] = {
        [PINFIX_ABIT_AW9D_MAX] = {
 -              .pins = alc882_abit_aw9d_pinfix
 +              .pins = (const struct alc_pincfg[]) {
 +                      { 0x15, 0x01080104 }, /* side */
 +                      { 0x16, 0x01011012 }, /* rear */
 +                      { 0x17, 0x01016011 }, /* clfe */
 +                      { }
 +              }
        },
        [PINFIX_PB_M5210] = {
 -              .verbs = pb_m5210_verbs
 +              .verbs = (const struct hda_verb[]) {
 +                      { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
 +                      {}
 +              }
        },
  };
  
@@@ -10541,11 -10545,12 +10542,11 @@@ static void alc882_auto_init_hp_out(str
  static void alc882_auto_init_analog_input(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
  
 -      for (i = 0; i < AUTO_PIN_LAST; i++) {
 -              hda_nid_t nid = spec->autocfg.input_pins[i];
 -              if (!nid)
 -                      continue;
 +      for (i = 0; i < cfg->num_inputs; i++) {
 +              hda_nid_t nid = cfg->inputs[i].pin;
                alc_set_input_pin(codec, nid, i);
                if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
                        snd_hda_codec_write(codec, nid, 0,
@@@ -10608,23 -10613,24 +10609,23 @@@ static void alc882_auto_init_input_src(
  static int alc_auto_add_mic_boost(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 -      int err;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
 +      int i, err;
        hda_nid_t nid;
  
 -      nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
 -      if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
 -              err = add_control(spec, ALC_CTL_WIDGET_VOL,
 -                                "Mic Boost",
 -                                HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
 -              if (err < 0)
 -                      return err;
 -      }
 -      nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
 -      if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
 -              err = add_control(spec, ALC_CTL_WIDGET_VOL,
 -                                "Front Mic Boost",
 +      for (i = 0; i < cfg->num_inputs; i++) {
 +              if (cfg->inputs[i].type > AUTO_PIN_FRONT_MIC)
 +                      break;
 +              nid = cfg->inputs[i].pin;
 +              if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
 +                      char label[32];
 +                      snprintf(label, sizeof(label), "%s Boost",
 +                               snd_hda_get_input_pin_label(cfg, i));
 +                      err = add_control(spec, ALC_CTL_WIDGET_VOL, label, 0,
                                  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
 -              if (err < 0)
 -                      return err;
 +                      if (err < 0)
 +                              return err;
 +              }
        }
        return 0;
  }
@@@ -14449,12 -14455,14 +14450,12 @@@ enum 
        ALC269_FIXUP_SONY_VAIO,
  };
  
 -static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = {
 -      {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
 -      {}
 -};
 -
  static const struct alc_fixup alc269_fixups[] = {
        [ALC269_FIXUP_SONY_VAIO] = {
 -              .verbs = alc269_sony_vaio_fixup_verbs
 +              .verbs = (const struct hda_verb[]) {
 +                      {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
 +                      {}
 +              }
        },
  };
  
@@@ -15578,11 -15586,10 +15579,11 @@@ static void alc861_auto_init_hp_out(str
  static void alc861_auto_init_analog_input(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
  
 -      for (i = 0; i < AUTO_PIN_LAST; i++) {
 -              hda_nid_t nid = spec->autocfg.input_pins[i];
 +      for (i = 0; i < cfg->num_inputs; i++) {
 +              hda_nid_t nid = cfg->inputs[i].pin;
                if (nid >= 0x0c && nid <= 0x11)
                        alc_set_input_pin(codec, nid, i);
        }
@@@ -15813,13 -15820,15 +15814,13 @@@ enum 
        PINFIX_FSC_AMILO_PI1505,
  };
  
 -static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
 -      { 0x0b, 0x0221101f }, /* HP */
 -      { 0x0f, 0x90170310 }, /* speaker */
 -      { }
 -};
 -
  static const struct alc_fixup alc861_fixups[] = {
        [PINFIX_FSC_AMILO_PI1505] = {
 -              .pins = alc861_fsc_amilo_pi1505_pinfix
 +              .pins = (const struct alc_pincfg[]) {
 +                      { 0x0b, 0x0221101f }, /* HP */
 +                      { 0x0f, 0x90170310 }, /* speaker */
 +                      { }
 +              }
        },
  };
  
@@@ -16571,11 -16580,10 +16572,11 @@@ static void alc861vd_auto_init_hp_out(s
  static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
  
 -      for (i = 0; i < AUTO_PIN_LAST; i++) {
 -              hda_nid_t nid = spec->autocfg.input_pins[i];
 +      for (i = 0; i < cfg->num_inputs; i++) {
 +              hda_nid_t nid = cfg->inputs[i].pin;
                if (alc_is_input_pin(codec, nid)) {
                        alc_set_input_pin(codec, nid, i);
                        if (nid != ALC861VD_PIN_CD_NID &&
@@@ -16787,14 -16795,16 +16788,14 @@@ enum 
  };
  
  /* reset GPIO1 */
 -static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
 -      {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
 -      {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
 -      {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
 -      { }
 -};
 -
  static const struct alc_fixup alc861vd_fixups[] = {
        [ALC660VD_FIX_ASUS_GPIO1] = {
 -              .verbs = alc660vd_fix_asus_gpio1_verbs,
 +              .verbs = (const struct hda_verb[]) {
 +                      {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
 +                      {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
 +                      {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
 +                      { }
 +              }
        },
  };
  
@@@ -18808,11 -18818,10 +18809,11 @@@ static void alc662_auto_init_hp_out(str
  static void alc662_auto_init_analog_input(struct hda_codec *codec)
  {
        struct alc_spec *spec = codec->spec;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
  
 -      for (i = 0; i < AUTO_PIN_LAST; i++) {
 -              hda_nid_t nid = spec->autocfg.input_pins[i];
 +      for (i = 0; i < cfg->num_inputs; i++) {
 +              hda_nid_t nid = cfg->inputs[i].pin;
                if (alc_is_input_pin(codec, nid)) {
                        alc_set_input_pin(codec, nid, i);
                        if (nid != ALC662_PIN_CD_NID &&
@@@ -19041,39 -19050,6 +19042,39 @@@ static hda_nid_t alc680_adc_nids[3] = 
  /*
   * Analog capture ADC cgange
   */
 +static void alc680_rec_autoswitch(struct hda_codec *codec)
 +{
 +      struct alc_spec *spec = codec->spec;
 +      struct auto_pin_cfg *cfg = &spec->autocfg;
 +      int pin_found = 0;
 +      int type_found = AUTO_PIN_LAST;
 +      hda_nid_t nid;
 +      int i;
 +
 +      for (i = 0; i < cfg->num_inputs; i++) {
 +              nid = cfg->inputs[i].pin;
 +              if (!(snd_hda_query_pin_caps(codec, nid) &
 +                    AC_PINCAP_PRES_DETECT))
 +                      continue;
 +              if (snd_hda_jack_detect(codec, nid)) {
 +                      if (cfg->inputs[i].type < type_found) {
 +                              type_found = cfg->inputs[i].type;
 +                              pin_found = nid;
 +                      }
 +              }
 +      }
 +
 +      nid = 0x07;
 +      if (pin_found)
 +              snd_hda_get_connections(codec, pin_found, &nid, 1);
 +
 +      if (nid != spec->cur_adc)
 +              __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
 +      spec->cur_adc = nid;
 +      snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
 +                                 spec->cur_adc_format);
 +}
 +
  static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
                                      struct hda_codec *codec,
                                      unsigned int stream_tag,
                                      struct snd_pcm_substream *substream)
  {
        struct alc_spec *spec = codec->spec;
 -      struct auto_pin_cfg *cfg = &spec->autocfg;
 -      unsigned int pre_mic, pre_line;
 -
 -      pre_mic  = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]);
 -      pre_line = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_LINE]);
  
 +      spec->cur_adc = 0x07;
        spec->cur_adc_stream_tag = stream_tag;
        spec->cur_adc_format = format;
  
 -      if (pre_mic || pre_line) {
 -              if (pre_mic)
 -                      snd_hda_codec_setup_stream(codec, 0x08, stream_tag, 0,
 -                                                                      format);
 -              else
 -                      snd_hda_codec_setup_stream(codec, 0x09, stream_tag, 0,
 -                                                                      format);
 -      } else
 -              snd_hda_codec_setup_stream(codec, 0x07, stream_tag, 0, format);
 +      alc680_rec_autoswitch(codec);
        return 0;
  }
  
@@@ -19172,7 -19160,6 +19173,7 @@@ static struct hda_verb alc680_init_verb
  
        {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT   | AC_USRSP_EN},
        {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT  | AC_USRSP_EN},
 +      {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT  | AC_USRSP_EN},
  
        { }
  };
@@@ -19185,11 -19172,25 +19186,11 @@@ static void alc680_base_setup(struct hd
        spec->autocfg.hp_pins[0] = 0x16;
        spec->autocfg.speaker_pins[0] = 0x14;
        spec->autocfg.speaker_pins[1] = 0x15;
 -      spec->autocfg.input_pins[AUTO_PIN_MIC] = 0x18;
 -      spec->autocfg.input_pins[AUTO_PIN_LINE] = 0x19;
 -}
 -
 -static void alc680_rec_autoswitch(struct hda_codec *codec)
 -{
 -      struct alc_spec *spec = codec->spec;
 -      struct auto_pin_cfg *cfg = &spec->autocfg;
 -      unsigned int present;
 -      hda_nid_t new_adc;
 -
 -      present = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]);
 -
 -      new_adc = present ? 0x8 : 0x7;
 -      __snd_hda_codec_cleanup_stream(codec, !present ? 0x8 : 0x7, 1);
 -      snd_hda_codec_setup_stream(codec, new_adc,
 -                                 spec->cur_adc_stream_tag, 0,
 -                                 spec->cur_adc_format);
 -
 +      spec->autocfg.num_inputs = 2;
 +      spec->autocfg.inputs[0].pin = 0x18;
 +      spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
 +      spec->autocfg.inputs[1].pin = 0x19;
 +      spec->autocfg.inputs[1].type = AUTO_PIN_LINE;
  }
  
  static void alc680_unsol_event(struct hda_codec *codec,