ALSA: hda - Fix duplicated DAC assignments for Realtek
[pandora-kernel.git] / sound / pci / hda / patch_realtek.c
index 8f1bd80..e125c60 100644 (file)
@@ -895,13 +895,15 @@ static void alc_init_auto_hp(struct hda_codec *codec)
        if (present == 3)
                spec->automute_hp_lo = 1; /* both HP and LO automute */
 
-       if (!cfg->speaker_pins[0]) {
+       if (!cfg->speaker_pins[0] &&
+           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
                memcpy(cfg->speaker_pins, cfg->line_out_pins,
                       sizeof(cfg->speaker_pins));
                cfg->speaker_outs = cfg->line_outs;
        }
 
-       if (!cfg->hp_pins[0]) {
+       if (!cfg->hp_pins[0] &&
+           cfg->line_out_type == AUTO_PIN_HP_OUT) {
                memcpy(cfg->hp_pins, cfg->line_out_pins,
                       sizeof(cfg->hp_pins));
                cfg->hp_outs = cfg->line_outs;
@@ -920,6 +922,7 @@ static void alc_init_auto_hp(struct hda_codec *codec)
                spec->automute_mode = ALC_AUTOMUTE_PIN;
        }
        if (spec->automute && cfg->line_out_pins[0] &&
+           cfg->speaker_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++) {
@@ -1338,11 +1341,11 @@ do_sku:
        return 1;
 }
 
-static void alc_ssid_check(struct hda_codec *codec,
-                          hda_nid_t porta, hda_nid_t porte,
-                          hda_nid_t portd, hda_nid_t porti)
+/* Check the validity of ALC subsystem-id
+ * ports contains an array of 4 pin NIDs for port-A, E, D and I */
+static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
 {
-       if (!alc_subsystem_id(codec, porta, porte, portd, porti)) {
+       if (!alc_subsystem_id(codec, ports[0], ports[1], ports[2], ports[3])) {
                struct alc_spec *spec = codec->spec;
                snd_printd("realtek: "
                           "Enable default setup for auto mode as fallback\n");
@@ -1911,7 +1914,7 @@ static int alc_build_controls(struct hda_codec *codec)
                                return err;
                }
        }
-       if (spec->cap_mixer) {
+       if (spec->cap_mixer && spec->adc_nids) {
                const char *kname = kctl ? kctl->id.name : NULL;
                for (knew = spec->cap_mixer; knew->name; knew++) {
                        if (kname && strcmp(knew->name, kname) == 0)
@@ -2386,7 +2389,7 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state)
 }
 #endif
 
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 static int alc_resume(struct hda_codec *codec)
 {
        msleep(150); /* to avoid pop noise */
@@ -2406,7 +2409,7 @@ static const struct hda_codec_ops alc_patch_ops = {
        .init = alc_init,
        .free = alc_free,
        .unsol_event = alc_unsol_event,
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
        .resume = alc_resume,
 #endif
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -2801,7 +2804,8 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
        int i;
 
  again:
-       spec->multiout.num_dacs = 0;
+       /* set num_dacs once to full for alc_auto_look_for_dac() */
+       spec->multiout.num_dacs = cfg->line_outs;
        spec->multiout.hp_nid = 0;
        spec->multiout.extra_out_nid[0] = 0;
        memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
@@ -2834,6 +2838,8 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
                }
        }
 
+       /* re-count num_dacs and squash invalid entries */
+       spec->multiout.num_dacs = 0;
        for (i = 0; i < cfg->line_outs; i++) {
                if (spec->private_dac_nids[i])
                        spec->multiout.num_dacs++;
@@ -3196,6 +3202,8 @@ static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
        for (i = 0; i < spec->multi_ios; i++)
                alc_set_multi_io(codec, i, i < ch);
        spec->multiout.max_channels = spec->ext_channel_count;
+       if (spec->need_dac_fix && !spec->const_channel_count)
+               spec->multiout.num_dacs = spec->multiout.max_channels / 2;
        return 1;
 }
 
@@ -3527,20 +3535,29 @@ static inline int has_cdefine_beep(struct hda_codec *codec)
 /* return 1 if successful, 0 if the proper config is not found,
  * or a negative error code
  */
-static int alc880_parse_auto_config(struct hda_codec *codec)
+static int alc_parse_auto_config(struct hda_codec *codec,
+                                const hda_nid_t *ignore_nids,
+                                const hda_nid_t *ssid_nids)
 {
        struct alc_spec *spec = codec->spec;
        int err;
-       static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
 
        err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc880_ignore);
+                                          ignore_nids);
        if (err < 0)
                return err;
-       if (!spec->autocfg.line_outs)
+       if (!spec->autocfg.line_outs) {
+               if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
+                       spec->multiout.max_channels = 2;
+                       spec->no_analog = 1;
+                       goto dig_only;
+               }
                return 0; /* can't find valid BIOS pin config */
-
+       }
        err = alc_auto_fill_dac_nids(codec);
+       if (err < 0)
+               return err;
+       err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
        if (err < 0)
                return err;
        err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
@@ -3558,19 +3575,35 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
+ dig_only:
        alc_auto_parse_digital(codec);
 
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
+       if (!spec->no_analog)
+               alc_remove_invalid_adc_nids(codec);
 
-       alc_remove_invalid_adc_nids(codec);
+       if (ssid_nids)
+               alc_ssid_check(codec, ssid_nids);
+
+       if (!spec->no_analog) {
+               alc_auto_check_switches(codec);
+               err = alc_auto_add_mic_boost(codec);
+               if (err < 0)
+                       return err;
+       }
 
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-       alc_auto_check_switches(codec);
+       if (spec->kctls.list)
+               add_mixer(spec, spec->kctls.list);
 
        return 1;
 }
 
+static int alc880_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 }; 
+       return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
+}
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static const struct hda_amp_list alc880_loopbacks[] = {
        { 0x0b, HDA_INPUT, 0 },
@@ -3617,6 +3650,7 @@ static int patch_alc880(struct hda_codec *codec)
        codec->spec = spec;
 
        spec->mixer_nid = 0x0b;
+       spec->need_dac_fix = 1;
 
        board_config = alc_board_config(codec, ALC880_MODEL_LAST,
                                        alc880_models, alc880_cfg_tbl);
@@ -3643,22 +3677,26 @@ static int patch_alc880(struct hda_codec *codec)
 #endif
        }
 
-       err = snd_hda_attach_beep_device(codec, 0x1);
-       if (err < 0) {
-               alc_free(codec);
-               return err;
-       }
-
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc880_presets[board_config]);
 
-       if (!spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
        }
-       set_capture_mixer(codec);
-       set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+
+       if (!spec->no_analog && !spec->cap_mixer)
+               set_capture_mixer(codec);
+
+       if (!spec->no_analog) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+               set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+       }
 
        spec->vmaster_nid = 0x0c;
 
@@ -3677,176 +3715,11 @@ static int patch_alc880(struct hda_codec *codec)
 /*
  * ALC260 support
  */
-
-/* convert from pin to volume-mixer widget */
-static hda_nid_t alc260_pin_to_vol_mix(hda_nid_t nid)
-{
-       if (nid >= 0x0f && nid <= 0x11)
-               return nid - 0x7;
-       else if (nid >= 0x12 && nid <= 0x15)
-               return 0x08;
-       else
-               return 0;
-}
-
-static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
-                                       const char *pfx, int *vol_bits)
-{
-       hda_nid_t nid_vol;
-       unsigned long vol_val, sw_val;
-       int chs, err;
-
-       nid_vol = alc260_pin_to_vol_mix(nid);
-       if (!nid_vol)
-               return 0; /* N/A */
-       if (nid == 0x11)
-               chs = 2;
-       else
-               chs = 3;
-       vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, chs, 0, HDA_OUTPUT);
-       sw_val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
-
-       if (!(*vol_bits & (1 << nid_vol))) {
-               /* first control for the volume widget */
-               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
-               if (err < 0)
-                       return err;
-               *vol_bits |= (1 << nid_vol);
-       }
-       err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
-       if (err < 0)
-               return err;
-       return 1;
-}
-
-/* add playback controls from the parsed DAC table */
-static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       hda_nid_t nid;
-       int err;
-       int vols = 0;
-
-       spec->multiout.num_dacs = 1;
-       spec->multiout.dac_nids = spec->private_dac_nids;
-       spec->private_dac_nids[0] = 0x02;
-
-       nid = cfg->line_out_pins[0];
-       if (nid) {
-               const char *pfx;
-               int index;
-               pfx = alc_get_line_out_pfx(spec, 0, true, &index);
-               err = alc260_add_playback_controls(spec, nid, pfx, &vols);
-               if (err < 0)
-                       return err;
-       }
-
-       nid = cfg->speaker_pins[0];
-       if (nid) {
-               err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
-               if (err < 0)
-                       return err;
-       }
-
-       nid = cfg->hp_pins[0];
-       if (nid) {
-               err = alc260_add_playback_controls(spec, nid, "Headphone",
-                                                  &vols);
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
-                                             hda_nid_t nid, int pin_type,
-                                             int sel_idx)
-{
-       hda_nid_t mix;
-
-       alc_set_pin_output(codec, nid, pin_type);
-       /* need the manual connection? */
-       if (nid >= 0x12) {
-               int idx = nid - 0x12;
-               snd_hda_codec_write(codec, idx + 0x0b, 0,
-                                   AC_VERB_SET_CONNECT_SEL, sel_idx);
-       }
-
-       mix = alc260_pin_to_vol_mix(nid);
-       if (!mix)
-               return;
-       snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           AMP_OUT_ZERO);
-       snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           AMP_IN_UNMUTE(0));
-       snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           AMP_IN_UNMUTE(1));
-}
-
-static void alc260_auto_init_multi_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t nid;
-
-       nid = spec->autocfg.line_out_pins[0];
-       if (nid) {
-               int pin_type = get_pin_type(spec->autocfg.line_out_type);
-               alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
-       }
-
-       nid = spec->autocfg.speaker_pins[0];
-       if (nid)
-               alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
-
-       nid = spec->autocfg.hp_pins[0];
-       if (nid)
-               alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
-}
-
 static int alc260_parse_auto_config(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       int err;
        static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc260_ignore);
-       if (err < 0)
-               return err;
-       err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       if (!spec->kctls.list)
-               return 0; /* can't find valid BIOS pin config */
-       err = alc_auto_create_input_ctls(codec);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = 2;
-
-       alc_auto_parse_digital(codec);
-
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       alc_remove_invalid_adc_nids(codec);
-
-       alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
-       alc_auto_check_switches(codec);
-
-       return 1;
-}
-
-/* additional initialization for auto-configuration model */
-static void alc260_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc260_auto_init_multi_out(codec);
-       alc_auto_init_analog_input(codec);
-       alc_auto_init_input_src(codec);
-       alc_auto_init_digital(codec);
-       if (spec->unsol_event)
-               alc_inithook(codec);
+       static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
+       return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -3931,22 +3804,26 @@ static int patch_alc260(struct hda_codec *codec)
 #endif
        }
 
-       err = snd_hda_attach_beep_device(codec, 0x1);
-       if (err < 0) {
-               alc_free(codec);
-               return err;
-       }
-
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc260_presets[board_config]);
 
-       if (!spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
        }
-       set_capture_mixer(codec);
-       set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
+
+       if (!spec->no_analog && !spec->cap_mixer)
+               set_capture_mixer(codec);
+
+       if (!spec->no_analog) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+               set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
+       }
 
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
@@ -3954,7 +3831,7 @@ static int patch_alc260(struct hda_codec *codec)
 
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC_MODEL_AUTO)
-               spec->init_hook = alc260_auto_init;
+               spec->init_hook = alc_auto_init_std;
        spec->shutup = alc_eapd_shutup;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
@@ -4035,53 +3912,9 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
 /* almost identical with ALC880 parser... */
 static int alc882_parse_auto_config(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
        static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
-       int err;
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc882_ignore);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs)
-               return 0; /* can't find valid BIOS pin config */
-
-       err = alc_auto_fill_dac_nids(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_hp_out(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_speaker_out(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_input_ctls(codec);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       alc_auto_parse_digital(codec);
-
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       err = alc_auto_add_mic_boost(codec);
-       if (err < 0)
-               return err;
-
-       alc_remove_invalid_adc_nids(codec);
-
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-       alc_auto_check_switches(codec);
-
-       return 1; /* config found */
+       static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
 }
 
 /*
@@ -4150,27 +3983,26 @@ static int patch_alc882(struct hda_codec *codec)
 #endif
        }
 
-       if (has_cdefine_beep(codec)) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
-               }
-       }
-
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc882_presets[board_config]);
 
-       if (!spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
        }
 
-       set_capture_mixer(codec);
+       if (!spec->no_analog && !spec->cap_mixer)
+               set_capture_mixer(codec);
 
-       if (has_cdefine_beep(codec))
+       if (!spec->no_analog && has_cdefine_beep(codec)) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+       }
 
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
@@ -4193,196 +4025,45 @@ static int patch_alc882(struct hda_codec *codec)
 /*
  * ALC262 support
  */
-
-/* We use two mixers depending on the output pin; 0x16 is a mono output
- * and thus it's bound with a different mixer.
- * This function returns which mixer amp should be used.
- */
-static int alc262_check_volbit(hda_nid_t nid)
+static int alc262_parse_auto_config(struct hda_codec *codec)
 {
-       if (!nid)
-               return 0;
-       else if (nid == 0x16)
-               return 2;
-       else
-               return 1;
+       static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
 }
 
-static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
-                                 const char *pfx, int *vbits, int idx)
-{
-       unsigned long val;
-       int vbit;
+/*
+ * Pin config fixes
+ */
+enum {
+       PINFIX_FSC_H270,
+       PINFIX_HP_Z200,
+};
 
-       vbit = alc262_check_volbit(nid);
-       if (!vbit)
-               return 0;
-       if (*vbits & vbit) /* a volume control for this mixer already there */
-               return 0;
-       *vbits |= vbit;
-       if (vbit == 2)
-               val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
-       else
-               val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
-       return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
-}
+static const struct alc_fixup alc262_fixups[] = {
+       [PINFIX_FSC_H270] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x15, 0x0221142f }, /* front HP */
+                       { 0x1b, 0x0121141f }, /* rear HP */
+                       { }
+               }
+       },
+       [PINFIX_HP_Z200] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x16, 0x99130120 }, /* internal speaker */
+                       { }
+               }
+       },
+};
 
-static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
-                                const char *pfx, int idx)
-{
-       unsigned long val;
-
-       if (!nid)
-               return 0;
-       if (nid == 0x16)
-               val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
-       else
-               val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-       return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
-}
-
-/* add playback controls from the parsed DAC table */
-static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       const char *pfx;
-       int vbits;
-       int i, index, err;
-
-       spec->multiout.num_dacs = 1;    /* only use one dac */
-       spec->multiout.dac_nids = spec->private_dac_nids;
-       spec->private_dac_nids[0] = 2;
-
-       for (i = 0; i < 2; i++) {
-               pfx = alc_get_line_out_pfx(spec, i, true, &index);
-               if (!pfx)
-                       pfx = "PCM";
-               err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx,
-                                           index);
-               if (err < 0)
-                       return err;
-               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-                       err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
-                                                   "Speaker", i);
-                       if (err < 0)
-                               return err;
-               }
-               if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
-                       err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
-                                                   "Headphone", i);
-                       if (err < 0)
-                               return err;
-               }
-       }
-
-       vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
-               alc262_check_volbit(cfg->speaker_pins[0]) |
-               alc262_check_volbit(cfg->hp_pins[0]);
-       vbits = 0;
-       for (i = 0; i < 2; i++) {
-               pfx = alc_get_line_out_pfx(spec, i, true, &index);
-               if (!pfx)
-                       pfx = "PCM";
-               err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
-                                            &vbits, i);
-               if (err < 0)
-                       return err;
-               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-                       err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
-                                                    "Speaker", &vbits, i);
-                       if (err < 0)
-                               return err;
-               }
-               if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
-                       err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
-                                                    "Headphone", &vbits, i);
-                       if (err < 0)
-                               return err;
-               }
-       }
-       return 0;
-}
-
-/*
- * BIOS auto configuration
- */
-static int alc262_parse_auto_config(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int err;
-       static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc262_ignore);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs) {
-               if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
-                       spec->multiout.max_channels = 2;
-                       spec->no_analog = 1;
-                       goto dig_only;
-               }
-               return 0; /* can't find valid BIOS pin config */
-       }
-       err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_input_ctls(codec);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
- dig_only:
-       alc_auto_parse_digital(codec);
-
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       err = alc_auto_add_mic_boost(codec);
-       if (err < 0)
-               return err;
-
-       alc_remove_invalid_adc_nids(codec);
-
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-       alc_auto_check_switches(codec);
-
-       return 1;
-}
-
-/*
- * Pin config fixes
- */
-enum {
-       PINFIX_FSC_H270,
-       PINFIX_HP_Z200,
-};
-
-static const struct alc_fixup alc262_fixups[] = {
-       [PINFIX_FSC_H270] = {
-               .type = ALC_FIXUP_PINS,
-               .v.pins = (const struct alc_pincfg[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x15, 0x0221142f }, /* front HP */
-                       { 0x1b, 0x0121141f }, /* rear HP */
-                       { }
-               }
-       },
-       [PINFIX_HP_Z200] = {
-               .type = ALC_FIXUP_PINS,
-               .v.pins = (const struct alc_pincfg[]) {
-                       { 0x16, 0x99130120 }, /* internal speaker */
-                       { }
-               }
-       },
-};
-
-static const struct snd_pci_quirk alc262_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200),
-       SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
-       {}
-};
+static const struct snd_pci_quirk alc262_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200),
+       SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
+       {}
+};
 
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -4456,26 +4137,26 @@ static int patch_alc262(struct hda_codec *codec)
 #endif
        }
 
-       if (!spec->no_analog && has_cdefine_beep(codec)) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
-               }
-       }
-
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc262_presets[board_config]);
 
-       if (!spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
        }
-       if (!spec->cap_mixer && !spec->no_analog)
+
+       if (!spec->no_analog && !spec->cap_mixer)
                set_capture_mixer(codec);
-       if (!spec->no_analog && has_cdefine_beep(codec))
+
+       if (!spec->no_analog && has_cdefine_beep(codec)) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+       }
 
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
@@ -4527,65 +4208,16 @@ static const struct hda_verb alc268_beep_init_verbs[] = {
  */
 static int alc268_parse_auto_config(struct hda_codec *codec)
 {
+       static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
        struct alc_spec *spec = codec->spec;
-       int err;
-       static const hda_nid_t alc268_ignore[] = { 0 };
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc268_ignore);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs) {
-               if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
-                       spec->multiout.max_channels = 2;
-                       spec->no_analog = 1;
-                       goto dig_only;
+       int err = alc_parse_auto_config(codec, NULL, alc268_ssids);
+       if (err > 0) {
+               if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
+                       add_mixer(spec, alc268_beep_mixer);
+                       add_verb(spec, alc268_beep_init_verbs);
                }
-               return 0; /* can't find valid BIOS pin config */
        }
-
-       err = alc_auto_fill_dac_nids(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_hp_out(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_speaker_out(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_input_ctls(codec);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = 2;
-
- dig_only:
-       /* digital only support output */
-       alc_auto_parse_digital(codec);
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
-               add_mixer(spec, alc268_beep_mixer);
-               add_verb(spec, alc268_beep_init_verbs);
-       }
-
-       err = alc_auto_add_mic_boost(codec);
-       if (err < 0)
-               return err;
-
-       alc_remove_invalid_adc_nids(codec);
-
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-       alc_auto_check_switches(codec);
-
-       return 1;
+       return err;
 }
 
 /*
@@ -4664,13 +4296,13 @@ static int patch_alc268(struct hda_codec *codec)
                                          (0 << AC_AMPCAP_MUTE_SHIFT));
        }
 
-       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
        }
 
-       if (!spec->cap_mixer && !spec->no_analog)
+       if (!spec->no_analog && !spec->cap_mixer)
                set_capture_mixer(codec);
 
        spec->vmaster_nid = 0x02;
@@ -4754,54 +4386,14 @@ enum {
  */
 static int alc269_parse_auto_config(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       int err;
        static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc269_ssids[] = { 0, 0x1b, 0x14, 0x21 };
+       static const hda_nid_t alc269va_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       struct alc_spec *spec = codec->spec;
+       const hda_nid_t *ssids = spec->codec_variant == ALC269_TYPE_ALC269VA ?
+               alc269va_ssids : alc269_ssids;
 
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc269_ignore);
-       if (err < 0)
-               return err;
-
-       err = alc_auto_fill_dac_nids(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_hp_out(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_speaker_out(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_input_ctls(codec);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       alc_auto_parse_digital(codec);
-
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       alc_remove_invalid_adc_nids(codec);
-
-       if (spec->codec_variant != ALC269_TYPE_ALC269VA)
-               alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
-       else
-               alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-       alc_auto_check_switches(codec);
-
-       err = alc_auto_add_mic_boost(codec);
-       if (err < 0)
-               return err;
-
-       if (!spec->cap_mixer && !spec->no_analog)
-               set_capture_mixer(codec);
-
-       return 1;
+       return alc_parse_auto_config(codec, alc269_ignore, ssids);
 }
 
 static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
@@ -4824,7 +4416,7 @@ static void alc269_shutup(struct hda_codec *codec)
        }
 }
 
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 static int alc269_resume(struct hda_codec *codec)
 {
        if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
@@ -4847,7 +4439,7 @@ static int alc269_resume(struct hda_codec *codec)
        hda_call_check_power_status(codec, 0x01);
        return 0;
 }
-#endif /* SND_HDA_NEEDS_RESUME */
+#endif /* CONFIG_PM */
 
 static void alc269_fixup_hweq(struct hda_codec *codec,
                               const struct alc_fixup *fix, int action)
@@ -4877,6 +4469,21 @@ static void alc271_fixup_dmic(struct hda_codec *codec,
                snd_hda_sequence_write(codec, verbs);
 }
 
+static void alc269_fixup_pcm_44k(struct hda_codec *codec,
+                                const struct alc_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action != ALC_FIXUP_ACT_PROBE)
+               return;
+
+       /* Due to a hardware problem on Lenovo Ideadpad, we need to
+        * fix the sample rate of analog I/O to 44.1kHz
+        */
+       spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
+       spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
+}
+
 enum {
        ALC269_FIXUP_SONY_VAIO,
        ALC275_FIXUP_SONY_VAIO_GPIO2,
@@ -4886,6 +4493,7 @@ enum {
        ALC269_FIXUP_LENOVO_EAPD,
        ALC275_FIXUP_SONY_HWEQ,
        ALC271_FIXUP_DMIC,
+       ALC269_FIXUP_PCM_44K,
 };
 
 static const struct alc_fixup alc269_fixups[] = {
@@ -4944,9 +4552,14 @@ static const struct alc_fixup alc269_fixups[] = {
                .type = ALC_FIXUP_FUNC,
                .v.func = alc271_fixup_dmic,
        },
+       [ALC269_FIXUP_PCM_44K] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc269_fixup_pcm_44k,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
        SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
        SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
        SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
@@ -4958,7 +4571,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
-       SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
+       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
        {}
 };
@@ -5092,44 +4705,33 @@ static int patch_alc269(struct hda_codec *codec)
 #endif
        }
 
-       if (has_cdefine_beep(codec)) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
-               }
-       }
-
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc269_presets[board_config]);
 
-#if 0
-       if (board_config == ALC269_QUANTA_FL1) {
-               /* Due to a hardware problem on Lenovo Ideadpad, we need to
-                * fix the sample rate of analog I/O to 44.1kHz
-                */
-               spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
-               spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
-       }
-#endif
-
-       if (!spec->adc_nids) { /* wasn't filled automatically? use default */
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
        }
 
-       if (!spec->cap_mixer)
+       if (!spec->no_analog && !spec->cap_mixer)
                set_capture_mixer(codec);
-       if (has_cdefine_beep(codec))
+
+       if (!spec->no_analog && has_cdefine_beep(codec)) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
                set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
+       }
 
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
        spec->vmaster_nid = 0x02;
 
        codec->patch_ops = alc_patch_ops;
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
        codec->patch_ops.resume = alc269_resume;
 #endif
        if (board_config == ALC_MODEL_AUTO)
@@ -5153,51 +4755,9 @@ static int patch_alc269(struct hda_codec *codec)
 
 static int alc861_parse_auto_config(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       int err;
        static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc861_ignore);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs)
-               return 0; /* can't find valid BIOS pin config */
-
-       err = alc_auto_fill_dac_nids(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_hp_out(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_speaker_out(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_input_ctls(codec);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       alc_auto_parse_digital(codec);
-
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       alc_remove_invalid_adc_nids(codec);
-
-       alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
-       alc_auto_check_switches(codec);
-
-       set_capture_mixer(codec);
-
-       return 1;
+       static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
+       return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
 }
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -5283,24 +4843,26 @@ static int patch_alc861(struct hda_codec *codec)
 #endif
        }
 
-       err = snd_hda_attach_beep_device(codec, 0x23);
-       if (err < 0) {
-               alc_free(codec);
-               return err;
-       }
-
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc861_presets[board_config]);
 
-       if (!spec->adc_nids) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
        }
 
-       if (!spec->cap_mixer)
+       if (!spec->no_analog && !spec->cap_mixer)
                set_capture_mixer(codec);
-       set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
+
+       if (!spec->no_analog) {
+               err = snd_hda_attach_beep_device(codec, 0x23);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+               set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
+       }
 
        spec->vmaster_nid = 0x03;
 
@@ -5334,53 +4896,9 @@ static int patch_alc861(struct hda_codec *codec)
 
 static int alc861vd_parse_auto_config(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       int err;
        static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc861vd_ignore);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs)
-               return 0; /* can't find valid BIOS pin config */
-
-       err = alc_auto_fill_dac_nids(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_hp_out(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_speaker_out(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_input_ctls(codec);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       alc_auto_parse_digital(codec);
-
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       alc_remove_invalid_adc_nids(codec);
-
-       alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-       alc_auto_check_switches(codec);
-
-       err = alc_auto_add_mic_boost(codec);
-       if (err < 0)
-               return err;
-
-       return 1;
+       static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
 }
 
 enum {
@@ -5461,12 +4979,6 @@ static int patch_alc861vd(struct hda_codec *codec)
 #endif
        }
 
-       err = snd_hda_attach_beep_device(codec, 0x23);
-       if (err < 0) {
-               alc_free(codec);
-               return err;
-       }
-
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc861vd_presets[board_config]);
 
@@ -5475,14 +4987,23 @@ static int patch_alc861vd(struct hda_codec *codec)
                add_verb(spec, alc660vd_eapd_verbs);
        }
 
-       if (!spec->adc_nids) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
        }
 
-       set_capture_mixer(codec);
-       set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+       if (!spec->no_analog && !spec->cap_mixer)
+               set_capture_mixer(codec);
+
+       if (!spec->no_analog) {
+               err = snd_hda_attach_beep_device(codec, 0x23);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
+               set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+       }
 
        spec->vmaster_nid = 0x02;
 
@@ -5522,62 +5043,17 @@ static int patch_alc861vd(struct hda_codec *codec)
 
 static int alc662_parse_auto_config(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       int err;
        static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc662_ignore);
-       if (err < 0)
-               return err;
-       if (!spec->autocfg.line_outs)
-               return 0; /* can't find valid BIOS pin config */
-
-       err = alc_auto_fill_dac_nids(codec);
-       if (err < 0)
-               return err;
-       err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-       err = alc_auto_create_extra_out(codec,
-                                          spec->autocfg.speaker_pins[0],
-                                          spec->multiout.extra_out_nid[0],
-                                          "Speaker");
-       if (err < 0)
-               return err;
-       err = alc_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
-                                          spec->multiout.hp_nid,
-                                          "Headphone");
-       if (err < 0)
-               return err;
-       err = alc_auto_create_input_ctls(codec);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
-
-       alc_auto_parse_digital(codec);
-
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       alc_remove_invalid_adc_nids(codec);
+       static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
+       static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       const hda_nid_t *ssids;
 
        if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
            codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
-           alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
+               ssids = alc663_ssids;
        else
-           alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
-       alc_auto_check_switches(codec);
-
-       err = alc_auto_add_mic_boost(codec);
-       if (err < 0)
-               return err;
-
-       return 1;
+               ssids = alc662_ssids;
+       return alc_parse_auto_config(codec, alc662_ignore, ssids);
 }
 
 static void alc272_fixup_mario(struct hda_codec *codec,
@@ -5724,27 +5200,24 @@ static int patch_alc662(struct hda_codec *codec)
 #endif
        }
 
-       if (has_cdefine_beep(codec)) {
-               err = snd_hda_attach_beep_device(codec, 0x1);
-               if (err < 0) {
-                       alc_free(codec);
-                       return err;
-               }
-       }
-
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc662_presets[board_config]);
 
-       if (!spec->adc_nids) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
        }
 
-       if (!spec->cap_mixer)
+       if (!spec->no_analog && !spec->cap_mixer)
                set_capture_mixer(codec);
 
-       if (has_cdefine_beep(codec)) {
+       if (!spec->no_analog && has_cdefine_beep(codec)) {
+               err = snd_hda_attach_beep_device(codec, 0x1);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               }
                switch (codec->vendor_id) {
                case 0x10ec0662:
                        set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
@@ -5810,61 +5283,7 @@ static int patch_alc899(struct hda_codec *codec)
 
 static int alc680_parse_auto_config(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       int err;
-       static const hda_nid_t alc680_ignore[] = { 0 };
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
-                                          alc680_ignore);
-       if (err < 0)
-               return err;
-
-       if (!spec->autocfg.line_outs) {
-               if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
-                       spec->multiout.max_channels = 2;
-                       spec->no_analog = 1;
-                       goto dig_only;
-               }
-               return 0; /* can't find valid BIOS pin config */
-       }
-
-       err = alc_auto_fill_dac_nids(codec);
-       if (err < 0)
-               return err;
-
-       err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       err = alc_auto_create_hp_out(codec);
-       if (err < 0)
-               return err;
-
-       err = alc_auto_create_speaker_out(codec);
-       if (err < 0)
-               return err;
-
-       err = alc_auto_create_input_ctls(codec);
-       if (err < 0)
-               return err;
-
-       spec->multiout.max_channels = 2;
-
- dig_only:
-       /* digital only support output */
-       alc_auto_parse_digital(codec);
-       if (spec->kctls.list)
-               add_mixer(spec, spec->kctls.list);
-
-       alc_remove_invalid_adc_nids(codec);
-
-       alc_auto_check_switches(codec);
-
-       err = alc_auto_add_mic_boost(codec);
-       if (err < 0)
-               return err;
-
-       return 1;
+       return alc_parse_auto_config(codec, NULL, NULL);
 }
 
 /*
@@ -5920,13 +5339,13 @@ static int patch_alc680(struct hda_codec *codec)
 #endif
        }
 
-       if (!spec->adc_nids) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
        }
 
-       if (!spec->cap_mixer)
+       if (!spec->no_analog && !spec->cap_mixer)
                set_capture_mixer(codec);
 
        spec->vmaster_nid = 0x02;