Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>

authored by

Andy Shevchenko and committed by
Wolfram Sang
62a615e0 6a62974b

+51 -20
+8 -3
Documentation/acpi/enumeration.txt
··· 347 347 resulting child platform device will have its ACPI_COMPANION() set to point 348 348 to the parent device. 349 349 350 - If the ACPI namespace has a device that we can match using an ACPI id, 351 - the id should be set like: 350 + If the ACPI namespace has a device that we can match using an ACPI id or ACPI 351 + adr, the cell should be set like: 352 + 353 + static struct mfd_cell_acpi_match my_subdevice_cell_acpi_match = { 354 + .pnpid = "XYZ0001", 355 + .adr = 0, 356 + }; 352 357 353 358 static struct mfd_cell my_subdevice_cell = { 354 359 .name = "my_subdevice", 355 360 /* set the resources relative to the parent */ 356 - .acpi_pnpid = "XYZ0001", 361 + .acpi_match = &my_subdevice_cell_acpi_match, 357 362 }; 358 363 359 364 The ACPI id "XYZ0001" is then used to lookup an ACPI device directly under
+35 -15
drivers/mfd/mfd-core.c
··· 82 82 static void mfd_acpi_add_device(const struct mfd_cell *cell, 83 83 struct platform_device *pdev) 84 84 { 85 - struct acpi_device *parent_adev; 85 + const struct mfd_cell_acpi_match *match = cell->acpi_match; 86 + struct acpi_device *parent, *child; 86 87 struct acpi_device *adev; 87 88 88 - parent_adev = ACPI_COMPANION(pdev->dev.parent); 89 - if (!parent_adev) 89 + parent = ACPI_COMPANION(pdev->dev.parent); 90 + if (!parent) 90 91 return; 91 92 92 93 /* 93 - * MFD child device gets its ACPI handle either from the ACPI 94 - * device directly under the parent that matches the acpi_pnpid or 95 - * it will use the parent handle if is no acpi_pnpid is given. 94 + * MFD child device gets its ACPI handle either from the ACPI device 95 + * directly under the parent that matches the either _HID or _CID, or 96 + * _ADR or it will use the parent handle if is no ID is given. 97 + * 98 + * Note that use of _ADR is a grey area in the ACPI specification, 99 + * though Intel Galileo Gen2 is using it to distinguish the children 100 + * devices. 96 101 */ 97 - adev = parent_adev; 98 - if (cell->acpi_pnpid) { 99 - struct acpi_device_id ids[2] = {}; 100 - struct acpi_device *child_adev; 102 + adev = parent; 103 + if (match) { 104 + if (match->pnpid) { 105 + struct acpi_device_id ids[2] = {}; 101 106 102 - strlcpy(ids[0].id, cell->acpi_pnpid, sizeof(ids[0].id)); 103 - list_for_each_entry(child_adev, &parent_adev->children, node) 104 - if (acpi_match_device_ids(child_adev, ids)) { 105 - adev = child_adev; 106 - break; 107 + strlcpy(ids[0].id, match->pnpid, sizeof(ids[0].id)); 108 + list_for_each_entry(child, &parent->children, node) { 109 + if (acpi_match_device_ids(child, ids)) { 110 + adev = child; 111 + break; 112 + } 107 113 } 114 + } else { 115 + unsigned long long adr; 116 + acpi_status status; 117 + 118 + list_for_each_entry(child, &parent->children, node) { 119 + status = acpi_evaluate_integer(child->handle, 120 + "_ADR", NULL, 121 + &adr); 122 + if (ACPI_SUCCESS(status) && match->adr == adr) { 123 + adev = child; 124 + break; 125 + } 126 + } 127 + } 108 128 } 109 129 110 130 ACPI_COMPANION_SET(&pdev->dev, adev);
+8 -2
include/linux/mfd/core.h
··· 18 18 19 19 struct irq_domain; 20 20 21 + /* Matches ACPI PNP id, either _HID or _CID, or ACPI _ADR */ 22 + struct mfd_cell_acpi_match { 23 + const char *pnpid; 24 + const unsigned long long adr; 25 + }; 26 + 21 27 /* 22 28 * This struct describes the MFD part ("cell"). 23 29 * After registration the copy of this structure will become the platform data ··· 50 44 */ 51 45 const char *of_compatible; 52 46 53 - /* Matches ACPI PNP id, either _HID or _CID */ 54 - const char *acpi_pnpid; 47 + /* Matches ACPI */ 48 + const struct mfd_cell_acpi_match *acpi_match; 55 49 56 50 /* 57 51 * These resources can be specified relative to the parent device.