Commit 7ce66933 authored by Stefan Binding's avatar Stefan Binding Committed by Takashi Iwai
Browse files

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: default avatarStefan Binding <sbinding@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20230921162849.1988124-3-sbinding@opensource.cirrus.com


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 502629a7
Loading
Loading
Loading
Loading
+82 −1
Original line number Diff line number Diff line
@@ -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);
}