Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: hda/realtek: Enable PC beep passthrough for HP EliteBook 855 G7

PC speaker works well on this platform in BIOS and in Linux until sound
card drivers are loaded. Then it stops working.

There seems to be a beep generator node at 0x1a in this CODEC
(ALC269_TYPE_ALC215) but it seems to be only connected to capture mixers
at nodes 0x22 and 0x23.
If I unmute the mixer input for 0x1a at node 0x23 and start recording
from its "ALC285 Analog" capture device I can clearly hear beeps in that
recording.

So the beep generator is indeed working properly, however I wasn't able to
figure out any way to connect it to speakers.

However, the bits in the "Passthrough Control" register (0x36) seems to
work at least partially: by zeroing "B" and "h" and setting "S" I can at
least make the PIT PC speaker output appear either in this laptop speakers
or headphones (depending on whether they are connected or not).

There are some caveats, however:
* If the CODEC gets runtime-suspended the beeps stop so it needs HDA beep
device for keeping it awake during beeping.

* If the beep generator node is generating any beep the PC beep passthrough
seems to be temporarily inhibited, so the HDA beep device has to be
prevented from using the actual beep generator node - but the beep device
is still necessary due to the previous point.

* In contrast with other platforms here beep amplification has to be
disabled otherwise the beeps output are WAY louder than they were on pure
BIOS setup.

Unless someone (from Realtek probably) knows how to make the beep generator
node output appear in speakers / headphones using PC beep passthrough seems
to be the only way to make PC speaker beeping actually work on this
platform.

Signed-off-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
Acked-by: kailang@realtek.com
Link: https://patch.msgid.link/7461f695b4daed80f2fc4b1463ead47f04f9ad05.1739741254.git.mail@maciej.szmigiero.name
Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by

Maciej S. Szmigiero and committed by
Takashi Iwai
aa85822c 3abe3d34

+43 -7
+1
include/sound/hda_codec.h
··· 195 195 /* beep device */ 196 196 struct hda_beep *beep; 197 197 unsigned int beep_mode; 198 + bool beep_just_power_on; 198 199 199 200 /* widget capabilities cache */ 200 201 u32 *wcaps;
+9 -6
sound/pci/hda/hda_beep.c
··· 31 31 beep->power_hook(beep, true); 32 32 beep->playing = 1; 33 33 } 34 - snd_hda_codec_write(codec, beep->nid, 0, 35 - AC_VERB_SET_BEEP_CONTROL, tone); 34 + if (!codec->beep_just_power_on) 35 + snd_hda_codec_write(codec, beep->nid, 0, 36 + AC_VERB_SET_BEEP_CONTROL, tone); 36 37 if (!tone && beep->playing) { 37 38 beep->playing = 0; 38 39 if (beep->power_hook) ··· 213 212 struct hda_beep *beep; 214 213 int err; 215 214 216 - if (!snd_hda_get_bool_hint(codec, "beep")) 217 - return 0; /* disabled explicitly by hints */ 218 - if (codec->beep_mode == HDA_BEEP_MODE_OFF) 219 - return 0; /* disabled by module option */ 215 + if (!codec->beep_just_power_on) { 216 + if (!snd_hda_get_bool_hint(codec, "beep")) 217 + return 0; /* disabled explicitly by hints */ 218 + if (codec->beep_mode == HDA_BEEP_MODE_OFF) 219 + return 0; /* disabled by module option */ 220 + } 220 221 221 222 beep = kzalloc(sizeof(*beep), GFP_KERNEL); 222 223 if (beep == NULL)
+33 -1
sound/pci/hda/patch_realtek.c
··· 28 28 #include <sound/hda_codec.h> 29 29 #include "hda_local.h" 30 30 #include "hda_auto_parser.h" 31 + #include "hda_beep.h" 31 32 #include "hda_jack.h" 32 33 #include "hda_generic.h" 33 34 #include "hda_component.h" ··· 6923 6922 } 6924 6923 } 6925 6924 6925 + static void alc285_fixup_hp_beep(struct hda_codec *codec, 6926 + const struct hda_fixup *fix, int action) 6927 + { 6928 + if (action == HDA_FIXUP_ACT_PRE_PROBE) { 6929 + codec->beep_just_power_on = true; 6930 + } else if (action == HDA_FIXUP_ACT_INIT) { 6931 + #ifdef CONFIG_SND_HDA_INPUT_BEEP 6932 + /* 6933 + * Just enable loopback to internal speaker and headphone jack. 6934 + * Disable amplification to get about the same beep volume as 6935 + * was on pure BIOS setup before loading the driver. 6936 + */ 6937 + alc_update_coef_idx(codec, 0x36, 0x7070, BIT(13)); 6938 + 6939 + snd_hda_enable_beep_device(codec, 1); 6940 + 6941 + #if !IS_ENABLED(CONFIG_INPUT_PCSPKR) 6942 + dev_warn_once(hda_codec_dev(codec), 6943 + "enable CONFIG_INPUT_PCSPKR to get PC beeps\n"); 6944 + #endif 6945 + #endif 6946 + } 6947 + } 6948 + 6926 6949 /* for hda_fixup_thinkpad_acpi() */ 6927 6950 #include "thinkpad_helper.c" 6928 6951 ··· 7731 7706 ALC285_FIXUP_HP_GPIO_LED, 7732 7707 ALC285_FIXUP_HP_MUTE_LED, 7733 7708 ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED, 7709 + ALC285_FIXUP_HP_BEEP_MICMUTE_LED, 7734 7710 ALC236_FIXUP_HP_MUTE_LED_COEFBIT2, 7735 7711 ALC236_FIXUP_HP_GPIO_LED, 7736 7712 ALC236_FIXUP_HP_MUTE_LED, ··· 9328 9302 .type = HDA_FIXUP_FUNC, 9329 9303 .v.func = alc285_fixup_hp_spectre_x360_mute_led, 9330 9304 }, 9305 + [ALC285_FIXUP_HP_BEEP_MICMUTE_LED] = { 9306 + .type = HDA_FIXUP_FUNC, 9307 + .v.func = alc285_fixup_hp_beep, 9308 + .chained = true, 9309 + .chain_id = ALC285_FIXUP_HP_MUTE_LED, 9310 + }, 9331 9311 [ALC236_FIXUP_HP_MUTE_LED_COEFBIT2] = { 9332 9312 .type = HDA_FIXUP_FUNC, 9333 9313 .v.func = alc236_fixup_hp_mute_led_coefbit2, ··· 10423 10391 SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), 10424 10392 SND_PCI_QUIRK(0x103c, 0x8735, "HP ProBook 435 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), 10425 10393 SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT), 10426 - SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED), 10394 + SND_PCI_QUIRK(0x103c, 0x8760, "HP EliteBook 8{4,5}5 G7", ALC285_FIXUP_HP_BEEP_MICMUTE_LED), 10427 10395 SND_PCI_QUIRK(0x103c, 0x876e, "HP ENVY x360 Convertible 13-ay0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS), 10428 10396 SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED), 10429 10397 SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED),