diff options
author | Stefan Binding <sbinding@opensource.cirrus.com> | 2023-09-21 19:28:47 +0300 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2023-09-22 11:47:48 +0300 |
commit | 7ce669334c55c50ecc2909c42275a3eec0039799 (patch) | |
tree | 7ad73960fe6bad6e617d4ada93909b5dce8b2305 /sound/pci/hda | |
parent | 502629a75566b5cb409c118125d38102e5edc8f6 (diff) | |
download | linux-7ce669334c55c50ecc2909c42275a3eec0039799.tar.xz |
ALSA: hda/realtek: Support ACPI Notification framework via component binding
For systems which have support for ACPI notifications, add a mechanism to
register a handler for ACPI notifications and then call the acpi_notify
api on the bound components.
Registering a handler in the Realtek HDA driver, allows a single handler to
be registered, which then calls into all the components, rather than
attempting to register the same handler multiple times, once for each
component.
Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20230921162849.1988124-3-sbinding@opensource.cirrus.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 83 |
1 files changed, 82 insertions, 1 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 883a7e865bc5..1e2b6a299dbc 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10,6 +10,7 @@ * Jonathan Woithe <jwoithe@just42.net> */ +#include <linux/acpi.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/slab.h> @@ -6704,12 +6705,91 @@ static void alc287_fixup_legion_15imhg05_speakers(struct hda_codec *codec, } } +#ifdef CONFIG_ACPI +static void comp_acpi_device_notify(acpi_handle handle, u32 event, void *data) +{ + struct hda_codec *cdc = data; + struct alc_spec *spec = cdc->spec; + int i; + + codec_info(cdc, "ACPI Notification %d\n", event); + + for (i = 0; i < HDA_MAX_COMPONENTS; i++) { + if (spec->comps[i].dev && spec->comps[i].acpi_notify) + spec->comps[i].acpi_notify(acpi_device_handle(spec->comps[i].adev), event, + spec->comps[i].dev); + } +} + +static int comp_bind_acpi(struct device *dev) +{ + struct hda_codec *cdc = dev_to_hda_codec(dev); + struct alc_spec *spec = cdc->spec; + bool support_notifications = false; + struct acpi_device *adev; + int ret; + int i; + + adev = spec->comps[0].adev; + if (!acpi_device_handle(adev)) + return 0; + + for (i = 0; i < HDA_MAX_COMPONENTS; i++) + support_notifications = support_notifications || + spec->comps[i].acpi_notifications_supported; + + if (support_notifications) { + ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, + comp_acpi_device_notify, cdc); + if (ret < 0) { + codec_warn(cdc, "Failed to install notify handler: %d\n", ret); + return 0; + } + + codec_dbg(cdc, "Notify handler installed\n"); + } + + return 0; +} + +static void comp_unbind_acpi(struct device *dev) +{ + struct hda_codec *cdc = dev_to_hda_codec(dev); + struct alc_spec *spec = cdc->spec; + struct acpi_device *adev; + int ret; + + adev = spec->comps[0].adev; + if (!acpi_device_handle(adev)) + return; + + ret = acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, + comp_acpi_device_notify); + if (ret < 0) + codec_warn(cdc, "Failed to uninstall notify handler: %d\n", ret); +} +#else +static int comp_bind_acpi(struct device *dev) +{ + return 0; +} + +static void comp_unbind_acpi(struct device *dev) +{ +} +#endif + static int comp_bind(struct device *dev) { struct hda_codec *cdc = dev_to_hda_codec(dev); struct alc_spec *spec = cdc->spec; + int ret; + + ret = component_bind_all(dev, spec->comps); + if (ret) + return ret; - return component_bind_all(dev, spec->comps); + return comp_bind_acpi(dev); } static void comp_unbind(struct device *dev) @@ -6717,6 +6797,7 @@ static void comp_unbind(struct device *dev) struct hda_codec *cdc = dev_to_hda_codec(dev); struct alc_spec *spec = cdc->spec; + comp_unbind_acpi(dev); component_unbind_all(dev, spec->comps); } |