diff mbox

[v2,1/2] ALSA: hda - Add mic mute hotkey quirk for Lenovo ThinkCentre AIO

Message ID 1451273725-28359-1-git-send-email-hui.wang@canonical.com (mailing list archive)
State New, archived
Headers show

Commit Message

Hui Wang Dec. 28, 2015, 3:35 a.m. UTC
From: Kailang <kailang@realtek.com>

The Lenovo ThinkCenter AIO uses Line2 (NID 0x1b) to implement the
micmute hotkey, here we register an input device and use Line2 unsol
event to collect the hotkey pressing or releasing.

In the meanwhile, the micmute led is controlled by GPIO2, so we
use an existing function alc_fixup_gpio_mic_mute_hook() to control
the led.

[Hui: And there are two places to register the input device, to make
the code simple and clean, move the two same code sections into a
function.]

Cc: <stable@vger.kernel.org>
Signed-off-by: Kailang <kailang@realtek.com>
Signed-off-by: Hui Wang <hui.wang@canonical.com>
---
 sound/pci/hda/patch_realtek.c | 84 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 71 insertions(+), 13 deletions(-)

Comments

Takashi Iwai Dec. 29, 2015, 9:05 a.m. UTC | #1
On Mon, 28 Dec 2015 04:35:24 +0100,
Hui Wang wrote:
> 
> From: Kailang <kailang@realtek.com>
> 
> The Lenovo ThinkCenter AIO uses Line2 (NID 0x1b) to implement the
> micmute hotkey, here we register an input device and use Line2 unsol
> event to collect the hotkey pressing or releasing.
> 
> In the meanwhile, the micmute led is controlled by GPIO2, so we
> use an existing function alc_fixup_gpio_mic_mute_hook() to control
> the led.
> 
> [Hui: And there are two places to register the input device, to make
> the code simple and clean, move the two same code sections into a
> function.]
> 
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Kailang <kailang@realtek.com>
> Signed-off-by: Hui Wang <hui.wang@canonical.com>

Applied both patch.  Thanks.


Takashi

> ---
>  sound/pci/hda/patch_realtek.c | 84 ++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 71 insertions(+), 13 deletions(-)
> 
> diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
> index fe96428..257b839 100644
> --- a/sound/pci/hda/patch_realtek.c
> +++ b/sound/pci/hda/patch_realtek.c
> @@ -3468,6 +3468,29 @@ static void gpio2_mic_hotkey_event(struct hda_codec *codec,
>  	input_sync(spec->kb_dev);
>  }
>  
> +static int alc_register_micmute_input_device(struct hda_codec *codec)
> +{
> +	struct alc_spec *spec = codec->spec;
> +
> +	spec->kb_dev = input_allocate_device();
> +	if (!spec->kb_dev) {
> +		codec_err(codec, "Out of memory (input_allocate_device)\n");
> +		return -ENOMEM;
> +	}
> +	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 -ENOMEM;
> +	}
> +
> +	return 0;
> +}
> +
>  static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
>  					     const struct hda_fixup *fix, int action)
>  {
> @@ -3485,20 +3508,8 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
>  	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");
> +		if (alc_register_micmute_input_device(codec) != 0)
>  			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->core.afg, 0,
> @@ -3528,6 +3539,47 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
>  	}
>  }
>  
> +static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec,
> +					     const struct hda_fixup *fix, int action)
> +{
> +	/* Line2 = mic mute hotkey
> +	   GPIO2 = mic mute LED */
> +	static const struct hda_verb gpio_init[] = {
> +		{ 0x01, AC_VERB_SET_GPIO_MASK, 0x04 },
> +		{ 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 },
> +		{}
> +	};
> +
> +	struct alc_spec *spec = codec->spec;
> +
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		if (alc_register_micmute_input_device(codec) != 0)
> +			return;
> +
> +		snd_hda_add_verbs(codec, gpio_init);
> +		snd_hda_jack_detect_enable_callback(codec, 0x1b,
> +						    gpio2_mic_hotkey_event);
> +
> +		spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
> +		spec->gpio_led = 0;
> +		spec->mute_led_polarity = 0;
> +		spec->gpio_mic_led_mask = 0x04;
> +		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)
>  {
> @@ -4628,6 +4680,7 @@ enum {
>  	ALC275_FIXUP_DELL_XPS,
>  	ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE,
>  	ALC293_FIXUP_LENOVO_SPK_NOISE,
> +	ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
>  };
>  
>  static const struct hda_fixup alc269_fixups[] = {
> @@ -5237,6 +5290,10 @@ static const struct hda_fixup alc269_fixups[] = {
>  		.chained = true,
>  		.chain_id = ALC269_FIXUP_THINKPAD_ACPI
>  	},
> +	[ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = alc233_fixup_lenovo_line2_mic_hotkey,
> +	},
>  };
>  
>  static const struct snd_pci_quirk alc269_fixup_tbl[] = {
> @@ -5386,6 +5443,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
>  	SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK),
>  	SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
>  	SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE),
> +	SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
>  	SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
>  	SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
>  	SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
> -- 
> 1.9.1
>
diff mbox

Patch

diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index fe96428..257b839 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -3468,6 +3468,29 @@  static void gpio2_mic_hotkey_event(struct hda_codec *codec,
 	input_sync(spec->kb_dev);
 }
 
+static int alc_register_micmute_input_device(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+
+	spec->kb_dev = input_allocate_device();
+	if (!spec->kb_dev) {
+		codec_err(codec, "Out of memory (input_allocate_device)\n");
+		return -ENOMEM;
+	}
+	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 -ENOMEM;
+	}
+
+	return 0;
+}
+
 static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
 					     const struct hda_fixup *fix, int action)
 {
@@ -3485,20 +3508,8 @@  static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
 	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");
+		if (alc_register_micmute_input_device(codec) != 0)
 			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->core.afg, 0,
@@ -3528,6 +3539,47 @@  static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
 	}
 }
 
+static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec,
+					     const struct hda_fixup *fix, int action)
+{
+	/* Line2 = mic mute hotkey
+	   GPIO2 = mic mute LED */
+	static const struct hda_verb gpio_init[] = {
+		{ 0x01, AC_VERB_SET_GPIO_MASK, 0x04 },
+		{ 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 },
+		{}
+	};
+
+	struct alc_spec *spec = codec->spec;
+
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		if (alc_register_micmute_input_device(codec) != 0)
+			return;
+
+		snd_hda_add_verbs(codec, gpio_init);
+		snd_hda_jack_detect_enable_callback(codec, 0x1b,
+						    gpio2_mic_hotkey_event);
+
+		spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
+		spec->gpio_led = 0;
+		spec->mute_led_polarity = 0;
+		spec->gpio_mic_led_mask = 0x04;
+		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)
 {
@@ -4628,6 +4680,7 @@  enum {
 	ALC275_FIXUP_DELL_XPS,
 	ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE,
 	ALC293_FIXUP_LENOVO_SPK_NOISE,
+	ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -5237,6 +5290,10 @@  static const struct hda_fixup alc269_fixups[] = {
 		.chained = true,
 		.chain_id = ALC269_FIXUP_THINKPAD_ACPI
 	},
+	[ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc233_fixup_lenovo_line2_mic_hotkey,
+	},
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5386,6 +5443,7 @@  static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE),
+	SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
 	SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
 	SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
 	SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),