[PATCH v2] ALSA: hda/realtek: Add inverted LED quirk for HP ZBook 8 G2a
From: Chris Chiu
Date: Sun Jul 12 2026 - 22:09:05 EST
HP ZBook 8 G2a 14 and 16 (SSIDs 0x103c:0x8f94, 0x103c:0x8f95) use
Realtek ALC245 codec with TAS2781 amplifier via I2C. These models
require inverted speaker mute LED handling compared to the existing
ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED quirk.
The existing quirk produces opposite LED behavior: when speaker is
muted, the LED turns off (should be on), and when unmuted, the LED
turns on (should be off). This patch adds a dedicated quirk that
properly handles the inverted LED polarity.
Code flow explanation:
- With HP pin (hp_pin != 0): Uses standard HDA LED framework via
alc245_fixup_hp_mute_led_coefbit() for full control interface
support, enabling both manual control and direct hardware updates.
- Without HP pin (hp_pin == 0, speaker-only laptops): Registers
direct vmaster_mute hook (alc245_hp_spk_mute_led_update_inverted)
to control LED during mute operations, ensuring LED feedback
without headphone jack detection capability.
Both paths use inverted LED update logic to correct polarity and
maintain backward compatibility with existing systems.
Signed-off-by: Chris Chiu <chris.chiu@xxxxxxxxxxxxx>
---
sound/hda/codecs/realtek/alc269.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index b26ed9c1f09f..e04b5adce075a 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -3776,6 +3776,15 @@ static void alc245_hp_spk_mute_led_update(void *private_data, int enabled)
alc_update_coef_idx(codec, 0x0b, 0x0c, val);
}
+static void alc245_hp_spk_mute_led_update_inverted(void *private_data, int enabled)
+{
+ struct hda_codec *codec = private_data;
+ unsigned int val;
+
+ val = enabled ? 0x04 : 0x08; /* inverted: 0x04 off, 0x08 on */
+ alc_update_coef_idx(codec, 0x0b, 0x0c, val);
+}
+
/* JD2: mute led GPIO3: micmute led */
static void alc245_tas2781_i2c_hp_fixup_muteled(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
@@ -3804,6 +3813,42 @@ static void alc245_tas2781_i2c_hp_fixup_muteled(struct hda_codec *codec,
alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
alc285_fixup_hp_coef_micmute_led(codec, fix, action);
}
+
+/* Inverted LED version for HP ZBook 8 G2a models (SSIDs 0x8f94, 0x8f95)
+ * This fixup handles systems where the speaker mute LED polarity is reversed
+/* Inverted LED quirk for HP ZBook 8 G2a (SSIDs 0x8f94, 0x8f95)
+ * Speaker mute LED polarity is reversed vs standard behavior.
+ * Code flow depends on HP pin detection availability:
+ * - With HP pin: Uses HDA LED framework for full control support
+ * - Without HP pin: Registers vmaster_mute hook for direct control
+ */
+static void alc245_tas2781_i2c_hp_fixup_muteled_inverted(struct hda_codec *codec,
+const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t hp_pin = alc_get_hp_pin(spec);
+ static const hda_nid_t conn[] = { 0x02 };
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ if (!hp_pin) {
+ /* Speaker-only config without HP pin detection */
+ spec->gen.vmaster_mute.hook = alc245_hp_spk_mute_led_update_inverted;
+ spec->gen.vmaster_mute_led = 1;
+ }
+ spec->gen.auto_mute_via_amp = 1;
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ if (!hp_pin)
+ alc245_hp_spk_mute_led_update_inverted(codec, !spec->gen.master_mute);
+ break;
+ }
+
+ tas2781_fixup_txnw_i2c(codec, fix, action);
+ if (hp_pin)
+ alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
+ alc285_fixup_hp_coef_micmute_led(codec, fix, action);
+}
/*
* Clear COEF 0x0d (PCBEEP passthrough) bit 0x40 where BIOS sets it wrongly
* at PM resume
@@ -4164,6 +4209,7 @@ enum {
ALC256_FIXUP_VAIO_RPL_MIC_NO_PRESENCE,
ALC245_FIXUP_HP_TAS2781_SPI_MUTE_LED,
ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED,
+ ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED_INVERTED,
ALC288_FIXUP_SURFACE_SWAP_DACS,
ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO,
ALC233_FIXUP_LENOVO_GPIO2_MIC_HOTKEY,
@@ -4481,6 +4527,10 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_before = true,
.chain_to = ALC269_FIXUP_HEADSET_MIC,
+ },
+ [ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED_INVERTED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc245_tas2781_i2c_hp_fixup_muteled_inverted,
},
[ALC288_FIXUP_SURFACE_SWAP_DACS] = {
.type = HDA_FIXUP_FUNC,
@@ -4785,6 +4835,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8e86, "HP", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8ec0, "HP", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8f94, "HP", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED_INVERTED),
+ SND_PCI_QUIRK(0x103c, 0x8f95, "HP", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED_INVERTED),
SND_PCI_QUIRK(0x103c, 0x91c6, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
SND_PCI_QUIRK(0x103c, 0x221c, "HP", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x1043, 0x1080, "ASUS K53UT", ALC269_FIXUP_SSID_IGNORED),