Skip to content

Commit 33f4acd

Browse files
David Henningssontiwai
authored andcommitted
ALSA: hda - Enable mic mute hotkey and LEDs for an HP machine
On this machine, the mic mute hotkey is connected to GPIO2. We therefore create an extra input device for this key. Also enable LEDs connected to GPIO3 and GPIO4. (Note: if this patch is backported to older kernels, where KEY_MIC_MUTE is not available, change the KEY_MIC_MUTE to KEY_F20, which was previously used for mic mute keys.) BugLink: https://bugs.launchpad.net/bugs/1408295 Tested-by: Keng-Yu Lin <[email protected]> Signed-off-by: David Henningsson <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent 3b6fe95 commit 33f4acd

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

sound/pci/hda/patch_realtek.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/pci.h>
3030
#include <linux/dmi.h>
3131
#include <linux/module.h>
32+
#include <linux/input.h>
3233
#include <sound/core.h>
3334
#include <sound/jack.h>
3435
#include "hda_codec.h"
@@ -120,6 +121,9 @@ struct alc_spec {
120121
hda_nid_t pll_nid;
121122
unsigned int pll_coef_idx, pll_coef_bit;
122123
unsigned int coef0;
124+
#if IS_ENABLED(CONFIG_INPUT)
125+
struct input_dev *kb_dev;
126+
#endif
123127
};
124128

125129
/*
@@ -3472,6 +3476,84 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
34723476
}
34733477
}
34743478

3479+
#if IS_ENABLED(CONFIG_INPUT)
3480+
static void gpio2_mic_hotkey_event(struct hda_codec *codec,
3481+
struct hda_jack_callback *event)
3482+
{
3483+
struct alc_spec *spec = codec->spec;
3484+
3485+
/* GPIO2 just toggles on a keypress/keyrelease cycle. Therefore
3486+
send both key on and key off event for every interrupt. */
3487+
input_report_key(spec->kb_dev, KEY_MICMUTE, 1);
3488+
input_sync(spec->kb_dev);
3489+
input_report_key(spec->kb_dev, KEY_MICMUTE, 0);
3490+
input_sync(spec->kb_dev);
3491+
}
3492+
#endif
3493+
3494+
static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
3495+
const struct hda_fixup *fix, int action)
3496+
{
3497+
#if IS_ENABLED(CONFIG_INPUT)
3498+
/* GPIO1 = set according to SKU external amp
3499+
GPIO2 = mic mute hotkey
3500+
GPIO3 = mute LED
3501+
GPIO4 = mic mute LED */
3502+
static const struct hda_verb gpio_init[] = {
3503+
{ 0x01, AC_VERB_SET_GPIO_MASK, 0x1e },
3504+
{ 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x1a },
3505+
{ 0x01, AC_VERB_SET_GPIO_DATA, 0x02 },
3506+
{}
3507+
};
3508+
3509+
struct alc_spec *spec = codec->spec;
3510+
3511+
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
3512+
spec->kb_dev = input_allocate_device();
3513+
if (!spec->kb_dev) {
3514+
codec_err(codec, "Out of memory (input_allocate_device)\n");
3515+
return;
3516+
}
3517+
spec->kb_dev->name = "Microphone Mute Button";
3518+
spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY);
3519+
spec->kb_dev->keybit[BIT_WORD(KEY_MICMUTE)] = BIT_MASK(KEY_MICMUTE);
3520+
if (input_register_device(spec->kb_dev)) {
3521+
codec_err(codec, "input_register_device failed\n");
3522+
input_free_device(spec->kb_dev);
3523+
spec->kb_dev = NULL;
3524+
return;
3525+
}
3526+
3527+
snd_hda_add_verbs(codec, gpio_init);
3528+
snd_hda_codec_write_cache(codec, codec->afg, 0,
3529+
AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x04);
3530+
snd_hda_jack_detect_enable_callback(codec, codec->afg,
3531+
gpio2_mic_hotkey_event);
3532+
3533+
spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
3534+
spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
3535+
spec->gpio_led = 0;
3536+
spec->mute_led_polarity = 0;
3537+
spec->gpio_mute_led_mask = 0x08;
3538+
spec->gpio_mic_led_mask = 0x10;
3539+
return;
3540+
}
3541+
3542+
if (!spec->kb_dev)
3543+
return;
3544+
3545+
switch (action) {
3546+
case HDA_FIXUP_ACT_PROBE:
3547+
spec->init_amp = ALC_INIT_DEFAULT;
3548+
break;
3549+
case HDA_FIXUP_ACT_FREE:
3550+
input_unregister_device(spec->kb_dev);
3551+
input_free_device(spec->kb_dev);
3552+
spec->kb_dev = NULL;
3553+
}
3554+
#endif
3555+
}
3556+
34753557
static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
34763558
const struct hda_fixup *fix, int action)
34773559
{
@@ -4341,6 +4423,7 @@ enum {
43414423
ALC282_FIXUP_ASPIRE_V5_PINS,
43424424
ALC280_FIXUP_HP_GPIO4,
43434425
ALC286_FIXUP_HP_GPIO_LED,
4426+
ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY,
43444427
};
43454428

43464429
static const struct hda_fixup alc269_fixups[] = {
@@ -4814,6 +4897,10 @@ static const struct hda_fixup alc269_fixups[] = {
48144897
.type = HDA_FIXUP_FUNC,
48154898
.v.func = alc286_fixup_hp_gpio_led,
48164899
},
4900+
[ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY] = {
4901+
.type = HDA_FIXUP_FUNC,
4902+
.v.func = alc280_fixup_hp_gpio2_mic_hotkey,
4903+
},
48174904
};
48184905

48194906
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -4843,6 +4930,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
48434930
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
48444931
SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
48454932
SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED),
4933+
SND_PCI_QUIRK(0x103c, 0x225f, "HP", ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY),
48464934
/* ALC282 */
48474935
SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
48484936
SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),

0 commit comments

Comments
 (0)