Merge ath-current from ath.git
[firefly-linux-kernel-4.4.55.git] / drivers / mfd / mfd-core.c
index c17635d3e5048418f9758eb37290b4cda282e1e4..60b60dc63dddbc610d0ac1cf02111066b4af5095 100644 (file)
@@ -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);