Linux Sound subsystem development
 help / color / mirror / Atom feed
* [PATCH] ALSA: hda/realtek: Add quirk for HP Laptop 15-fd0039nt speaker mute LED
@ 2026-08-21 20:57 Habil Eren Türker
  2026-08-23  8:57 ` Takashi Iwai
  0 siblings, 1 reply; 2+ messages in thread
From: Habil Eren Türker @ 2026-08-21 20:57 UTC (permalink / raw)
  To: perex, tiwai; +Cc: alsa-devel, linux-sound, Habil Eren Türker

HP Laptop 15-fd0039nt (SSID 103c:8bb6) has a speaker mute LED that is
controlled via VREF100 on NID 0x1a. Unlike standard implementations, this
device requires PIN_VREF100 (0x24) to turn the LED on and PIN_IN (0x20)
to turn it off, with active-high polarity.

The existing ALC236_FIXUP_HP_MICMUTE_LED_ONLY quirk only handles the
microphone mute LED, so this patch adds a new fixup
ALC236_FIXUP_HP_15_FD0XXX that covers both:
- Mic mute LED via GPIO0 (active-low)
- Speaker mute LED via NID 0x1a VREF100

The patch also adds a custom power_filter to ensure the pin remains
powered during suspend, and a shutdown hook to restore the pin state.

Tested-by: Habil Eren Türker <habilerenturker@hotmail.com>
Signed-off-by: Habil Eren Türker <habilerenturker@hotmail.com>
---
 sound/hda/codecs/realtek/alc269.c | 59 ++++++++++++++++++++++++++-----
 1 file changed, 50 insertions(+), 9 deletions(-)

diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index 01b87267f..d19935be3 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -1364,16 +1364,57 @@ static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
 	alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10);
 }
 
-static void alc236_fixup_hp_micmute_led_only(struct hda_codec *codec,
-				const struct hda_fixup *fix, int action)
+/* Patch for HP 15-fd0xxx (8BB6) Speaker Mute LED & Mic-Mute LED */
+
+static void hp_8bb6_shutup(struct hda_codec *codec)
+{
+	snd_hda_shutup_pins(codec);
+	snd_hda_set_pin_ctl(codec, 0x1a,
+			   snd_hda_codec_get_pin_target(codec, 0x1a));
+}
+
+static unsigned int hp_8bb6_power_filter(struct hda_codec *codec,
+					  hda_nid_t nid,
+					  unsigned int power_state)
+{
+	if (nid == 0x1a)
+		return AC_PWRST_D0;
+	return snd_hda_gen_path_power_filter(codec, nid, power_state);
+}
+
+static int hp_8bb6_speaker_mute_led_set(struct led_classdev *led_cdev,
+					 enum led_brightness brightness)
+{
+	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+	unsigned int val = (brightness == LED_OFF) ? PIN_IN : PIN_VREF100;
+
+	snd_hda_set_pin_ctl_cache(codec, 0x1a, val);
+	return 0;
+}
+
+static void alc236_fixup_hp_15_fd0xxx(struct hda_codec *codec,
+				      const struct hda_fixup *fix,
+				      int action)
 {
 	struct alc_spec *spec = codec->spec;
 
-	if (action == HDA_FIXUP_ACT_PRE_PROBE)
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
 		spec->micmute_led_polarity = 1;
-	alc_fixup_hp_gpio_led(codec, action, 0x00, 0x01);
-}
+		alc_fixup_hp_gpio_led(codec, action, 0x00, 0x01);
+		spec->mute_led_polarity = 0;
+		snd_hda_gen_add_mute_led_cdev(codec, hp_8bb6_speaker_mute_led_set);
+		codec->power_filter = hp_8bb6_power_filter;
+		codec->power_save_node = 0;
+		spec->shutup = hp_8bb6_shutup;
+		break;
 
+	case HDA_FIXUP_ACT_INIT:
+		if (spec->gen.vmaster_mute.hook)
+			snd_hda_sync_vmaster_hook(&spec->gen.vmaster_mute);
+		break;
+	}
+}
 static void alc285_fixup_hp_gpio_led(struct hda_codec *codec,
 				const struct hda_fixup *fix, int action)
 {
@@ -4096,7 +4137,7 @@ enum {
 	ALC236_FIXUP_HP_GPIO_LED,
 	ALC236_FIXUP_HP_MUTE_LED,
 	ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF,
-	ALC236_FIXUP_HP_MICMUTE_LED_ONLY,
+	ALC236_FIXUP_HP_15_FD0XXX,
 	ALC236_FIXUP_LENOVO_INV_DMIC,
 	ALC298_FIXUP_SAMSUNG_AMP,
 	ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS,
@@ -5839,9 +5880,9 @@ static const struct hda_fixup alc269_fixups[] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc236_fixup_hp_mute_led_micmute_gpio,
 	},
-	[ALC236_FIXUP_HP_MICMUTE_LED_ONLY] = {
+	[ALC236_FIXUP_HP_15_FD0XXX] = {
 		.type = HDA_FIXUP_FUNC,
-		.v.func = alc236_fixup_hp_micmute_led_only,
+		.v.func = alc236_fixup_hp_15_fd0xxx,
 	},
 	[ALC236_FIXUP_LENOVO_INV_DMIC] = {
 		.type = HDA_FIXUP_FUNC,
@@ -7345,7 +7386,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
 	SND_PCI_QUIRK(0x103c, 0x8bb3, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2),
 	SND_PCI_QUIRK(0x103c, 0x8bb4, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2),
-	SND_PCI_QUIRK(0x103c, 0x8bb6, "HP Laptop 15-fd0039nt", ALC236_FIXUP_HP_MICMUTE_LED_ONLY),
+	SND_PCI_QUIRK(0x103c, 0x8bb6, "HP Laptop 15-fd0039nt", ALC236_FIXUP_HP_15_FD0XXX),
 	SND_PCI_QUIRK(0x103c, 0x8bbe, "HP Victus 16-r0xxx (MB 8BBE)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
 	SND_PCI_QUIRK(0x103c, 0x8bc8, "HP Victus 15-fa1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
 	SND_PCI_QUIRK(0x103c, 0x8bcd, "HP Omen 16-xd0xxx", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT),
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] ALSA: hda/realtek: Add quirk for HP Laptop 15-fd0039nt speaker mute LED
  2026-08-21 20:57 [PATCH] ALSA: hda/realtek: Add quirk for HP Laptop 15-fd0039nt speaker mute LED Habil Eren Türker
@ 2026-08-23  8:57 ` Takashi Iwai
  0 siblings, 0 replies; 2+ messages in thread
From: Takashi Iwai @ 2026-08-23  8:57 UTC (permalink / raw)
  To: "Habil Eren Türker"
  Cc: perex, tiwai, alsa-devel, linux-sound, Habil Eren Türker

On Fri, 21 Aug 2026 22:57:06 +0200,
Habil Eren Türker wrote:
> 
> HP Laptop 15-fd0039nt (SSID 103c:8bb6) has a speaker mute LED that is
> controlled via VREF100 on NID 0x1a. Unlike standard implementations, this
> device requires PIN_VREF100 (0x24) to turn the LED on and PIN_IN (0x20)
> to turn it off, with active-high polarity.
> 
> The existing ALC236_FIXUP_HP_MICMUTE_LED_ONLY quirk only handles the
> microphone mute LED, so this patch adds a new fixup
> ALC236_FIXUP_HP_15_FD0XXX that covers both:
> - Mic mute LED via GPIO0 (active-low)
> - Speaker mute LED via NID 0x1a VREF100
> 
> The patch also adds a custom power_filter to ensure the pin remains
> powered during suspend, and a shutdown hook to restore the pin state.
> 
> Tested-by: Habil Eren Türker <habilerenturker@hotmail.com>
> Signed-off-by: Habil Eren Türker <habilerenturker@hotmail.com>
> ---
>  sound/hda/codecs/realtek/alc269.c | 59 ++++++++++++++++++++++++++-----
>  1 file changed, 50 insertions(+), 9 deletions(-)
> 
> diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
> index 01b87267f..d19935be3 100644
> --- a/sound/hda/codecs/realtek/alc269.c
> +++ b/sound/hda/codecs/realtek/alc269.c
> @@ -1364,16 +1364,57 @@ static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
>  	alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10);
>  }
>  
> -static void alc236_fixup_hp_micmute_led_only(struct hda_codec *codec,
> -				const struct hda_fixup *fix, int action)
> +/* Patch for HP 15-fd0xxx (8BB6) Speaker Mute LED & Mic-Mute LED */
> +
> +static void hp_8bb6_shutup(struct hda_codec *codec)
> +{
> +	snd_hda_shutup_pins(codec);
> +	snd_hda_set_pin_ctl(codec, 0x1a,
> +			   snd_hda_codec_get_pin_target(codec, 0x1a));
> +}
> +
> +static unsigned int hp_8bb6_power_filter(struct hda_codec *codec,
> +					  hda_nid_t nid,
> +					  unsigned int power_state)
> +{
> +	if (nid == 0x1a)
> +		return AC_PWRST_D0;
> +	return snd_hda_gen_path_power_filter(codec, nid, power_state);
> +}
> +
> +static int hp_8bb6_speaker_mute_led_set(struct led_classdev *led_cdev,
> +					 enum led_brightness brightness)
> +{
> +	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
> +	unsigned int val = (brightness == LED_OFF) ? PIN_IN : PIN_VREF100;
> +
> +	snd_hda_set_pin_ctl_cache(codec, 0x1a, val);
> +	return 0;
> +}
> +
> +static void alc236_fixup_hp_15_fd0xxx(struct hda_codec *codec,
> +				      const struct hda_fixup *fix,
> +				      int action)
>  {
>  	struct alc_spec *spec = codec->spec;
>  
> -	if (action == HDA_FIXUP_ACT_PRE_PROBE)
> +	switch (action) {
> +	case HDA_FIXUP_ACT_PRE_PROBE:
>  		spec->micmute_led_polarity = 1;
> -	alc_fixup_hp_gpio_led(codec, action, 0x00, 0x01);
> -}
> +		alc_fixup_hp_gpio_led(codec, action, 0x00, 0x01);
> +		spec->mute_led_polarity = 0;
> +		snd_hda_gen_add_mute_led_cdev(codec, hp_8bb6_speaker_mute_led_set);
> +		codec->power_filter = hp_8bb6_power_filter;
> +		codec->power_save_node = 0;
> +		spec->shutup = hp_8bb6_shutup;
> +		break;
>  
> +	case HDA_FIXUP_ACT_INIT:
> +		if (spec->gen.vmaster_mute.hook)
> +			snd_hda_sync_vmaster_hook(&spec->gen.vmaster_mute);
> +		break;
> +	}
> +}

Hmm, the whole workarounds look too much.
For example, power_save_node is already turned off as default in
alc269_probe().

And, if the pin-shutup causes a problem, you can simply set
spec->no_shutup_pins flag.

And, this is an enhancement of the existing quirk entry, you can
mention the relevant commit, too.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-08-23  8:57 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-21 20:57 [PATCH] ALSA: hda/realtek: Add quirk for HP Laptop 15-fd0039nt speaker mute LED Habil Eren Türker
2026-08-23  8:57 ` Takashi Iwai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox