diff options
| -rw-r--r-- | Documentation/acpi/enumeration.txt | 27 | ||||
| -rw-r--r-- | drivers/mfd/mfd-core.c | 40 | ||||
| -rw-r--r-- | include/linux/mfd/core.h | 3 |
3 files changed, 70 insertions, 0 deletions
diff --git a/Documentation/acpi/enumeration.txt b/Documentation/acpi/enumeration.txt index e182be5e3c83..b60d2ab69497 100644 --- a/Documentation/acpi/enumeration.txt +++ b/Documentation/acpi/enumeration.txt | |||
| @@ -312,3 +312,30 @@ a code like this: | |||
| 312 | 312 | ||
| 313 | There are also devm_* versions of these functions which release the | 313 | There are also devm_* versions of these functions which release the |
| 314 | descriptors once the device is released. | 314 | descriptors once the device is released. |
| 315 | |||
| 316 | MFD devices | ||
| 317 | ~~~~~~~~~~~ | ||
| 318 | The MFD devices register their children as platform devices. For the child | ||
| 319 | devices there needs to be an ACPI handle that they can use to reference | ||
| 320 | parts of the ACPI namespace that relate to them. In the Linux MFD subsystem | ||
| 321 | we provide two ways: | ||
| 322 | |||
| 323 | o The children share the parent ACPI handle. | ||
| 324 | o The MFD cell can specify the ACPI id of the device. | ||
| 325 | |||
| 326 | For the first case, the MFD drivers do not need to do anything. The | ||
| 327 | resulting child platform device will have its ACPI_COMPANION() set to point | ||
| 328 | to the parent device. | ||
| 329 | |||
| 330 | If the ACPI namespace has a device that we can match using an ACPI id, | ||
| 331 | the id should be set like: | ||
| 332 | |||
| 333 | static struct mfd_cell my_subdevice_cell = { | ||
| 334 | .name = "my_subdevice", | ||
| 335 | /* set the resources relative to the parent */ | ||
| 336 | .acpi_pnpid = "XYZ0001", | ||
| 337 | }; | ||
| 338 | |||
| 339 | The ACPI id "XYZ0001" is then used to lookup an ACPI device directly under | ||
| 340 | the MFD device and if found, that ACPI companion device is bound to the | ||
| 341 | resulting child platform device. | ||
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 5d0fbe1e097a..f3338fe9d069 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c | |||
| @@ -78,6 +78,44 @@ static int mfd_platform_add_cell(struct platform_device *pdev, | |||
| 78 | return 0; | 78 | return 0; |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | #if IS_ENABLED(CONFIG_ACPI) | ||
| 82 | static void mfd_acpi_add_device(const struct mfd_cell *cell, | ||
| 83 | struct platform_device *pdev) | ||
| 84 | { | ||
| 85 | struct acpi_device *parent_adev; | ||
| 86 | struct acpi_device *adev; | ||
| 87 | |||
| 88 | parent_adev = ACPI_COMPANION(pdev->dev.parent); | ||
| 89 | if (!parent_adev) | ||
| 90 | return; | ||
| 91 | |||
| 92 | /* | ||
| 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. | ||
| 96 | */ | ||
| 97 | adev = parent_adev; | ||
| 98 | if (cell->acpi_pnpid) { | ||
| 99 | struct acpi_device_id ids[2] = {}; | ||
| 100 | struct acpi_device *child_adev; | ||
| 101 | |||
| 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 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | ACPI_COMPANION_SET(&pdev->dev, adev); | ||
| 111 | } | ||
| 112 | #else | ||
| 113 | static inline void mfd_acpi_add_device(const struct mfd_cell *cell, | ||
| 114 | struct platform_device *pdev) | ||
| 115 | { | ||
| 116 | } | ||
| 117 | #endif | ||
| 118 | |||
| 81 | static int mfd_add_device(struct device *parent, int id, | 119 | static int mfd_add_device(struct device *parent, int id, |
| 82 | const struct mfd_cell *cell, atomic_t *usage_count, | 120 | const struct mfd_cell *cell, atomic_t *usage_count, |
| 83 | struct resource *mem_base, | 121 | struct resource *mem_base, |
| @@ -119,6 +157,8 @@ static int mfd_add_device(struct device *parent, int id, | |||
| 119 | } | 157 | } |
| 120 | } | 158 | } |
| 121 | 159 | ||
| 160 | mfd_acpi_add_device(cell, pdev); | ||
| 161 | |||
| 122 | if (cell->pdata_size) { | 162 | if (cell->pdata_size) { |
| 123 | ret = platform_device_add_data(pdev, | 163 | ret = platform_device_add_data(pdev, |
| 124 | cell->platform_data, cell->pdata_size); | 164 | cell->platform_data, cell->pdata_size); |
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index f543de91ce19..73e1709d4c09 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h | |||
| @@ -44,6 +44,9 @@ struct mfd_cell { | |||
| 44 | */ | 44 | */ |
| 45 | const char *of_compatible; | 45 | const char *of_compatible; |
| 46 | 46 | ||
| 47 | /* Matches ACPI PNP id, either _HID or _CID */ | ||
| 48 | const char *acpi_pnpid; | ||
| 49 | |||
| 47 | /* | 50 | /* |
| 48 | * These resources can be specified relative to the parent device. | 51 | * These resources can be specified relative to the parent device. |
| 49 | * For accessing hardware you should use resources from the platform dev | 52 | * For accessing hardware you should use resources from the platform dev |
