[ALSA] hda-codec - Fix ALC880 uniwill auto-mutes
[firefly-linux-kernel-4.4.55.git] / sound / pci / hda / patch_realtek.c
index 61dffb8c57fc8f1abe3add99a7e95cdae1897827..8c0b4fbc1448fda607d63270fb33c07b26c0a3b8 100644 (file)
@@ -1487,7 +1487,7 @@ static struct hda_verb alc880_beep_init_verbs[] = {
 };
 
 /* toggle speaker-output according to the hp-jack state */
-static void alc880_uniwill_automute(struct hda_codec *codec)
+static void alc880_uniwill_hp_automute(struct hda_codec *codec)
 {
        unsigned int present;
        unsigned char bits;
@@ -1503,11 +1503,27 @@ static void alc880_uniwill_automute(struct hda_codec *codec)
                                 0x80, bits);
        snd_hda_codec_amp_update(codec, 0x16, 1, HDA_OUTPUT, 0,
                                 0x80, bits);
+}
+
+/* auto-toggle front mic */
+static void alc880_uniwill_mic_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+       unsigned char bits;
 
        present = snd_hda_codec_read(codec, 0x18, 0,
                                     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
-       snd_hda_codec_write(codec, 0x0b, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           0x7000 | (0x01 << 8) | bits);
+       bits = present ? 0x80 : 0;
+       snd_hda_codec_amp_update(codec, 0x0b, 0, HDA_INPUT, 1,
+                                0x80, bits);
+       snd_hda_codec_amp_update(codec, 0x0b, 1, HDA_INPUT, 1,
+                                0x80, bits);
+}
+
+static void alc880_uniwill_automute(struct hda_codec *codec)
+{
+       alc880_uniwill_hp_automute(codec);
+       alc880_uniwill_mic_automute(codec);
 }
 
 static void alc880_uniwill_unsol_event(struct hda_codec *codec,
@@ -1516,9 +1532,14 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec,
        /* Looks like the unsol event is incompatible with the standard
         * definition.  4bit tag is placed at 28 bit!
         */
-       if ((res >> 28) == ALC880_HP_EVENT ||
-           (res >> 28) == ALC880_MIC_EVENT)
-               alc880_uniwill_automute(codec);
+       switch (res >> 28) {
+       case ALC880_HP_EVENT:
+               alc880_uniwill_hp_automute(codec);
+               break;
+       case ALC880_MIC_EVENT:
+               alc880_uniwill_mic_automute(codec);
+               break;
+       }
 }
 
 static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec)
@@ -3095,6 +3116,14 @@ static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
        }
 }
 
+static int get_pin_type(int line_out_type)
+{
+       if (line_out_type == AUTO_PIN_HP_OUT)
+               return PIN_HP;
+       else
+               return PIN_OUT;
+}
+
 static void alc880_auto_init_multi_out(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -3103,7 +3132,8 @@ static void alc880_auto_init_multi_out(struct hda_codec *codec)
        alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
        for (i = 0; i < spec->autocfg.line_outs; i++) {
                hda_nid_t nid = spec->autocfg.line_out_pins[i];
-               alc880_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
+               int pin_type = get_pin_type(spec->autocfg.line_out_type);
+               alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
        }
 }
 
@@ -4292,8 +4322,10 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec)
 
        alc_subsystem_id(codec, 0x10, 0x15, 0x0f);
        nid = spec->autocfg.line_out_pins[0];
-       if (nid)
-               alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
+       if (nid) {
+               int pin_type = get_pin_type(spec->autocfg.line_out_type);
+               alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
+       }
        
        nid = spec->autocfg.speaker_pins[0];
        if (nid)
@@ -4301,7 +4333,7 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec)
 
        nid = spec->autocfg.hp_pins[0];
        if (nid)
-               alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
+               alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
 }
 
 #define ALC260_PIN_CD_NID              0x16
@@ -5164,8 +5196,9 @@ static void alc882_auto_init_multi_out(struct hda_codec *codec)
        alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
        for (i = 0; i <= HDA_SIDE; i++) {
                hda_nid_t nid = spec->autocfg.line_out_pins[i];
+               int pin_type = get_pin_type(spec->autocfg.line_out_type);
                if (nid)
-                       alc882_auto_set_output_and_unmute(codec, nid, PIN_OUT,
+                       alc882_auto_set_output_and_unmute(codec, nid, pin_type,
                                                          i);
        }
 }
@@ -6185,8 +6218,9 @@ static void alc883_auto_init_multi_out(struct hda_codec *codec)
        alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
        for (i = 0; i <= HDA_SIDE; i++) {
                hda_nid_t nid = spec->autocfg.line_out_pins[i];
+               int pin_type = get_pin_type(spec->autocfg.line_out_type);
                if (nid)
-                       alc883_auto_set_output_and_unmute(codec, nid, PIN_OUT,
+                       alc883_auto_set_output_and_unmute(codec, nid, pin_type,
                                                          i);
        }
 }
@@ -8182,8 +8216,9 @@ static void alc861_auto_init_multi_out(struct hda_codec *codec)
        alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b);
        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);
                if (nid)
-                       alc861_auto_set_output_and_unmute(codec, nid, PIN_OUT,
+                       alc861_auto_set_output_and_unmute(codec, nid, pin_type,
                                                          spec->multiout.dac_nids[i]);
        }
 }
@@ -8294,6 +8329,7 @@ static struct snd_pci_quirk alc861_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
        SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
        SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
+       SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
        SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
        SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660_3ST),
        SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
@@ -8892,9 +8928,10 @@ static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
        alc_subsystem_id(codec, 0x15, 0x1b, 0x14);
        for (i = 0; i <= HDA_SIDE; i++) {
                hda_nid_t nid = spec->autocfg.line_out_pins[i];
+               int pin_type = get_pin_type(spec->autocfg.line_out_type);
                if (nid)
                        alc861vd_auto_set_output_and_unmute(codec, nid,
-                                                               PIN_OUT, i);
+                                                           pin_type, i);
        }
 }
 
@@ -9867,8 +9904,9 @@ static void alc662_auto_init_multi_out(struct hda_codec *codec)
 
        for (i = 0; i <= HDA_SIDE; i++) {
                hda_nid_t nid = spec->autocfg.line_out_pins[i];
+               int pin_type = get_pin_type(spec->autocfg.line_out_type);
                if (nid)
-                       alc662_auto_set_output_and_unmute(codec, nid, PIN_OUT,
+                       alc662_auto_set_output_and_unmute(codec, nid, pin_type,
                                                          i);
        }
 }