Merge branch 'topic/hda' into for-linus
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / sound / pci / hda / patch_realtek.c
index b4f78952381a911e2cdb0ce7aa2aa906a013a7a1..51c08edd75636d6e30a580144fa6f2a2999f9eff 100644 (file)
@@ -2026,6 +2026,7 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
        { }
 };
 
@@ -5068,6 +5069,25 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
        return 0;
 }
 
+static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg,
+                                       bool can_be_master)
+{
+       if (!cfg->hp_outs && !cfg->speaker_outs && can_be_master)
+               return "Master";
+
+       switch (cfg->line_out_type) {
+       case AUTO_PIN_SPEAKER_OUT:
+               return "Speaker";
+       case AUTO_PIN_HP_OUT:
+               return "Headphone";
+       default:
+               if (cfg->line_outs == 1)
+                       return "PCM";
+               break;
+       }
+       return NULL;
+}
+
 /* add playback controls from the parsed DAC table */
 static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                                             const struct auto_pin_cfg *cfg)
@@ -5075,6 +5095,7 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
        static const char *chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
+       const char *pfx = alc_get_line_out_pfx(cfg, false);
        hda_nid_t nid;
        int i, err;
 
@@ -5082,7 +5103,7 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                if (!spec->multiout.dac_nids[i])
                        continue;
                nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
-               if (i == 2) {
+               if (!pfx && i == 2) {
                        /* Center/LFE */
                        err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
                                              "Center",
@@ -5109,18 +5130,17 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                        if (err < 0)
                                return err;
                } else {
-                       const char *pfx;
-                       if (cfg->line_outs == 1 &&
-                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-                               pfx = "Speaker";
-                       else
-                               pfx = chname[i];
-                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
+                       const char *name = pfx;
+                       if (!name)
+                               name = chname[i];
+                       err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+                                               name, i,
                                          HDA_COMPOSE_AMP_VAL(nid, 3, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
+                       err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+                                              name, i,
                                          HDA_COMPOSE_AMP_VAL(nid, 3, 2,
                                                              HDA_INPUT));
                        if (err < 0)
@@ -10853,6 +10873,9 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec)
        return 0;
 }
 
+static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
+                                            const struct auto_pin_cfg *cfg);
+
 /* almost identical with ALC880 parser... */
 static int alc882_parse_auto_config(struct hda_codec *codec)
 {
@@ -10870,7 +10893,10 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
        err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       if (codec->vendor_id == 0x10ec0887)
+               err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       else
+               err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
        err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
@@ -12085,13 +12111,8 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
        spec->multiout.dac_nids = spec->private_dac_nids;
        spec->multiout.dac_nids[0] = 2;
 
-       if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
-               pfx = "Master";
-       else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-               pfx = "Speaker";
-       else if (cfg->line_out_type == AUTO_PIN_HP_OUT)
-               pfx = "Headphone";
-       else
+       pfx = alc_get_line_out_pfx(cfg, true);
+       if (!pfx)
                pfx = "Front";
        for (i = 0; i < 2; i++) {
                err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
@@ -14800,12 +14821,23 @@ static int alc269_resume(struct hda_codec *codec)
 }
 #endif /* SND_HDA_NEEDS_RESUME */
 
+static void alc269_fixup_hweq(struct hda_codec *codec,
+                              const struct alc_fixup *fix, int pre_init)
+{
+       int coef;
+
+       coef = alc_read_coef_idx(codec, 0x1e);
+       alc_write_coef_idx(codec, 0x1e, coef | 0x80);
+}
+
 enum {
        ALC269_FIXUP_SONY_VAIO,
        ALC275_FIX_SONY_VAIO_GPIO2,
        ALC269_FIXUP_DELL_M101Z,
        ALC269_FIXUP_SKU_IGNORE,
        ALC269_FIXUP_ASUS_G73JW,
+       ALC269_FIXUP_LENOVO_EAPD,
+       ALC275_FIXUP_SONY_HWEQ,
 };
 
 static const struct alc_fixup alc269_fixups[] = {
@@ -14820,6 +14852,7 @@ static const struct alc_fixup alc269_fixups[] = {
                        {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
                        {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
                        {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+                       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
                        { }
                }
        },
@@ -14840,17 +14873,34 @@ static const struct alc_fixup alc269_fixups[] = {
                        { }
                }
        },
+       [ALC269_FIXUP_LENOVO_EAPD] = {
+               .verbs = (const struct hda_verb[]) {
+                       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
+                       {}
+               }
+       },
+       [ALC275_FIXUP_SONY_HWEQ] = {
+               .func = alc269_fixup_hweq,
+               .verbs = (const struct hda_verb[]) {
+                       {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
+                       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
+                       {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+                       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
+                       { }
+               }
+       }
 };
 
 static struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
-       SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
-       SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIX_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),
        SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
        SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
+       SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
        {}
 };
 
@@ -15885,13 +15935,16 @@ static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
        return 0;
 }
 
-static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
-                               hda_nid_t nid, unsigned int chs)
+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,
+       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)
@@ -15900,26 +15953,15 @@ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
        static const char *chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
+       const char *pfx = alc_get_line_out_pfx(cfg, true);
        hda_nid_t nid;
        int i, err;
 
-       if (cfg->line_outs == 1) {
-               const char *pfx = NULL;
-               if (!cfg->hp_outs)
-                       pfx = "Master";
-               else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-                       pfx = "Speaker";
-               if (pfx) {
-                       nid = spec->multiout.dac_nids[0];
-                       return alc861_create_out_sw(codec, pfx, nid, 3);
-               }
-       }
-
        for (i = 0; i < cfg->line_outs; i++) {
                nid = spec->multiout.dac_nids[i];
                if (!nid)
                        continue;
-               if (i == 2) {
+               if (!pfx && i == 2) {
                        /* Center/LFE */
                        err = alc861_create_out_sw(codec, "Center", nid, 1);
                        if (err < 0)
@@ -15928,7 +15970,10 @@ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
                        if (err < 0)
                                return err;
                } else {
-                       err = alc861_create_out_sw(codec, chname[i], nid, 3);
+                       const char *name = pfx;
+                       if (!name)
+                               name = chname[i];
+                       err = __alc861_create_out_sw(codec, name, nid, i, 3);
                        if (err < 0)
                                return err;
                }
@@ -17027,12 +17072,13 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
 #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,
+/* Based on ALC880 version. But ALC861VD and ALC887 have 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)
 {
        static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
+       const char *pfx = alc_get_line_out_pfx(cfg, true);
        hda_nid_t nid_v, nid_s;
        int i, err;
 
@@ -17046,7 +17092,7 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                                alc880_dac_to_idx(
                                        spec->multiout.dac_nids[i]));
 
-               if (i == 2) {
+               if (!pfx && i == 2) {
                        /* Center/LFE */
                        err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
                                              "Center",
@@ -17073,24 +17119,17 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                        if (err < 0)
                                return err;
                } else {
-                       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];
-                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
+                       const char *name = pfx;
+                       if (!name)
+                               name = chname[i];
+                       err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+                                               name, i,
                                          HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       if (cfg->line_outs == 1 &&
-                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-                               pfx = "Speaker";
-                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
+                       err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+                                              name, i,
                                          HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
                                                              HDA_INPUT));
                        if (err < 0)
@@ -19078,20 +19117,24 @@ static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
        return 0;
 }
 
-static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
-                             hda_nid_t nid, unsigned int chs)
+static inline int __alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
+                                      hda_nid_t nid, int idx, unsigned int chs)
 {
-       return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
+       return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx,
                           HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
 }
 
-static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
-                            hda_nid_t nid, unsigned int chs)
+static inline int __alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
+                                     hda_nid_t nid, int idx, unsigned int chs)
 {
-       return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
+       return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
                           HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
 }
 
+#define alc662_add_vol_ctl(spec, pfx, nid, chs) \
+       __alc662_add_vol_ctl(spec, pfx, nid, 0, chs)
+#define alc662_add_sw_ctl(spec, pfx, nid, chs) \
+       __alc662_add_sw_ctl(spec, pfx, nid, 0, chs)
 #define alc662_add_stereo_vol(spec, pfx, nid) \
        alc662_add_vol_ctl(spec, pfx, nid, 3)
 #define alc662_add_stereo_sw(spec, pfx, nid) \
@@ -19105,6 +19148,7 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
        static const char *chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
+       const char *pfx = alc_get_line_out_pfx(cfg, true);
        hda_nid_t nid, mix;
        int i, err;
 
@@ -19115,7 +19159,7 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
                mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
                if (!mix)
                        continue;
-               if (i == 2) {
+               if (!pfx && i == 2) {
                        /* Center/LFE */
                        err = alc662_add_vol_ctl(spec, "Center", nid, 1);
                        if (err < 0)
@@ -19130,22 +19174,13 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
                        if (err < 0)
                                return err;
                } else {
-                       const char *pfx;
-                       if (cfg->line_outs == 1 &&
-                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
-                               if (cfg->hp_outs)
-                                       pfx = "Speaker";
-                               else
-                                       pfx = "PCM";
-                       } else
-                               pfx = chname[i];
-                       err = alc662_add_vol_ctl(spec, pfx, nid, 3);
+                       const char *name = pfx;
+                       if (!name)
+                               name = chname[i];
+                       err = __alc662_add_vol_ctl(spec, name, nid, i, 3);
                        if (err < 0)
                                return err;
-                       if (cfg->line_outs == 1 &&
-                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-                               pfx = "Speaker";
-                       err = alc662_add_sw_ctl(spec, pfx, mix, 3);
+                       err = __alc662_add_sw_ctl(spec, name, mix, i, 3);
                        if (err < 0)
                                return err;
                }