From: Andy Shevchenko <andriy.shevche...@linux.intel.com>

commit 541019157c6b5951f2a488dbf4f7fa5f4b8f9b98 upstream.

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: Rafael J. Wysocki <rafael.j.wyso...@intel.com>
Acked-by: Lee Jones <lee.jo...@linaro.org>
Signed-off-by: Andy Shevchenko <andriy.shevche...@linux.intel.com>
Signed-off-by: Wolfram Sang <w...@the-dreams.de>
(cherry picked from commit 98a3be44ffa67b812de7aa7aed9f2331edcfb1a5)
---
 Documentation/acpi/enumeration.txt | 11 +++++---
 drivers/mfd/mfd-core.c             | 52 ++++++++++++++++++++++++++------------
 include/linux/mfd/core.h           | 10 ++++++--
 3 files changed, 52 insertions(+), 21 deletions(-)

diff --git a/Documentation/acpi/enumeration.txt 
b/Documentation/acpi/enumeration.txt
index 15dfce7..afd34d0 100644
--- a/Documentation/acpi/enumeration.txt
+++ b/Documentation/acpi/enumeration.txt
@@ -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
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 1aed3b7..ea844dc 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -82,29 +82,49 @@ 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) {
-               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;
-                               break;
+       adev = parent;
+       if (match) {
+               if (match->pnpid) {
+                       struct acpi_device_id ids[2] = {};
+
+                       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);
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
index a76bc10..27dac3f 100644
--- a/include/linux/mfd/core.h
+++ b/include/linux/mfd/core.h
@@ -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.
-- 
2.5.0

-- 
_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to