Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 62a615e0 authored by Andy Shevchenko's avatar Andy Shevchenko Committed by Wolfram Sang
Browse files

mfd: core: redo ACPI matching of the children devices



There is at least one board on the market, i.e. Intel Galileo Gen2, that uses
_ADR to distinguish the devices under one actual device. Due to this we have to
improve the quirk in the MFD core to handle that board.

Acked-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: default avatarLee Jones <lee.jones@linaro.org>
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent 6a62974b
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -347,13 +347,18 @@ For the first case, the MFD drivers do not need to do anything. The
resulting child platform device will have its ACPI_COMPANION() set to point
to the parent device.

If the ACPI namespace has a device that we can match using an ACPI id,
the id should be set like:
If the ACPI namespace has a device that we can match using an ACPI id or ACPI
adr, the cell should be set like:

	static struct mfd_cell_acpi_match my_subdevice_cell_acpi_match = {
		.pnpid = "XYZ0001",
		.adr = 0,
	};

	static struct mfd_cell my_subdevice_cell = {
		.name = "my_subdevice",
		/* set the resources relative to the parent */
		.acpi_pnpid = "XYZ0001",
		.acpi_match = &my_subdevice_cell_acpi_match,
	};

The ACPI id "XYZ0001" is then used to lookup an ACPI device directly under
+36 −16
Original line number Diff line number Diff line
@@ -82,30 +82,50 @@ static int mfd_platform_add_cell(struct platform_device *pdev,
static void mfd_acpi_add_device(const struct mfd_cell *cell,
				struct platform_device *pdev)
{
	struct acpi_device *parent_adev;
	const struct mfd_cell_acpi_match *match = cell->acpi_match;
	struct acpi_device *parent, *child;
	struct acpi_device *adev;

	parent_adev = ACPI_COMPANION(pdev->dev.parent);
	if (!parent_adev)
	parent = ACPI_COMPANION(pdev->dev.parent);
	if (!parent)
		return;

	/*
	 * MFD child device gets its ACPI handle either from the ACPI
	 * device directly under the parent that matches the acpi_pnpid or
	 * it will use the parent handle if is no acpi_pnpid is given.
	 * MFD child device gets its ACPI handle either from the ACPI device
	 * directly under the parent that matches the either _HID or _CID, or
	 * _ADR or it will use the parent handle if is no ID is given.
	 *
	 * Note that use of _ADR is a grey area in the ACPI specification,
	 * though Intel Galileo Gen2 is using it to distinguish the children
	 * devices.
	 */
	adev = parent_adev;
	if (cell->acpi_pnpid) {
	adev = parent;
	if (match) {
		if (match->pnpid) {
			struct acpi_device_id ids[2] = {};
		struct acpi_device *child_adev;

		strlcpy(ids[0].id, cell->acpi_pnpid, sizeof(ids[0].id));
		list_for_each_entry(child_adev, &parent_adev->children, node)
			if (acpi_match_device_ids(child_adev, ids)) {
				adev = child_adev;
			strlcpy(ids[0].id, match->pnpid, sizeof(ids[0].id));
			list_for_each_entry(child, &parent->children, node) {
				if (acpi_match_device_ids(child, ids)) {
					adev = child;
					break;
				}
			}
		} else {
			unsigned long long adr;
			acpi_status status;

			list_for_each_entry(child, &parent->children, node) {
				status = acpi_evaluate_integer(child->handle,
							       "_ADR", NULL,
							       &adr);
				if (ACPI_SUCCESS(status) && match->adr == adr) {
					adev = child;
					break;
				}
			}
		}
	}

	ACPI_COMPANION_SET(&pdev->dev, adev);
}
+8 −2
Original line number Diff line number Diff line
@@ -18,6 +18,12 @@

struct irq_domain;

/* Matches ACPI PNP id, either _HID or _CID, or ACPI _ADR */
struct mfd_cell_acpi_match {
	const char			*pnpid;
	const unsigned long long	adr;
};

/*
 * This struct describes the MFD part ("cell").
 * After registration the copy of this structure will become the platform data
@@ -44,8 +50,8 @@ struct mfd_cell {
	 */
	const char		*of_compatible;

	/* Matches ACPI PNP id, either _HID or _CID */
	const char		*acpi_pnpid;
	/* Matches ACPI */
	const struct mfd_cell_acpi_match	*acpi_match;

	/*
	 * These resources can be specified relative to the parent device.