ALSA: hda - enable mute led quirk for one more hp machine.
[pandora-kernel.git] / sound / pci / hda / patch_realtek.c
index 65f1f4e..b2b24a8 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/pci.h>
 #include <linux/dmi.h>
 #include <linux/module.h>
+#include <linux/input.h>
 #include <sound/core.h>
 #include <sound/jack.h>
 #include "hda_codec.h"
@@ -120,6 +121,7 @@ struct alc_spec {
        hda_nid_t pll_nid;
        unsigned int pll_coef_idx, pll_coef_bit;
        unsigned int coef0;
+       struct input_dev *kb_dev;
 };
 
 /*
@@ -3472,6 +3474,79 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
        }
 }
 
+static void gpio2_mic_hotkey_event(struct hda_codec *codec,
+                                  struct hda_jack_callback *event)
+{
+       struct alc_spec *spec = codec->spec;
+
+       /* GPIO2 just toggles on a keypress/keyrelease cycle. Therefore
+          send both key on and key off event for every interrupt. */
+       input_report_key(spec->kb_dev, KEY_MICMUTE, 1);
+       input_sync(spec->kb_dev);
+       input_report_key(spec->kb_dev, KEY_MICMUTE, 0);
+       input_sync(spec->kb_dev);
+}
+
+static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
+                                            const struct hda_fixup *fix, int action)
+{
+       /* GPIO1 = set according to SKU external amp
+          GPIO2 = mic mute hotkey
+          GPIO3 = mute LED
+          GPIO4 = mic mute LED */
+       static const struct hda_verb gpio_init[] = {
+               { 0x01, AC_VERB_SET_GPIO_MASK, 0x1e },
+               { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x1a },
+               { 0x01, AC_VERB_SET_GPIO_DATA, 0x02 },
+               {}
+       };
+
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->kb_dev = input_allocate_device();
+               if (!spec->kb_dev) {
+                       codec_err(codec, "Out of memory (input_allocate_device)\n");
+                       return;
+               }
+               spec->kb_dev->name = "Microphone Mute Button";
+               spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY);
+               spec->kb_dev->keybit[BIT_WORD(KEY_MICMUTE)] = BIT_MASK(KEY_MICMUTE);
+               if (input_register_device(spec->kb_dev)) {
+                       codec_err(codec, "input_register_device failed\n");
+                       input_free_device(spec->kb_dev);
+                       spec->kb_dev = NULL;
+                       return;
+               }
+
+               snd_hda_add_verbs(codec, gpio_init);
+               snd_hda_codec_write_cache(codec, codec->afg, 0,
+                                         AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x04);
+               snd_hda_jack_detect_enable_callback(codec, codec->afg,
+                                                   gpio2_mic_hotkey_event);
+
+               spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
+               spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
+               spec->gpio_led = 0;
+               spec->mute_led_polarity = 0;
+               spec->gpio_mute_led_mask = 0x08;
+               spec->gpio_mic_led_mask = 0x10;
+               return;
+       }
+
+       if (!spec->kb_dev)
+               return;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PROBE:
+               spec->init_amp = ALC_INIT_DEFAULT;
+               break;
+       case HDA_FIXUP_ACT_FREE:
+               input_unregister_device(spec->kb_dev);
+               spec->kb_dev = NULL;
+       }
+}
+
 static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
                                const struct hda_fixup *fix, int action)
 {
@@ -4341,6 +4416,8 @@ enum {
        ALC282_FIXUP_ASPIRE_V5_PINS,
        ALC280_FIXUP_HP_GPIO4,
        ALC286_FIXUP_HP_GPIO_LED,
+       ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY,
+       ALC280_FIXUP_HP_DOCK_PINS,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -4814,6 +4891,21 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc286_fixup_hp_gpio_led,
        },
+       [ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc280_fixup_hp_gpio2_mic_hotkey,
+       },
+       [ALC280_FIXUP_HP_DOCK_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x21011020 }, /* line-out */
+                       { 0x1a, 0x01a1903c }, /* headset mic */
+                       { 0x18, 0x2181103f }, /* line-in */
+                       { },
+               },
+               .chained = true,
+               .chain_id = ALC280_FIXUP_HP_GPIO4
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -4843,7 +4935,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
        SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x225f, "HP", ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY),
        /* ALC282 */
+       SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2236, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
@@ -4856,6 +4950,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2271, "HP", ALC286_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC280_FIXUP_HP_DOCK_PINS),
+       SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC280_FIXUP_HP_DOCK_PINS),
        SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),