ALSA: hda - add dock support for Thinkpad T430
[pandora-kernel.git] / sound / pci / hda / patch_realtek.c
index 3d440fc..2c62edd 100644 (file)
@@ -594,7 +594,7 @@ static void call_update_outputs(struct hda_codec *codec)
 }
 
 /* standard HP-automute helper */
-static void alc_hp_automute(struct hda_codec *codec)
+static void alc_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
 {
        struct alc_spec *spec = codec->spec;
 
@@ -607,10 +607,12 @@ static void alc_hp_automute(struct hda_codec *codec)
 }
 
 /* standard line-out-automute helper */
-static void alc_line_automute(struct hda_codec *codec)
+static void alc_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
 {
        struct alc_spec *spec = codec->spec;
 
+       if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
+               return;
        /* check LO jack only when it's different from HP */
        if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
                return;
@@ -627,7 +629,7 @@ static void alc_line_automute(struct hda_codec *codec)
        snd_hda_get_conn_index(codec, mux, nid, 0)
 
 /* standard mic auto-switch helper */
-static void alc_mic_automute(struct hda_codec *codec)
+static void alc_mic_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
 {
        struct alc_spec *spec = codec->spec;
        hda_nid_t *pins = spec->imux_pins;
@@ -648,25 +650,8 @@ static void alc_mic_automute(struct hda_codec *codec)
                alc_mux_select(codec, 0, spec->int_mic_idx, false);
 }
 
-/* handle the specified unsol action (ALC_XXX_EVENT) */
-static void alc_exec_unsol_event(struct hda_codec *codec, int action)
-{
-       switch (action) {
-       case ALC_HP_EVENT:
-               alc_hp_automute(codec);
-               break;
-       case ALC_FRONT_EVENT:
-               alc_line_automute(codec);
-               break;
-       case ALC_MIC_EVENT:
-               alc_mic_automute(codec);
-               break;
-       }
-       snd_hda_jack_report_sync(codec);
-}
-
 /* update the master volume per volume-knob's unsol event */
-static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid)
+static void alc_update_knob_master(struct hda_codec *codec, struct hda_jack_tbl *jack)
 {
        unsigned int val;
        struct snd_kcontrol *kctl;
@@ -678,7 +663,7 @@ static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid)
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
        if (!uctl)
                return;
-       val = snd_hda_codec_read(codec, nid, 0,
+       val = snd_hda_codec_read(codec, jack->nid, 0,
                                 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
        val &= HDA_AMP_VOLMASK;
        uctl->value.integer.value[0] = val;
@@ -687,37 +672,19 @@ static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid)
        kfree(uctl);
 }
 
-/* unsolicited event for HP jack sensing */
-static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
+static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       int action;
-
-       if (codec->vendor_id == 0x10ec0880)
-               res >>= 28;
-       else
-               res >>= 26;
-       action = snd_hda_jack_get_action(codec, res);
-       if (action == ALC_DCVOL_EVENT) {
-               /* Execute the dc-vol event here as it requires the NID
-                * but we don't pass NID to alc_exec_unsol_event().
-                * Once when we convert all static quirks to the auto-parser,
-                * this can be integerated into there.
-                */
-               struct hda_jack_tbl *jack;
-               jack = snd_hda_jack_tbl_get_from_tag(codec, res);
-               if (jack)
-                       alc_update_knob_master(codec, jack->nid);
-               return;
-       }
-       alc_exec_unsol_event(codec, action);
+       /* For some reason, the res given from ALC880 is broken.
+          Here we adjust it properly. */
+       snd_hda_jack_unsol_event(codec, res >> 2);
 }
 
 /* call init functions of standard auto-mute helpers */
 static void alc_inithook(struct hda_codec *codec)
 {
-       alc_hp_automute(codec);
-       alc_line_automute(codec);
-       alc_mic_automute(codec);
+       alc_hp_automute(codec, NULL);
+       alc_line_automute(codec, NULL);
+       alc_mic_automute(codec, NULL);
 }
 
 /* additional initialization for ALC888 variants */
@@ -999,7 +966,8 @@ static void alc_init_automute(struct hda_codec *codec)
                        continue;
                snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
                            nid);
-               snd_hda_jack_detect_enable(codec, nid, ALC_HP_EVENT);
+               snd_hda_jack_detect_enable_callback(codec, nid, ALC_HP_EVENT,
+                                                   alc_hp_automute);
                spec->detect_hp = 1;
        }
 
@@ -1011,10 +979,10 @@ static void alc_init_automute(struct hda_codec *codec)
                                        continue;
                                snd_printdd("realtek: Enable Line-Out "
                                            "auto-muting on NID 0x%x\n", nid);
-                               snd_hda_jack_detect_enable(codec, nid,
-                                                          ALC_FRONT_EVENT);
+                               snd_hda_jack_detect_enable_callback(codec, nid, ALC_FRONT_EVENT,
+                                                                   alc_line_automute);
                                spec->detect_lo = 1;
-               }
+                       }
                spec->automute_lo_possible = spec->detect_hp;
        }
 
@@ -1110,10 +1078,12 @@ static bool alc_auto_mic_check_imux(struct hda_codec *codec)
                return false; /* no corresponding imux */
        }
 
-       snd_hda_jack_detect_enable(codec, spec->ext_mic_pin, ALC_MIC_EVENT);
+       snd_hda_jack_detect_enable_callback(codec, spec->ext_mic_pin,
+                                           ALC_MIC_EVENT, alc_mic_automute);
        if (spec->dock_mic_pin)
-               snd_hda_jack_detect_enable(codec, spec->dock_mic_pin,
-                                          ALC_MIC_EVENT);
+               snd_hda_jack_detect_enable_callback(codec, spec->dock_mic_pin,
+                                                   ALC_MIC_EVENT,
+                                                   alc_mic_automute);
 
        spec->auto_mic_valid_imux = 1;
        spec->auto_mic = 1;
@@ -2473,7 +2443,7 @@ static const struct hda_codec_ops alc_patch_ops = {
        .build_pcms = alc_build_pcms,
        .init = alc_init,
        .free = alc_free,
-       .unsol_event = alc_unsol_event,
+       .unsol_event = snd_hda_jack_unsol_event,
 #ifdef CONFIG_PM
        .resume = alc_resume,
 #endif
@@ -2484,6 +2454,7 @@ static const struct hda_codec_ops alc_patch_ops = {
        .reboot_notify = alc_shutup,
 };
 
+
 /* replace the codec chip_name with the given string */
 static int alc_codec_rename(struct hda_codec *codec, const char *name)
 {
@@ -2627,8 +2598,10 @@ static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
                        return "PCM";
                break;
        }
-       if (snd_BUG_ON(ch >= ARRAY_SIZE(channel_name)))
+       if (ch >= ARRAY_SIZE(channel_name)) {
+               snd_BUG();
                return "PCM";
+       }
 
        return channel_name[ch];
 }
@@ -4276,6 +4249,7 @@ static void alc_auto_init_std(struct hda_codec *codec)
        ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
 
 static const struct snd_pci_quirk beep_white_list[] = {
+       SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
        SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
        SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
        SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
@@ -4447,7 +4421,7 @@ static void alc880_fixup_vol_knob(struct hda_codec *codec,
                                  const struct alc_fixup *fix, int action)
 {
        if (action == ALC_FIXUP_ACT_PROBE)
-               snd_hda_jack_detect_enable(codec, 0x21, ALC_DCVOL_EVENT);
+               snd_hda_jack_detect_enable_callback(codec, 0x21, ALC_DCVOL_EVENT, alc_update_knob_master);
 }
 
 static const struct alc_fixup alc880_fixups[] = {
@@ -4812,6 +4786,8 @@ static int patch_alc880(struct hda_codec *codec)
        }
 
        codec->patch_ops = alc_patch_ops;
+       codec->patch_ops.unsol_event = alc880_unsol_event;
+
 
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
@@ -4866,7 +4842,8 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
                spec->detect_hp = 1;
                spec->automute_speaker = 1;
                spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
-               snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT);
+               snd_hda_jack_detect_enable_callback(codec, 0x0f, ALC_HP_EVENT,
+                                                   alc_hp_automute);
                snd_hda_gen_add_verbs(&spec->gen, alc_gpio1_init_verbs);
        }
 }
@@ -6211,6 +6188,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
@@ -6335,6 +6313,12 @@ static int patch_alc269(struct hda_codec *codec)
 
        spec = codec->spec;
 
+       alc_pick_fixup(codec, alc269_fixup_models,
+                      alc269_fixup_tbl, alc269_fixups);
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+
+       alc_auto_parse_customize_define(codec);
+
        if (codec->vendor_id == 0x10ec0269) {
                spec->codec_variant = ALC269_TYPE_ALC269VA;
                switch (alc_get_coef0(codec) & 0x00f0) {
@@ -6362,12 +6346,6 @@ static int patch_alc269(struct hda_codec *codec)
                alc269_fill_coef(codec);
        }
 
-       alc_pick_fixup(codec, alc269_fixup_models,
-                      alc269_fixup_tbl, alc269_fixups);
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
-
-       alc_auto_parse_customize_define(codec);
-
        /* automatic parse from the BIOS config */
        err = alc269_parse_auto_config(codec);
        if (err < 0)
@@ -7069,6 +7047,8 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
        { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 },
        { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 },
+       { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 },
+       { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 },
        { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
          .patch = patch_alc861 },
        { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },