[alsa-devel] [PATCH v2] ALSA: hda - Enable mic mute hotkey and LEDs for an HP machine

Takashi Iwai tiwai at suse.de
Wed Jan 7 15:59:52 CET 2015


At Wed,  7 Jan 2015 15:50:13 +0100,
David Henningsson wrote:
> 
> 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 <keng-yu.lin at canonical.com>
> Signed-off-by: David Henningsson <david.henningsson at canonical.com>
> ---
> 
> Changes since v1 (which was by mistake not posted to alsa-devel)
>  - fixes according to Takashi's review comments

Thanks, applied now.


Takashi

> 
>  sound/pci/hda/patch_realtek.c | 88 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 88 insertions(+)
> 
> diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
> index 65f1f4e..09d2131 100644
> --- a/sound/pci/hda/patch_realtek.c
> +++ b/sound/pci/hda/patch_realtek.c
> @@ -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,9 @@ struct alc_spec {
>  	hda_nid_t pll_nid;
>  	unsigned int pll_coef_idx, pll_coef_bit;
>  	unsigned int coef0;
> +#if IS_ENABLED(CONFIG_INPUT)
> +	struct input_dev *kb_dev;
> +#endif
>  };
>  
>  /*
> @@ -3472,6 +3476,84 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
>  	}
>  }
>  
> +#if IS_ENABLED(CONFIG_INPUT)
> +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);
> +}
> +#endif
> +
> +static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
> +					     const struct hda_fixup *fix, int action)
> +{
> +#if IS_ENABLED(CONFIG_INPUT)
> +	/* 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);
> +		input_free_device(spec->kb_dev);
> +		spec->kb_dev = NULL;
> +	}
> +#endif
> +}
> +
>  static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
>  				const struct hda_fixup *fix, int action)
>  {
> @@ -4341,6 +4423,7 @@ enum {
>  	ALC282_FIXUP_ASPIRE_V5_PINS,
>  	ALC280_FIXUP_HP_GPIO4,
>  	ALC286_FIXUP_HP_GPIO_LED,
> +	ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY,
>  };
>  
>  static const struct hda_fixup alc269_fixups[] = {
> @@ -4814,6 +4897,10 @@ 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,
> +	},
>  };
>  
>  static const struct snd_pci_quirk alc269_fixup_tbl[] = {
> @@ -4843,6 +4930,7 @@ 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, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
>  	SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
> -- 
> 1.9.1
> 


More information about the Alsa-devel mailing list