Merge branch 'fix/hda' into topic/hda
[linux-2.6-block.git] / sound / pci / hda / patch_realtek.c
index 141ff446104ab30b169727681ced2368f72172a5..c53faa959390458c8de34c30f928fa349f0dac5f 100644 (file)
@@ -1097,6 +1097,16 @@ static void alc889_coef_init(struct hda_codec *codec)
        snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
 }
 
+/* turn on/off EAPD control (only if available) */
+static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
+{
+       if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+               return;
+       if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
+                                   on ? 2 : 0);
+}
+
 static void alc_auto_init_amp(struct hda_codec *codec, int type)
 {
        unsigned int tmp;
@@ -1114,25 +1124,22 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
        case ALC_INIT_DEFAULT:
                switch (codec->vendor_id) {
                case 0x10ec0260:
-                       snd_hda_codec_write(codec, 0x0f, 0,
-                                           AC_VERB_SET_EAPD_BTLENABLE, 2);
-                       snd_hda_codec_write(codec, 0x10, 0,
-                                           AC_VERB_SET_EAPD_BTLENABLE, 2);
+                       set_eapd(codec, 0x0f, 1);
+                       set_eapd(codec, 0x10, 1);
                        break;
                case 0x10ec0262:
                case 0x10ec0267:
                case 0x10ec0268:
                case 0x10ec0269:
+               case 0x10ec0270:
                case 0x10ec0272:
                case 0x10ec0660:
                case 0x10ec0662:
                case 0x10ec0663:
                case 0x10ec0862:
                case 0x10ec0889:
-                       snd_hda_codec_write(codec, 0x14, 0,
-                                           AC_VERB_SET_EAPD_BTLENABLE, 2);
-                       snd_hda_codec_write(codec, 0x15, 0,
-                                           AC_VERB_SET_EAPD_BTLENABLE, 2);
+                       set_eapd(codec, 0x14, 1);
+                       set_eapd(codec, 0x15, 1);
                        break;
                }
                switch (codec->vendor_id) {
@@ -1234,6 +1241,8 @@ static void alc_init_auto_mic(struct hda_codec *codec)
                        return; /* invalid entry */
                }
        }
+       if (!ext || !fixed)
+               return;
        if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
                return; /* no unsol support */
        snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n",
@@ -3720,25 +3729,22 @@ static void alc_power_eapd(struct hda_codec *codec)
        /* We currently only handle front, HP */
        switch (codec->vendor_id) {
        case 0x10ec0260:
-               snd_hda_codec_write(codec, 0x0f, 0,
-                                   AC_VERB_SET_EAPD_BTLENABLE, 0x00);
-               snd_hda_codec_write(codec, 0x10, 0,
-                                   AC_VERB_SET_EAPD_BTLENABLE, 0x00);
+               set_eapd(codec, 0x0f, 0);
+               set_eapd(codec, 0x10, 0);
                break;
        case 0x10ec0262:
        case 0x10ec0267:
        case 0x10ec0268:
        case 0x10ec0269:
+       case 0x10ec0270:
        case 0x10ec0272:
        case 0x10ec0660:
        case 0x10ec0662:
        case 0x10ec0663:
        case 0x10ec0862:
        case 0x10ec0889:
-               snd_hda_codec_write(codec, 0x14, 0,
-                                   AC_VERB_SET_EAPD_BTLENABLE, 0x00);
-               snd_hda_codec_write(codec, 0x15, 0,
-                                   AC_VERB_SET_EAPD_BTLENABLE, 0x00);
+               set_eapd(codec, 0x14, 0);
+               set_eapd(codec, 0x15, 0);
                break;
        }
 }
@@ -4917,6 +4923,49 @@ static void fixup_automic_adc(struct hda_codec *codec)
        spec->auto_mic = 0; /* disable auto-mic to be sure */
 }
 
+/* choose the ADC/MUX containing the input pin and initialize the setup */
+static void fixup_single_adc(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t pin;
+       int i;
+
+       /* search for the input pin; there must be only one */
+       for (i = 0; i < AUTO_PIN_LAST; i++) {
+               if (spec->autocfg.input_pins[i]) {
+                       pin = spec->autocfg.input_pins[i];
+                       break;
+               }
+       }
+       if (!pin)
+               return;
+
+       /* set the default connection to that pin */
+       for (i = 0; i < spec->num_adc_nids; i++) {
+               hda_nid_t cap = spec->capsrc_nids ?
+                       spec->capsrc_nids[i] : spec->adc_nids[i];
+               int idx;
+
+               idx = get_connection_index(codec, cap, pin);
+               if (idx < 0)
+                       continue;
+               /* use only this ADC */
+               if (spec->capsrc_nids)
+                       spec->capsrc_nids += i;
+               spec->adc_nids += i;
+               spec->num_adc_nids = 1;
+               /* select or unmute this route */
+               if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
+                       snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
+                                                HDA_AMP_MUTE, 0);
+               } else {
+                       snd_hda_codec_write_cache(codec, cap, 0,
+                                         AC_VERB_SET_CONNECT_SEL, idx);
+               }
+               return;
+       }
+}
+
 static void set_capture_mixer(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -4929,14 +4978,15 @@ static void set_capture_mixer(struct hda_codec *codec)
                  alc_capture_mixer3 },
        };
        if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
-               int mux;
-               if (spec->auto_mic) {
-                       mux = 0;
+               int mux = 0;
+               if (spec->auto_mic)
                        fixup_automic_adc(codec);
-               } else if (spec->input_mux && spec->input_mux->num_items > 1)
-                       mux = 1;
-               else
-                       mux = 0;
+               else if (spec->input_mux) {
+                       if (spec->input_mux->num_items > 1)
+                               mux = 1;
+                       else if (spec->input_mux->num_items == 1)
+                               fixup_single_adc(codec);
+               }
                spec->cap_mixer = caps[mux][spec->num_adc_nids - 1];
        }
 }
@@ -7201,8 +7251,8 @@ static struct snd_kcontrol_new alc885_mb5_mixer[] = {
        HDA_BIND_MUTE   ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
        HDA_BIND_MUTE   ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("HP Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("HP Playback Switch", 0x0f, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE   ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
        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, 0x01, HDA_INPUT),
@@ -7603,6 +7653,7 @@ static struct hda_verb alc885_mb5_init_verbs[] = {
        {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, 0x03},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
        /* Front Mic pin: input vref at 80% */
        {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
        {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
@@ -7787,6 +7838,27 @@ static void alc885_mbp3_setup(struct hda_codec *codec)
        spec->autocfg.speaker_pins[0] = 0x14;
 }
 
+static void alc885_mb5_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+
+       present = snd_hda_codec_read(codec, 0x14, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+       snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0,
+                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
+
+}
+
+static void alc885_mb5_unsol_event(struct hda_codec *codec,
+                                   unsigned int res)
+{
+       /* Headphone insertion or removal. */
+       if ((res >> 26) == ALC880_HP_EVENT)
+               alc885_mb5_automute(codec);
+}
+
 static void alc885_imac91_automute(struct hda_codec *codec)
 {
        unsigned int present;
@@ -9233,6 +9305,8 @@ static struct alc_config_preset alc882_presets[] = {
                .input_mux = &mb5_capture_source,
                .dig_out_nid = ALC882_DIGOUT_NID,
                .dig_in_nid = ALC882_DIGIN_NID,
+               .unsol_event = alc885_mb5_unsol_event,
+               .init_hook = alc885_mb5_automute,
        },
        [ALC885_MACPRO] = {
                .mixers = { alc882_macpro_mixer },
@@ -11310,7 +11384,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
 }
 
 #define alc262_auto_create_input_ctls \
-       alc880_auto_create_input_ctls
+       alc882_auto_create_input_ctls
 
 /*
  * generic initialization of ADC, input mixers and output mixers
@@ -12605,6 +12679,7 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
                dac = 0x02;
                break;
        case 0x15:
+       case 0x21:
                dac = 0x03;
                break;
        default:
@@ -14991,6 +15066,8 @@ static int patch_alc861(struct hda_codec *codec)
        spec->stream_digital_playback = &alc861_pcm_digital_playback;
        spec->stream_digital_capture = &alc861_pcm_digital_capture;
 
+       if (!spec->cap_mixer)
+               set_capture_mixer(codec);
        set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
 
        spec->vmaster_nid = 0x03;
@@ -15633,7 +15710,7 @@ static struct alc_config_preset alc861vd_presets[] = {
 static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
+       return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x22, 0);
 }
 
 
@@ -17391,7 +17468,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
        SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
        SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
                      ALC662_3ST_6ch_DIG),
-       SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB200", ALC663_ASUS_MODE4),
+       SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
        SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
                      ALC662_3ST_6ch_DIG),