ALSA: hda - Merge ALC269 parser code
[deliverable/linux.git] / sound / pci / hda / patch_realtek.c
index c1adb3bce7e89f621efd147802c0a7a14b7cdec5..2a94c58b2104c33dfd6d8dda9705e85ed138b25b 100644 (file)
@@ -206,6 +206,22 @@ struct alc_spec {
 
 #define ALC_MODEL_AUTO         0       /* common for all chips */
 
+static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
+                          int dir, unsigned int bits)
+{
+       if (!nid)
+               return false;
+       if (get_wcaps(codec, nid) & (1 << (dir + 1)))
+               if (query_amp_caps(codec, nid, dir) & bits)
+                       return true;
+       return false;
+}
+
+#define nid_has_mute(codec, nid, dir) \
+       check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
+#define nid_has_volume(codec, nid, dir) \
+       check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
+
 /*
  * input MUX handling
  */
@@ -958,7 +974,7 @@ static bool alc_check_dyn_adc_switch(struct hda_codec *codec)
                                break;
                }
                if (i >= imux->num_items)
-                       return false; /* no ADC-switch is needed */
+                       return true; /* no ADC-switch is needed */
        }
 
        for (i = 0; i < imux->num_items; i++) {
@@ -2637,7 +2653,8 @@ static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
                            pin_type);
        /* unmute pin */
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+       if (nid_has_mute(codec, nid, HDA_OUTPUT))
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
                            AMP_OUT_UNMUTE);
 }
 
@@ -2682,6 +2699,8 @@ 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;
 
+       if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_AUD_OUT)
+               return nid;
        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)
@@ -2838,6 +2857,8 @@ static int alc_auto_add_vol_ctl(struct hda_codec *codec,
                              const char *pfx, int cidx,
                              hda_nid_t nid, unsigned int chs)
 {
+       if (!nid)
+               return 0;
        return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx,
                                 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
 }
@@ -2852,9 +2873,16 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec,
                             const char *pfx, int cidx,
                             hda_nid_t nid, unsigned int chs)
 {
+       int wid_type;
        int type;
        unsigned long val;
-       if (snd_hda_get_conn_list(codec, nid, NULL) == 1) {
+       if (!nid)
+               return 0;
+       wid_type = get_wcaps_type(get_wcaps(codec, nid));
+       if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) {
+               type = ALC_CTL_WIDGET_MUTE;
+               val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
+       } else if (snd_hda_get_conn_list(codec, nid, NULL) == 1) {
                type = ALC_CTL_WIDGET_MUTE;
                val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT);
        } else {
@@ -2867,12 +2895,37 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec,
 #define alc_auto_add_stereo_sw(codec, pfx, cidx, nid)  \
        alc_auto_add_sw_ctl(codec, pfx, cidx, nid, 3)
 
+static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
+                                          hda_nid_t pin, hda_nid_t dac)
+{
+       hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac);
+       if (nid_has_mute(codec, pin, HDA_OUTPUT))
+               return pin;
+       else if (mix && nid_has_mute(codec, mix, HDA_INPUT))
+               return mix;
+       else if (nid_has_mute(codec, dac, HDA_OUTPUT))
+               return dac;
+       return 0;
+}
+
+static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
+                                         hda_nid_t pin, hda_nid_t dac)
+{
+       hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac);
+       if (nid_has_volume(codec, dac, HDA_OUTPUT))
+               return dac;
+       else if (nid_has_volume(codec, mix, HDA_OUTPUT))
+               return mix;
+       else if (nid_has_volume(codec, pin, HDA_OUTPUT))
+               return pin;
+       return 0;
+}
+
 /* add playback controls from the parsed DAC table */
 static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
                                             const struct auto_pin_cfg *cfg)
 {
        struct alc_spec *spec = codec->spec;
-       hda_nid_t nid, mix, pin;
        int i, err, noutputs;
 
        noutputs = cfg->line_outs;
@@ -2882,36 +2935,39 @@ static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
        for (i = 0; i < noutputs; i++) {
                const char *name;
                int index;
-               nid = spec->multiout.dac_nids[i];
-               if (!nid)
+               hda_nid_t dac, pin;
+               hda_nid_t sw, vol;
+
+               dac = spec->multiout.dac_nids[i];
+               if (!dac)
                        continue;
                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;
+
+               sw = alc_look_for_out_mute_nid(codec, pin, dac);
+               vol = alc_look_for_out_vol_nid(codec, pin, dac);
                name = alc_get_line_out_pfx(spec, i, true, &index);
                if (!name) {
                        /* Center/LFE */
-                       err = alc_auto_add_vol_ctl(codec, "Center", 0, nid, 1);
+                       err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1);
                        if (err < 0)
                                return err;
-                       err = alc_auto_add_vol_ctl(codec, "LFE", 0, nid, 2);
+                       err = alc_auto_add_vol_ctl(codec, "LFE", 0, vol, 2);
                        if (err < 0)
                                return err;
-                       err = alc_auto_add_sw_ctl(codec, "Center", 0, mix, 1);
+                       err = alc_auto_add_sw_ctl(codec, "Center", 0, sw, 1);
                        if (err < 0)
                                return err;
-                       err = alc_auto_add_sw_ctl(codec, "LFE", 0, mix, 2);
+                       err = alc_auto_add_sw_ctl(codec, "LFE", 0, sw, 2);
                        if (err < 0)
                                return err;
                } else {
-                       err = alc_auto_add_stereo_vol(codec, name, index, nid);
+                       err = alc_auto_add_stereo_vol(codec, name, index, vol);
                        if (err < 0)
                                return err;
-                       err = alc_auto_add_stereo_sw(codec, name, index, mix);
+                       err = alc_auto_add_stereo_sw(codec, name, index, sw);
                        if (err < 0)
                                return err;
                }
@@ -2924,7 +2980,7 @@ static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
                                        hda_nid_t dac, const char *pfx)
 {
        struct alc_spec *spec = codec->spec;
-       hda_nid_t mix;
+       hda_nid_t sw, vol;
        int err;
 
        if (!pin)
@@ -2938,13 +2994,12 @@ static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
                                   HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
        }
 
-       mix = alc_auto_dac_to_mix(codec, pin, dac);
-       if (!mix)
-               return 0;
-       err = alc_auto_add_stereo_vol(codec, pfx, 0, dac);
+       sw = alc_look_for_out_mute_nid(codec, pin, dac);
+       vol = alc_look_for_out_vol_nid(codec, pin, dac);
+       err = alc_auto_add_stereo_vol(codec, pfx, 0, vol);
        if (err < 0)
                return err;
-       err = alc_auto_add_stereo_sw(codec, pfx, 0, mix);
+       err = alc_auto_add_stereo_sw(codec, pfx, 0, sw);
        if (err < 0)
                return err;
        return 0;
@@ -2967,15 +3022,15 @@ static int alc_auto_create_speaker_out(struct hda_codec *codec)
 }
 
 static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
-                                             hda_nid_t nid, int pin_type,
+                                             hda_nid_t pin, int pin_type,
                                              hda_nid_t dac)
 {
        int i, num;
-       hda_nid_t mix = 0;
+       hda_nid_t nid, mix = 0;
        hda_nid_t srcs[HDA_MAX_CONNECTIONS];
 
-       alc_set_pin_output(codec, nid, pin_type);
-       nid = alc_go_down_to_selector(codec, nid);
+       alc_set_pin_output(codec, pin, pin_type);
+       nid = alc_go_down_to_selector(codec, pin);
        num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
        for (i = 0; i < num; i++) {
                if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
@@ -2990,19 +3045,17 @@ static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
        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, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+       if (nid_has_mute(codec, mix, HDA_INPUT)) {
+               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,
+               snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
                            AMP_IN_UNMUTE(1));
+       }
        /* initialize volume */
-       if (query_amp_caps(codec, dac, HDA_OUTPUT) & AC_AMPCAP_NUM_STEPS)
-               nid = dac;
-       else if (query_amp_caps(codec, mix, HDA_OUTPUT) & AC_AMPCAP_NUM_STEPS)
-               nid = mix;
-       else
-               return;
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           AMP_OUT_ZERO);
+       nid = alc_look_for_out_vol_nid(codec, pin, dac);
+       if (nid)
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_OUT_ZERO);
 }
 
 static void alc_auto_init_multi_out(struct hda_codec *codec)
@@ -3269,7 +3322,7 @@ static void alc_auto_init_adc(struct hda_codec *codec, int adc_idx)
 
        nid = spec->adc_nids[adc_idx];
        /* mute ADC */
-       if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE) {
+       if (nid_has_mute(codec, nid, HDA_INPUT)) {
                snd_hda_codec_write(codec, nid, 0,
                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                    AMP_IN_MUTE(0));
@@ -3278,7 +3331,7 @@ static void alc_auto_init_adc(struct hda_codec *codec, int adc_idx)
        if (!spec->capsrc_nids)
                return;
        nid = spec->capsrc_nids[adc_idx];
-       if (query_amp_caps(codec, nid, HDA_OUTPUT) & AC_AMPCAP_MUTE)
+       if (nid_has_mute(codec, nid, HDA_OUTPUT))
                snd_hda_codec_write(codec, nid, 0,
                                    AC_VERB_SET_AMP_GAIN_MUTE,
                                    AMP_OUT_MUTE);
@@ -3395,12 +3448,10 @@ static void set_capture_mixer(struct hda_codec *codec)
        };
 
        /* check whether either of ADC or MUX has a volume control */
-       if (!(query_amp_caps(codec, spec->adc_nids[0], HDA_INPUT) &
-             AC_AMPCAP_NUM_STEPS)) {
+       if (!nid_has_volume(codec, spec->adc_nids[0], HDA_INPUT)) {
                if (!spec->capsrc_nids)
                        return; /* no volume */
-               if (!(query_amp_caps(codec, spec->capsrc_nids[0], HDA_OUTPUT) &
-                     AC_AMPCAP_NUM_STEPS))
+               if (!nid_has_volume(codec, spec->capsrc_nids[0], HDA_OUTPUT))
                        return; /* no volume in capsrc, too */
                spec->vol_in_capsrc = 1;
        }
@@ -3427,6 +3478,21 @@ static void set_capture_mixer(struct hda_codec *codec)
        }
 }
 
+/*
+ * standard auto-parser initializations
+ */
+static void alc_auto_init_std(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       alc_auto_init_multi_out(codec);
+       alc_auto_init_extra_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);
+}
+
 /*
  * Digital-beep handlers
  */
@@ -3475,9 +3541,6 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
                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);
@@ -3508,19 +3571,6 @@ static int alc880_parse_auto_config(struct hda_codec *codec)
        return 1;
 }
 
-/* additional initialization for auto-configuration model */
-static void alc880_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc_auto_init_multi_out(codec);
-       alc_auto_init_extra_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);
-}
-
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static const struct hda_amp_list alc880_loopbacks[] = {
        { 0x0b, HDA_INPUT, 0 },
@@ -3614,7 +3664,7 @@ static int patch_alc880(struct hda_codec *codec)
 
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC_MODEL_AUTO)
-               spec->init_hook = alc880_auto_init;
+               spec->init_hook = alc_auto_init_std;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc880_loopbacks;
@@ -4034,19 +4084,6 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
        return 1; /* config found */
 }
 
-/* additional initialization for auto-configuration model */
-static void alc882_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc_auto_init_multi_out(codec);
-       alc_auto_init_extra_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);
-}
-
 /*
  */
 #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
@@ -4141,7 +4178,7 @@ static int patch_alc882(struct hda_codec *codec)
 
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC_MODEL_AUTO)
-               spec->init_hook = alc882_auto_init;
+               spec->init_hook = alc_auto_init_std;
 
        alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -4156,119 +4193,6 @@ 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)
-{
-       if (!nid)
-               return 0;
-       else if (nid == 0x16)
-               return 2;
-       else
-               return 1;
-}
-
-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;
-
-       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 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;
@@ -4287,7 +4211,16 @@ static int alc262_parse_auto_config(struct hda_codec *codec)
                }
                return 0; /* can't find valid BIOS pin config */
        }
-       err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       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);
@@ -4352,19 +4285,6 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = {
 #define alc262_loopbacks       alc880_loopbacks
 #endif
 
-/* init callback for auto-configuration model -- overriding the default init */
-static void alc262_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc_auto_init_multi_out(codec);
-       alc_auto_init_extra_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);
-}
-
 /*
  */
 #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
@@ -4459,7 +4379,7 @@ static int patch_alc262(struct hda_codec *codec)
 
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC_MODEL_AUTO)
-               spec->init_hook = alc262_auto_init;
+               spec->init_hook = alc_auto_init_std;
        spec->shutup = alc_eapd_shutup;
 
        alc_init_jacks(codec);
@@ -4474,204 +4394,6 @@ static int patch_alc262(struct hda_codec *codec)
 /*
  *  ALC268
  */
-/* create input playback/capture controls for the given pin */
-static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
-                                   const char *ctlname, int idx)
-{
-       hda_nid_t dac;
-       int err;
-
-       switch (nid) {
-       case 0x14:
-       case 0x16:
-               dac = 0x02;
-               break;
-       case 0x15:
-       case 0x1a: /* ALC259/269 only */
-       case 0x1b: /* ALC259/269 only */
-       case 0x21: /* ALC269vb has this pin, too */
-               dac = 0x03;
-               break;
-       default:
-               snd_printd(KERN_WARNING "hda_codec: "
-                          "ignoring pin 0x%x as unknown\n", nid);
-               return 0;
-       }
-       if (spec->multiout.dac_nids[0] != dac &&
-           spec->multiout.dac_nids[1] != dac) {
-               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
-                                 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
-                                                     HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-               spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
-       }
-
-       if (nid != 0x16)
-               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
-                         HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
-       else /* mono */
-               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
-                         HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
-       if (err < 0)
-               return err;
-       return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       hda_nid_t nid;
-       int err;
-
-       spec->multiout.dac_nids = spec->private_dac_nids;
-
-       nid = cfg->line_out_pins[0];
-       if (nid) {
-               const char *name;
-               int index;
-               name = alc_get_line_out_pfx(spec, 0, true, &index);
-               err = alc268_new_analog_output(spec, nid, name, 0);
-               if (err < 0)
-                       return err;
-       }
-
-       nid = cfg->speaker_pins[0];
-       if (nid == 0x1d) {
-               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
-                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
-               if (err < 0)
-                       return err;
-       } else if (nid) {
-               err = alc268_new_analog_output(spec, nid, "Speaker", 0);
-               if (err < 0)
-                       return err;
-       }
-       nid = cfg->hp_pins[0];
-       if (nid) {
-               err = alc268_new_analog_output(spec, nid, "Headphone", 0);
-               if (err < 0)
-                       return err;
-       }
-
-       nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
-       if (nid == 0x16) {
-               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
-                                 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
-                                             hda_nid_t nid, int pin_type)
-{
-       int idx;
-
-       alc_set_pin_output(codec, nid, pin_type);
-       if (snd_hda_get_conn_list(codec, nid, NULL) <= 1)
-               return;
-       if (nid == 0x14 || nid == 0x16)
-               idx = 0;
-       else
-               idx = 1;
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
-}
-
-static void alc268_auto_init_dac(struct hda_codec *codec, hda_nid_t nid)
-{
-       if (!nid)
-               return;
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           AMP_OUT_ZERO);
-}
-
-static void alc268_auto_init_multi_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->autocfg.line_outs; i++) {
-               hda_nid_t nid = spec->autocfg.line_out_pins[i];
-               int pin_type = get_pin_type(spec->autocfg.line_out_type);
-               alc268_auto_set_output_and_unmute(codec, nid, pin_type);
-       }
-       /* mute DACs */
-       for (i = 0; i < spec->multiout.num_dacs; i++)
-               alc268_auto_init_dac(codec, spec->multiout.dac_nids[i]);
-}
-
-static void alc268_auto_init_hp_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t pin;
-       int i;
-
-       for (i = 0; i < spec->autocfg.hp_outs; i++) {
-               pin = spec->autocfg.hp_pins[i];
-               alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
-       }
-       for (i = 0; i < spec->autocfg.speaker_outs; i++) {
-               pin = spec->autocfg.speaker_pins[i];
-               alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
-       }
-       if (spec->autocfg.mono_out_pin)
-               snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-       /* mute DACs */
-       alc268_auto_init_dac(codec, spec->multiout.hp_nid);
-       for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++)
-               alc268_auto_init_dac(codec, spec->multiout.extra_out_nid[i]);
-}
-
-static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
-       hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
-       hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
-       unsigned int    dac_vol1, dac_vol2;
-
-       if (line_nid == 0x1d || speaker_nid == 0x1d) {
-               snd_hda_codec_write(codec, speaker_nid, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-               /* mute mixer inputs from 0x1d */
-               snd_hda_codec_write(codec, 0x0f, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE,
-                                   AMP_IN_UNMUTE(1));
-               snd_hda_codec_write(codec, 0x10, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE,
-                                   AMP_IN_UNMUTE(1));
-       } else {
-               /* unmute mixer inputs from 0x1d */
-               snd_hda_codec_write(codec, 0x0f, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
-               snd_hda_codec_write(codec, 0x10, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
-       }
-
-       dac_vol1 = dac_vol2 = 0xb000 | 0x40;    /* set max volume  */
-       if (line_nid == 0x14)
-               dac_vol2 = AMP_OUT_ZERO;
-       else if (line_nid == 0x15)
-               dac_vol1 = AMP_OUT_ZERO;
-       if (hp_nid == 0x14)
-               dac_vol2 = AMP_OUT_ZERO;
-       else if (hp_nid == 0x15)
-               dac_vol1 = AMP_OUT_ZERO;
-       if (line_nid != 0x16 || hp_nid != 0x16 ||
-           spec->autocfg.line_out_pins[1] != 0x16 ||
-           spec->autocfg.line_out_pins[2] != 0x16)
-               dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
-
-       snd_hda_codec_write(codec, 0x02, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
-       snd_hda_codec_write(codec, 0x03, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
-}
-
 /* bind Beep switches of both NID 0x0f and 0x10 */
 static const struct hda_bind_ctls alc268_bind_beep_sw = {
        .ops = &snd_hda_bind_sw,
@@ -4717,10 +4439,23 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
                }
                return 0; /* can't find valid BIOS pin config */
        }
-       err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
+
+       err = alc_auto_fill_dac_nids(codec);
        if (err < 0)
                return err;
-       err = alc_auto_create_input_ctls(codec);
+       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;
 
@@ -4749,20 +4484,6 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
        return 1;
 }
 
-/* init callback for auto-configuration model -- overriding the default init */
-static void alc268_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc268_auto_init_multi_out(codec);
-       alc268_auto_init_hp_out(codec);
-       alc268_auto_init_mono_speaker_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);
-}
-
 /*
  */
 #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
@@ -4852,7 +4573,7 @@ static int patch_alc268(struct hda_codec *codec)
 
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC_MODEL_AUTO)
-               spec->init_hook = alc268_auto_init;
+               spec->init_hook = alc_auto_init_std;
        spec->shutup = alc_eapd_shutup;
 
        alc_init_jacks(codec);
@@ -4863,9 +4584,6 @@ static int patch_alc268(struct hda_codec *codec)
 /*
  * ALC269
  */
-#define alc269_auto_create_multi_out_ctls \
-       alc268_auto_create_multi_out_ctls
-
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc269_loopbacks       alc880_loopbacks
 #endif
@@ -4941,7 +4659,16 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        if (err < 0)
                return err;
 
-       err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       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);
@@ -4973,23 +4700,6 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        return 1;
 }
 
-#define alc269_auto_init_multi_out     alc268_auto_init_multi_out
-#define alc269_auto_init_hp_out                alc268_auto_init_hp_out
-
-
-/* init callback for auto-configuration model -- overriding the default init */
-static void alc269_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc269_auto_init_multi_out(codec);
-       alc269_auto_init_hp_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 void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
 {
        int val = alc_read_coef_idx(codec, 0x04);
@@ -5319,7 +5029,7 @@ static int patch_alc269(struct hda_codec *codec)
        codec->patch_ops.resume = alc269_resume;
 #endif
        if (board_config == ALC_MODEL_AUTO)
-               spec->init_hook = alc269_auto_init;
+               spec->init_hook = alc_auto_init_std;
        spec->shutup = alc269_shutup;
 
        alc_init_jacks(codec);
@@ -5337,176 +5047,6 @@ static int patch_alc269(struct hda_codec *codec)
  * ALC861
  */
 
-static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t mix, srcs[5];
-       int i, num;
-
-       if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
-               return 0;
-       num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
-       if (num < 0)
-               return 0;
-       for (i = 0; i < num; i++) {
-               unsigned int type;
-               type = get_wcaps_type(get_wcaps(codec, srcs[i]));
-               if (type != AC_WID_AUD_OUT)
-                       continue;
-               if (!found_in_nid_list(srcs[i], spec->multiout.dac_nids,
-                                      spec->multiout.num_dacs))
-                       return srcs[i];
-       }
-       return 0;
-}
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int alc861_auto_fill_dac_nids(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       const struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i;
-       hda_nid_t nid, dac;
-
-       spec->multiout.dac_nids = spec->private_dac_nids;
-       for (i = 0; i < cfg->line_outs; i++) {
-               nid = cfg->line_out_pins[i];
-               dac = alc861_look_for_dac(codec, nid);
-               if (!dac)
-                       continue;
-               spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
-       }
-       return 0;
-}
-
-static int __alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
-                                 hda_nid_t nid, int idx, unsigned int chs)
-{
-       return __add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
-                          HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
-}
-
-#define alc861_create_out_sw(codec, pfx, nid, chs) \
-       __alc861_create_out_sw(codec, pfx, nid, 0, chs)
-
-/* add playback controls from the parsed DAC table */
-static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t nid;
-       int i, err, noutputs;
-
-       noutputs = cfg->line_outs;
-       if (spec->multi_ios > 0)
-               noutputs += spec->multi_ios;
-
-       for (i = 0; i < noutputs; i++) {
-               const char *name;
-               int index;
-               nid = spec->multiout.dac_nids[i];
-               if (!nid)
-                       continue;
-               name = alc_get_line_out_pfx(spec, i, true, &index);
-               if (!name) {
-                       /* Center/LFE */
-                       err = alc861_create_out_sw(codec, "Center", nid, 1);
-                       if (err < 0)
-                               return err;
-                       err = alc861_create_out_sw(codec, "LFE", nid, 2);
-                       if (err < 0)
-                               return err;
-               } else {
-                       err = __alc861_create_out_sw(codec, name, nid, index, 3);
-                       if (err < 0)
-                               return err;
-               }
-       }
-       return 0;
-}
-
-static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
-{
-       struct alc_spec *spec = codec->spec;
-       int err;
-       hda_nid_t nid;
-
-       if (!pin)
-               return 0;
-
-       if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
-               nid = alc861_look_for_dac(codec, pin);
-               if (nid) {
-                       err = alc861_create_out_sw(codec, "Headphone", nid, 3);
-                       if (err < 0)
-                               return err;
-                       spec->multiout.hp_nid = nid;
-               }
-       }
-       return 0;
-}
-
-static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
-                                             hda_nid_t nid,
-                                             int pin_type, hda_nid_t dac)
-{
-       hda_nid_t mix, srcs[5];
-       int i, num;
-
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           pin_type);
-       snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           AMP_OUT_UNMUTE);
-       if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
-               return;
-       num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
-       if (num < 0)
-               return;
-       for (i = 0; i < num; i++) {
-               unsigned int mute;
-               if (srcs[i] == dac || srcs[i] == 0x15)
-                       mute = AMP_IN_UNMUTE(i);
-               else
-                       mute = AMP_IN_MUTE(i);
-               snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                                   mute);
-       }
-}
-
-static void alc861_auto_init_multi_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->autocfg.line_outs + spec->multi_ios; i++) {
-               hda_nid_t nid = spec->autocfg.line_out_pins[i];
-               int pin_type = get_pin_type(spec->autocfg.line_out_type);
-               if (nid)
-                       alc861_auto_set_output_and_unmute(codec, nid, pin_type,
-                                                         spec->multiout.dac_nids[i]);
-       }
-}
-
-static void alc861_auto_init_hp_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (spec->autocfg.hp_outs)
-               alc861_auto_set_output_and_unmute(codec,
-                                                 spec->autocfg.hp_pins[0],
-                                                 PIN_HP,
-                                                 spec->multiout.hp_nid);
-       if (spec->autocfg.speaker_outs)
-               alc861_auto_set_output_and_unmute(codec,
-                                                 spec->autocfg.speaker_pins[0],
-                                                 PIN_OUT,
-                                                 spec->multiout.dac_nids[0]);
-}
-
-/* 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
- */
 static int alc861_parse_auto_config(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -5520,16 +5060,19 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
        if (!spec->autocfg.line_outs)
                return 0; /* can't find valid BIOS pin config */
 
-       err = alc861_auto_fill_dac_nids(codec);
+       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_add_multi_channel_mode(codec, alc861_auto_fill_dac_nids);
+       err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
+       err = alc_auto_create_hp_out(codec);
        if (err < 0)
                return err;
-       err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
+       err = alc_auto_create_speaker_out(codec);
        if (err < 0)
                return err;
        err = alc_auto_create_input_ctls(codec);
@@ -5553,18 +5096,6 @@ static int alc861_parse_auto_config(struct hda_codec *codec)
        return 1;
 }
 
-/* additional initialization for auto-configuration model */
-static void alc861_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc861_auto_init_multi_out(codec);
-       alc861_auto_init_hp_out(codec);
-       alc_auto_init_analog_input(codec);
-       alc_auto_init_digital(codec);
-       if (spec->unsol_event)
-               alc_inithook(codec);
-}
-
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static const struct hda_amp_list alc861_loopbacks[] = {
        { 0x15, HDA_INPUT, 0 },
@@ -5673,7 +5204,7 @@ static int patch_alc861(struct hda_codec *codec)
 
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC_MODEL_AUTO) {
-               spec->init_hook = alc861_auto_init;
+               spec->init_hook = alc_auto_init_std;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
                spec->power_hook = alc_power_eapd;
 #endif
@@ -5697,137 +5228,6 @@ static int patch_alc861(struct hda_codec *codec)
 #define alc861vd_loopbacks     alc880_loopbacks
 #endif
 
-/*
- * BIOS auto configuration
- */
-#define alc861vd_is_fixed_pin(nid)     ((nid) >= 0x14 && (nid) <= 0x17)
-#define alc861vd_fixed_pin_idx(nid)    ((nid) - 0x14)
-#define alc861vd_is_multi_pin(nid)     ((nid) >= 0x18)
-#define alc861vd_multi_pin_idx(nid)    ((nid) - 0x18)
-#define alc861vd_idx_to_dac(nid)               ((nid) + 0x02)
-#define alc861vd_dac_to_idx(nid)               ((nid) - 0x02)
-#define alc861vd_idx_to_mixer_vol(nid)         ((nid) + 0x02)
-#define alc861vd_idx_to_mixer_switch(nid)      ((nid) + 0x0c)
-
-/* add playback controls from the parsed DAC table */
-/* Based on ALC880 version. But ALC861VD has separate,
- * different NIDs for mute/unmute switch and volume control */
-static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       hda_nid_t nid_v, nid_s;
-       int i, err, noutputs;
-
-       noutputs = cfg->line_outs;
-       if (spec->multi_ios > 0)
-               noutputs += spec->multi_ios;
-
-       for (i = 0; i < noutputs; i++) {
-               const char *name;
-               int index;
-               if (!spec->multiout.dac_nids[i])
-                       continue;
-               nid_v = alc861vd_idx_to_mixer_vol(
-                               alc861vd_dac_to_idx(
-                                       spec->multiout.dac_nids[i]));
-               nid_s = alc861vd_idx_to_mixer_switch(
-                               alc861vd_dac_to_idx(
-                                       spec->multiout.dac_nids[i]));
-
-               name = alc_get_line_out_pfx(spec, i, true, &index);
-               if (!name) {
-                       /* Center/LFE */
-                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
-                                             "Center",
-                                         HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
-                                             "LFE",
-                                         HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
-                                            "Center",
-                                         HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
-                                                             HDA_INPUT));
-                       if (err < 0)
-                               return err;
-                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
-                                            "LFE",
-                                         HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
-                                                             HDA_INPUT));
-                       if (err < 0)
-                               return err;
-               } else {
-                       err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
-                                               name, index,
-                                         HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
-                                              name, index,
-                                         HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
-                                                             HDA_INPUT));
-                       if (err < 0)
-                               return err;
-               }
-       }
-       return 0;
-}
-
-/* add playback controls for speaker and HP outputs */
-/* Based on ALC880 version. But ALC861VD has separate,
- * different NIDs for mute/unmute switch and volume control */
-static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
-                                       hda_nid_t pin, const char *pfx)
-{
-       hda_nid_t nid_v, nid_s;
-       int err;
-
-       if (!pin)
-               return 0;
-
-       if (alc861vd_is_fixed_pin(pin)) {
-               nid_v = alc861vd_idx_to_dac(alc861vd_fixed_pin_idx(pin));
-               /* specify the DAC as the extra output */
-               if (!spec->multiout.hp_nid)
-                       spec->multiout.hp_nid = nid_v;
-               else
-                       spec->multiout.extra_out_nid[0] = nid_v;
-               /* control HP volume/switch on the output mixer amp */
-               nid_v = alc861vd_idx_to_mixer_vol(
-                               alc861vd_fixed_pin_idx(pin));
-               nid_s = alc861vd_idx_to_mixer_switch(
-                               alc861vd_fixed_pin_idx(pin));
-
-               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
-                                 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-               err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
-                                 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
-               if (err < 0)
-                       return err;
-       } else if (alc861vd_is_multi_pin(pin)) {
-               /* set manual connection */
-               /* we have only a switch on HP-out PIN */
-               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
-                                 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-/* 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
- * Based on ALC880 version - had to change it to override
- * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
 static int alc861vd_parse_auto_config(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -5847,17 +5247,13 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
        err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
        if (err < 0)
                return err;
-       err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc861vd_auto_create_extra_out(spec,
-                                            spec->autocfg.speaker_pins[0],
-                                            "Speaker");
+       err = alc_auto_create_hp_out(codec);
        if (err < 0)
                return err;
-       err = alc861vd_auto_create_extra_out(spec,
-                                            spec->autocfg.hp_pins[0],
-                                            "Headphone");
+       err = alc_auto_create_speaker_out(codec);
        if (err < 0)
                return err;
        err = alc_auto_create_input_ctls(codec);
@@ -5883,19 +5279,6 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec)
        return 1;
 }
 
-/* additional initialization for auto-configuration model */
-static void alc861vd_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc_auto_init_multi_out(codec);
-       alc_auto_init_extra_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);
-}
-
 enum {
        ALC660VD_FIX_ASUS_GPIO1
 };
@@ -6004,7 +5387,7 @@ static int patch_alc861vd(struct hda_codec *codec)
        codec->patch_ops = alc_patch_ops;
 
        if (board_config == ALC_MODEL_AUTO)
-               spec->init_hook = alc861vd_auto_init;
+               spec->init_hook = alc_auto_init_std;
        spec->shutup = alc_eapd_shutup;
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
@@ -6093,19 +5476,6 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
        return 1;
 }
 
-/* additional initialization for auto-configuration model */
-static void alc662_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc_auto_init_multi_out(codec);
-       alc_auto_init_extra_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 void alc272_fixup_mario(struct hda_codec *codec,
                               const struct alc_fixup *fix, int action)
 {
@@ -6126,6 +5496,7 @@ enum {
        ALC272_FIXUP_MARIO,
        ALC662_FIXUP_CZC_P10T,
        ALC662_FIXUP_SKU_IGNORE,
+       ALC662_FIXUP_HP_RP5800,
 };
 
 static const struct alc_fixup alc662_fixups[] = {
@@ -6158,12 +5529,22 @@ static const struct alc_fixup alc662_fixups[] = {
                .type = ALC_FIXUP_SKU,
                .v.sku = ALC_FIXUP_SKU_IGNORE,
        },
+       [ALC662_FIXUP_HP_RP5800] = {
+               .type = ALC_FIXUP_PINS,
+               .v.pins = (const struct alc_pincfg[]) {
+                       { 0x14, 0x0221201f }, /* HP out */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_SKU_IGNORE
+       },
 };
 
 static const 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(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
        SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
@@ -6280,7 +5661,7 @@ static int patch_alc662(struct hda_codec *codec)
 
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC_MODEL_AUTO)
-               spec->init_hook = alc662_auto_init;
+               spec->init_hook = alc_auto_init_std;
        spec->shutup = alc_eapd_shutup;
 
        alc_init_jacks(codec);
@@ -6322,112 +5703,7 @@ static int patch_alc899(struct hda_codec *codec)
 /*
  * ALC680 support
  */
-/* create input playback/capture controls for the given pin */
-static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
-                                   const char *ctlname, int idx)
-{
-       hda_nid_t dac;
-       int err;
 
-       switch (nid) {
-       case 0x14:
-               dac = 0x02;
-               break;
-       case 0x15:
-               dac = 0x03;
-               break;
-       case 0x16:
-               dac = 0x04;
-               break;
-       default:
-               return 0;
-       }
-       if (spec->multiout.dac_nids[0] != dac &&
-           spec->multiout.dac_nids[1] != dac) {
-               err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
-                                 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
-                                                     HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-
-               err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
-                         HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
-
-               if (err < 0)
-                       return err;
-               spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
-       }
-
-       return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
-                                            const struct auto_pin_cfg *cfg)
-{
-       hda_nid_t nid;
-       int err;
-
-       spec->multiout.dac_nids = spec->private_dac_nids;
-
-       nid = cfg->line_out_pins[0];
-       if (nid) {
-               const char *name;
-               int index;
-               name = alc_get_line_out_pfx(spec, 0, true, &index);
-               err = alc680_new_analog_output(spec, nid, name, 0);
-               if (err < 0)
-                       return err;
-       }
-
-       nid = cfg->speaker_pins[0];
-       if (nid) {
-               err = alc680_new_analog_output(spec, nid, "Speaker", 0);
-               if (err < 0)
-                       return err;
-       }
-       nid = cfg->hp_pins[0];
-       if (nid) {
-               err = alc680_new_analog_output(spec, nid, "Headphone", 0);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
-                                             hda_nid_t nid, int pin_type)
-{
-       alc_set_pin_output(codec, nid, pin_type);
-}
-
-static void alc680_auto_init_multi_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t nid = spec->autocfg.line_out_pins[0];
-       if (nid) {
-               int pin_type = get_pin_type(spec->autocfg.line_out_type);
-               alc680_auto_set_output_and_unmute(codec, nid, pin_type);
-       }
-}
-
-static void alc680_auto_init_hp_out(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t pin;
-
-       pin = spec->autocfg.hp_pins[0];
-       if (pin)
-               alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
-       pin = spec->autocfg.speaker_pins[0];
-       if (pin)
-               alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
-}
-
-/*
- * BIOS auto configuration
- */
 static int alc680_parse_auto_config(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -6447,7 +5723,20 @@ static int alc680_parse_auto_config(struct hda_codec *codec)
                }
                return 0; /* can't find valid BIOS pin config */
        }
-       err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
+
+       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;
 
@@ -6474,19 +5763,6 @@ static int alc680_parse_auto_config(struct hda_codec *codec)
        return 1;
 }
 
-/* init callback for auto-configuration model -- overriding the default init */
-static void alc680_auto_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc680_auto_init_multi_out(codec);
-       alc680_auto_init_hp_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);
-}
-
 /*
  */
 #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
@@ -6553,7 +5829,7 @@ static int patch_alc680(struct hda_codec *codec)
 
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC_MODEL_AUTO)
-               spec->init_hook = alc680_auto_init;
+               spec->init_hook = alc_auto_init_std;
 
        return 0;
 }
This page took 0.043053 seconds and 5 git commands to generate.