Commit 98a3be44 authored by Andy Shevchenko's avatar Andy Shevchenko Committed by Wolfram Sang

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 049e6dde
...@@ -347,13 +347,18 @@ For the first case, the MFD drivers do not need to do anything. The ...@@ -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 resulting child platform device will have its ACPI_COMPANION() set to point
to the parent device. to the parent device.
If the ACPI namespace has a device that we can match using an ACPI id, If the ACPI namespace has a device that we can match using an ACPI id or ACPI
the id should be set like: 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 = { static struct mfd_cell my_subdevice_cell = {
.name = "my_subdevice", .name = "my_subdevice",
/* set the resources relative to the parent */ /* 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 The ACPI id "XYZ0001" is then used to lookup an ACPI device directly under
......
...@@ -82,30 +82,50 @@ static int mfd_platform_add_cell(struct platform_device *pdev, ...@@ -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, static void mfd_acpi_add_device(const struct mfd_cell *cell,
struct platform_device *pdev) 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; struct acpi_device *adev;
parent_adev = ACPI_COMPANION(pdev->dev.parent); parent = ACPI_COMPANION(pdev->dev.parent);
if (!parent_adev) if (!parent)
return; return;
/* /*
* MFD child device gets its ACPI handle either from the ACPI * MFD child device gets its ACPI handle either from the ACPI device
* device directly under the parent that matches the acpi_pnpid or * directly under the parent that matches the either _HID or _CID, or
* it will use the parent handle if is no acpi_pnpid is given. * _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; adev = parent;
if (cell->acpi_pnpid) { if (match) {
if (match->pnpid) {
struct acpi_device_id ids[2] = {}; struct acpi_device_id ids[2] = {};
struct acpi_device *child_adev;
strlcpy(ids[0].id, cell->acpi_pnpid, sizeof(ids[0].id)); strlcpy(ids[0].id, match->pnpid, sizeof(ids[0].id));
list_for_each_entry(child_adev, &parent_adev->children, node) list_for_each_entry(child, &parent->children, node) {
if (acpi_match_device_ids(child_adev, ids)) { if (acpi_match_device_ids(child, ids)) {
adev = child_adev; adev = child;
break; 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); ACPI_COMPANION_SET(&pdev->dev, adev);
} }
......
...@@ -18,6 +18,12 @@ ...@@ -18,6 +18,12 @@
struct irq_domain; 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"). * This struct describes the MFD part ("cell").
* After registration the copy of this structure will become the platform data * After registration the copy of this structure will become the platform data
...@@ -44,8 +50,8 @@ struct mfd_cell { ...@@ -44,8 +50,8 @@ struct mfd_cell {
*/ */
const char *of_compatible; const char *of_compatible;
/* Matches ACPI PNP id, either _HID or _CID */ /* Matches ACPI */
const char *acpi_pnpid; const struct mfd_cell_acpi_match *acpi_match;
/* /*
* These resources can be specified relative to the parent device. * These resources can be specified relative to the parent device.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment