Merge branch 'fix/hda' into for-linus
[pandora-kernel.git] / sound / pci / hda / patch_realtek.c
index 3c8773a..1296058 100644 (file)
@@ -220,6 +220,7 @@ enum {
        ALC888_ACER_ASPIRE_4930G,
        ALC888_ACER_ASPIRE_6530G,
        ALC888_ACER_ASPIRE_8930G,
+       ALC888_ACER_ASPIRE_7730G,
        ALC883_MEDION,
        ALC883_MEDION_MD2,
        ALC883_LAPTOP_EAPD,
@@ -231,6 +232,7 @@ enum {
        ALC888_3ST_HP,
        ALC888_6ST_DELL,
        ALC883_MITAC,
+       ALC883_CLEVO_M540R,
        ALC883_CLEVO_M720,
        ALC883_FUJITSU_PI2515,
        ALC888_FUJITSU_XA3530,
@@ -4398,13 +4400,19 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                        if (err < 0)
                                return err;
                } else {
-                       sprintf(name, "%s Playback Volume", chname[i]);
+                       const char *pfx;
+                       if (cfg->line_outs == 1 &&
+                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+                               pfx = "Speaker";
+                       else
+                               pfx = chname[i];
+                       sprintf(name, "%s Playback Volume", pfx);
                        err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
                                          HDA_COMPOSE_AMP_VAL(nid, 3, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
+                       sprintf(name, "%s Playback Switch", pfx);
                        err = add_control(spec, ALC_CTL_BIND_MUTE, name,
                                          HDA_COMPOSE_AMP_VAL(nid, 3, 2,
                                                              HDA_INPUT));
@@ -6011,7 +6019,14 @@ static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
 
        nid = cfg->line_out_pins[0];
        if (nid) {
-               err = alc260_add_playback_controls(spec, nid, "Front", &vols);
+               const char *pfx;
+               if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
+                       pfx = "Master";
+               else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+                       pfx = "Speaker";
+               else
+                       pfx = "Front";
+               err = alc260_add_playback_controls(spec, nid, pfx, &vols);
                if (err < 0)
                        return err;
        }
@@ -6642,6 +6657,52 @@ static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
 
 #define alc883_3ST_6ch_modes   alc882_3ST_6ch_modes
 
+/*
+ * 2ch mode
+ */
+static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { } /* end */
+};
+
+/*
+ * 4ch mode
+ */
+static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+/*
+ * 6ch mode
+ */
+static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
+       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
+       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
+       { } /* end */
+};
+
+static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
+       { 2, alc883_3ST_ch2_clevo_init },
+       { 4, alc883_3ST_ch4_clevo_init },
+       { 6, alc883_3ST_ch6_clevo_init },
+};
+
+
 /*
  * 6ch mode
  */
@@ -6684,9 +6745,9 @@ static struct hda_verb alc885_mbp_ch2_init[] = {
 };
 
 /*
- * 6ch mode
+ * 4ch mode
  */
-static struct hda_verb alc885_mbp_ch6_init[] = {
+static struct hda_verb alc885_mbp_ch4_init[] = {
        { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
        { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
@@ -6695,9 +6756,9 @@ static struct hda_verb alc885_mbp_ch6_init[] = {
        { } /* end */
 };
 
-static struct hda_channel_mode alc885_mbp_6ch_modes[2] = {
+static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
        { 2, alc885_mbp_ch2_init },
-       { 6, alc885_mbp_ch6_init },
+       { 4, alc885_mbp_ch4_init },
 };
 
 /*
@@ -6941,10 +7002,11 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
 };
 
 static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
@@ -7373,14 +7435,18 @@ static struct hda_verb alc885_mbp3_init_verbs[] = {
        {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
        {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* HP mixer */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
        /* Front Pin: output 0 (0x0c) */
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* HP Pin: output 0 (0x0d) */
+       /* HP Pin: output 0 (0x0e) */
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
        {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
        /* Mic (rear) pin: input vref at 80% */
        {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
@@ -7861,8 +7927,9 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
 
 static struct snd_kcontrol_new alc883_targa_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
        HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
@@ -7881,8 +7948,9 @@ static struct snd_kcontrol_new alc883_targa_mixer[] = {
 
 static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
@@ -7894,6 +7962,15 @@ static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       { } /* end */
+};
+
 static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -8115,6 +8192,22 @@ static struct hda_verb alc883_mitac_verbs[] = {
        { } /* end */
 };
 
+static struct hda_verb alc883_clevo_m540r_verbs[] = {
+       /* HP */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       /* Int speaker */
+       /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
+
+       /* enable unsolicited event */
+       /*
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
+       */
+
+       { } /* end */
+};
+
 static struct hda_verb alc883_clevo_m720_verbs[] = {
        /* HP */
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -8471,6 +8564,13 @@ static struct hda_verb alc883_acer_eapd_verbs[] = {
        { }
 };
 
+static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
+       {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       { } /* end */
+};
+
 static void alc888_6st_dell_setup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -8632,6 +8732,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = {
        [ALC888_ACER_ASPIRE_4930G]      = "acer-aspire-4930g",
        [ALC888_ACER_ASPIRE_6530G]      = "acer-aspire-6530g",
        [ALC888_ACER_ASPIRE_8930G]      = "acer-aspire-8930g",
+       [ALC888_ACER_ASPIRE_7730G]      = "acer-aspire-7730g",
        [ALC883_MEDION]         = "medion",
        [ALC883_MEDION_MD2]     = "medion-md2",
        [ALC883_LAPTOP_EAPD]    = "laptop-eapd",
@@ -8643,6 +8744,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = {
        [ALC888_3ST_HP]         = "3stack-hp",
        [ALC888_6ST_DELL]       = "6stack-dell",
        [ALC883_MITAC]          = "mitac",
+       [ALC883_CLEVO_M540R]    = "clevo-m540r",
        [ALC883_CLEVO_M720]     = "clevo-m720",
        [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
        [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
@@ -8678,6 +8780,8 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
                ALC888_ACER_ASPIRE_6530G),
        SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
                ALC888_ACER_ASPIRE_6530G),
+       SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
+               ALC888_ACER_ASPIRE_7730G),
        /* default Acer -- disabled as it causes more problems.
         *    model=auto should work fine now
         */
@@ -8747,6 +8851,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
        SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
        SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
+       SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
        SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
        /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
@@ -8848,10 +8953,11 @@ static struct alc_config_preset alc882_presets[] = {
                .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
                .init_verbs = { alc885_mbp3_init_verbs,
                                alc880_gpio1_init_verbs },
-               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .num_dacs = 2,
                .dac_nids = alc882_dac_nids,
-               .channel_mode = alc885_mbp_6ch_modes,
-               .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes),
+               .hp_nid = 0x04,
+               .channel_mode = alc885_mbp_4ch_modes,
+               .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
                .input_mux = &alc882_capture_source,
                .dig_out_nid = ALC882_DIGOUT_NID,
                .dig_in_nid = ALC882_DIGIN_NID,
@@ -9072,7 +9178,8 @@ static struct alc_config_preset alc882_presets[] = {
                .init_hook = alc882_targa_automute,
        },
        [ALC883_TARGA_8ch_DIG] = {
-               .mixers = { alc883_base_mixer, alc883_chmode_mixer },
+               .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
+                           alc883_chmode_mixer },
                .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
                                alc883_targa_verbs },
                .num_dacs = ARRAY_SIZE(alc883_dac_nids),
@@ -9179,6 +9286,26 @@ static struct alc_config_preset alc882_presets[] = {
                .setup = alc889_acer_aspire_8930g_setup,
                .init_hook = alc_automute_amp,
        },
+       [ALC888_ACER_ASPIRE_7730G] = {
+               .mixers = { alc883_3ST_6ch_mixer,
+                               alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
+                               alc888_acer_aspire_7730G_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
+               .adc_nids = alc883_adc_nids_rev,
+               .capsrc_nids = alc883_capsrc_nids_rev,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
+               .channel_mode = alc883_3ST_6ch_modes,
+               .need_dac_fix = 1,
+               .const_channel_count = 6,
+               .input_mux = &alc883_capture_source,
+               .unsol_event = alc_automute_amp_unsol_event,
+               .setup = alc888_acer_aspire_6530g_setup,
+               .init_hook = alc_automute_amp,
+       },
        [ALC883_MEDION] = {
                .mixers = { alc883_fivestack_mixer,
                            alc883_chmode_mixer },
@@ -9214,6 +9341,21 @@ static struct alc_config_preset alc882_presets[] = {
                .channel_mode = alc883_3ST_2ch_modes,
                .input_mux = &alc883_capture_source,
        },
+       [ALC883_CLEVO_M540R] = {
+               .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
+               .channel_mode = alc883_3ST_6ch_clevo_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_capture_source,
+               /* This machine has the hardware HP auto-muting, thus
+                * we need no software mute via unsol event
+                */
+       },
        [ALC883_CLEVO_M720] = {
                .mixers = { alc883_clevo_m720_mixer },
                .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
@@ -10777,80 +10919,106 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
        { } /* end */
 };
 
+/* 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)
+{
+       char name[32];
+       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;
+       snprintf(name, sizeof(name), "%s Playback Volume", pfx);
+       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_control(spec, ALC_CTL_WIDGET_VOL, name, val);
+}
+
+static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
+                                const char *pfx)
+{
+       char name[32];
+       unsigned long val;
+
+       if (!nid)
+               return 0;
+       snprintf(name, sizeof(name), "%s Playback Switch", pfx);
+       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_control(spec, ALC_CTL_WIDGET_MUTE, name, 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)
 {
-       hda_nid_t nid;
+       const char *pfx;
+       int vbits;
        int err;
 
        spec->multiout.num_dacs = 1;    /* only use one dac */
        spec->multiout.dac_nids = spec->private_dac_nids;
        spec->multiout.dac_nids[0] = 2;
 
-       nid = cfg->line_out_pins[0];
-       if (nid) {
-               err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                 "Front Playback Volume",
-                                 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-               err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                 "Front Playback Switch",
-                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
-               if (err < 0)
-                       return err;
-       }
+       if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
+               pfx = "Master";
+       else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+               pfx = "Speaker";
+       else
+               pfx = "Front";
+       err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx);
+       if (err < 0)
+               return err;
+       err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker");
+       if (err < 0)
+               return err;
+       err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone");
+       if (err < 0)
+               return err;
 
-       nid = cfg->speaker_pins[0];
-       if (nid) {
-               if (nid == 0x16) {
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "Speaker Playback Volume",
-                                         HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                         "Speaker Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(nid, 2, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else {
-                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                         "Speaker Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(nid, 3, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               }
-       }
-       nid = cfg->hp_pins[0];
-       if (nid) {
-               /* spec->multiout.hp_nid = 2; */
-               if (nid == 0x16) {
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                         "Headphone Playback Volume",
-                                         HDA_COMPOSE_AMP_VAL(0x0e, 2, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                         "Headphone Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(nid, 2, 0,
-                                                             HDA_OUTPUT));
-                       if (err < 0)
-                               return err;
-               } else {
-                       err = add_control(spec, ALC_CTL_WIDGET_MUTE,
-                                         "Headphone Playback Switch",
-                                         HDA_COMPOSE_AMP_VAL(nid, 3, 0,
-                                                             HDA_OUTPUT));
-                       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]);
+       if (vbits == 1 || vbits == 2)
+               pfx = "Master"; /* only one mixer is used */
+       else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+               pfx = "Speaker";
+       else
+               pfx = "Front";
+       vbits = 0;
+       err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits);
+       if (err < 0)
+               return err;
+       err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker",
+                                    &vbits);
+       if (err < 0)
+               return err;
+       err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone",
+                                    &vbits);
+       if (err < 0)
+               return err;
        return 0;
 }
 
@@ -12233,6 +12401,42 @@ static int alc268_auto_create_input_ctls(struct hda_codec *codec,
        return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
 }
 
+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 (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_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);
+               alc268_auto_set_output_and_unmute(codec, nid, pin_type);
+       }
+}
+
+static void alc268_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)
+               alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
+       pin = spec->autocfg.speaker_pins[0];
+       if (pin)
+               alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
+}
+
 static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -12241,9 +12445,10 @@ static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
        hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
        unsigned int    dac_vol1, dac_vol2;
 
-       if (speaker_nid) {
+       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));
@@ -12251,6 +12456,7 @@ static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
                                    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,
@@ -12338,8 +12544,6 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
        return 1;
 }
 
-#define alc268_auto_init_multi_out     alc882_auto_init_multi_out
-#define alc268_auto_init_hp_out                alc882_auto_init_hp_out
 #define alc268_auto_init_analog_input  alc882_auto_init_analog_input
 
 /* init callback for auto-configuration model -- overriding the default init */
@@ -12382,8 +12586,11 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = {
                                                ALC268_ACER_ASPIRE_ONE),
        SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
        SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL),
+       /* almost compatible with toshiba but with optional digital outs;
+        * auto-probing seems working fine
+        */
        SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
-                          ALC268_TOSHIBA),
+                          ALC268_AUTO),
        SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
        SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
        SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
@@ -13150,8 +13357,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        return 1;
 }
 
-#define alc269_auto_init_multi_out     alc882_auto_init_multi_out
-#define alc269_auto_init_hp_out                alc882_auto_init_hp_out
+#define alc269_auto_init_multi_out     alc268_auto_init_multi_out
+#define alc269_auto_init_hp_out                alc268_auto_init_hp_out
 #define alc269_auto_init_analog_input  alc882_auto_init_analog_input
 
 
@@ -13175,7 +13382,8 @@ static const char *alc269_models[ALC269_MODEL_LAST] = {
        [ALC269_ASUS_EEEPC_P703]        = "eeepc-p703",
        [ALC269_ASUS_EEEPC_P901]        = "eeepc-p901",
        [ALC269_FUJITSU]                = "fujitsu",
-       [ALC269_LIFEBOOK]               = "lifebook"
+       [ALC269_LIFEBOOK]               = "lifebook",
+       [ALC269_AUTO]                   = "auto",
 };
 
 static struct snd_pci_quirk alc269_cfg_tbl[] = {
@@ -15194,13 +15402,25 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                        if (err < 0)
                                return err;
                } else {
-                       sprintf(name, "%s Playback Volume", chname[i]);
+                       const char *pfx;
+                       if (cfg->line_outs == 1 &&
+                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
+                               if (!cfg->hp_pins)
+                                       pfx = "Speaker";
+                               else
+                                       pfx = "PCM";
+                       } else
+                               pfx = chname[i];
+                       sprintf(name, "%s Playback Volume", pfx);
                        err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
                                          HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
+                       if (cfg->line_outs == 1 &&
+                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+                               pfx = "Speaker";
+                       sprintf(name, "%s Playback Switch", pfx);
                        err = add_control(spec, ALC_CTL_BIND_MUTE, name,
                                          HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
                                                              HDA_INPUT));
@@ -16967,13 +17187,25 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
                        if (err < 0)
                                return err;
                } else {
-                       sprintf(name, "%s Playback Volume", chname[i]);
+                       const char *pfx;
+                       if (cfg->line_outs == 1 &&
+                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
+                               if (!cfg->hp_pins)
+                                       pfx = "Speaker";
+                               else
+                                       pfx = "PCM";
+                       } else
+                               pfx = chname[i];
+                       sprintf(name, "%s Playback Volume", pfx);
                        err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
                                          HDA_COMPOSE_AMP_VAL(nid, 3, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       sprintf(name, "%s Playback Switch", chname[i]);
+                       if (cfg->line_outs == 1 &&
+                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+                               pfx = "Speaker";
+                       sprintf(name, "%s Playback Switch", pfx);
                        err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
                                HDA_COMPOSE_AMP_VAL(alc880_idx_to_mixer(i),
                                                    3, 0, HDA_INPUT));