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 |