hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/mfd/mfd-core.c
....@@ -1,19 +1,16 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * drivers/mfd/mfd-core.c
34 *
45 * core MFD support
56 * Copyright (c) 2006 Ian Molton
67 * Copyright (c) 2007,2008 Dmitry Baryshkov
7
- *
8
- * This program is free software; you can redistribute it and/or modify
9
- * it under the terms of the GNU General Public License version 2 as
10
- * published by the Free Software Foundation.
11
- *
128 */
139
1410 #include <linux/kernel.h>
1511 #include <linux/platform_device.h>
1612 #include <linux/acpi.h>
13
+#include <linux/list.h>
1714 #include <linux/property.h>
1815 #include <linux/mfd/core.h>
1916 #include <linux/pm_runtime.h>
....@@ -21,7 +18,16 @@
2118 #include <linux/module.h>
2219 #include <linux/irqdomain.h>
2320 #include <linux/of.h>
21
+#include <linux/of_address.h>
2422 #include <linux/regulator/consumer.h>
23
+
24
+static LIST_HEAD(mfd_of_node_list);
25
+
26
+struct mfd_of_node_entry {
27
+ struct list_head list;
28
+ struct device *dev;
29
+ struct device_node *np;
30
+};
2531
2632 static struct device_type mfd_dev_type = {
2733 .name = "mfd_device",
....@@ -30,64 +36,28 @@
3036 int mfd_cell_enable(struct platform_device *pdev)
3137 {
3238 const struct mfd_cell *cell = mfd_get_cell(pdev);
33
- int err = 0;
3439
3540 if (!cell->enable) {
3641 dev_dbg(&pdev->dev, "No .enable() call-back registered\n");
3742 return 0;
3843 }
3944
40
- /* only call enable hook if the cell wasn't previously enabled */
41
- if (atomic_inc_return(cell->usage_count) == 1)
42
- err = cell->enable(pdev);
43
-
44
- /* if the enable hook failed, decrement counter to allow retries */
45
- if (err)
46
- atomic_dec(cell->usage_count);
47
-
48
- return err;
45
+ return cell->enable(pdev);
4946 }
5047 EXPORT_SYMBOL(mfd_cell_enable);
5148
5249 int mfd_cell_disable(struct platform_device *pdev)
5350 {
5451 const struct mfd_cell *cell = mfd_get_cell(pdev);
55
- int err = 0;
5652
5753 if (!cell->disable) {
5854 dev_dbg(&pdev->dev, "No .disable() call-back registered\n");
5955 return 0;
6056 }
6157
62
- /* only disable if no other clients are using it */
63
- if (atomic_dec_return(cell->usage_count) == 0)
64
- err = cell->disable(pdev);
65
-
66
- /* if the disable hook failed, increment to allow retries */
67
- if (err)
68
- atomic_inc(cell->usage_count);
69
-
70
- /* sanity check; did someone call disable too many times? */
71
- WARN_ON(atomic_read(cell->usage_count) < 0);
72
-
73
- return err;
58
+ return cell->disable(pdev);
7459 }
7560 EXPORT_SYMBOL(mfd_cell_disable);
76
-
77
-static int mfd_platform_add_cell(struct platform_device *pdev,
78
- const struct mfd_cell *cell,
79
- atomic_t *usage_count)
80
-{
81
- if (!cell)
82
- return 0;
83
-
84
- pdev->mfd_cell = kmemdup(cell, sizeof(*cell), GFP_KERNEL);
85
- if (!pdev->mfd_cell)
86
- return -ENOMEM;
87
-
88
- pdev->mfd_cell->usage_count = usage_count;
89
- return 0;
90
-}
9161
9262 #if IS_ENABLED(CONFIG_ACPI)
9363 static void mfd_acpi_add_device(const struct mfd_cell *cell,
....@@ -147,14 +117,60 @@
147117 }
148118 #endif
149119
120
+static int mfd_match_of_node_to_dev(struct platform_device *pdev,
121
+ struct device_node *np,
122
+ const struct mfd_cell *cell)
123
+{
124
+#if IS_ENABLED(CONFIG_OF)
125
+ struct mfd_of_node_entry *of_entry;
126
+ const __be32 *reg;
127
+ u64 of_node_addr;
128
+
129
+ /* Skip if OF node has previously been allocated to a device */
130
+ list_for_each_entry(of_entry, &mfd_of_node_list, list)
131
+ if (of_entry->np == np)
132
+ return -EAGAIN;
133
+
134
+ if (!cell->use_of_reg)
135
+ /* No of_reg defined - allocate first free compatible match */
136
+ goto allocate_of_node;
137
+
138
+ /* We only care about each node's first defined address */
139
+ reg = of_get_address(np, 0, NULL, NULL);
140
+ if (!reg)
141
+ /* OF node does not contatin a 'reg' property to match to */
142
+ return -EAGAIN;
143
+
144
+ of_node_addr = of_read_number(reg, of_n_addr_cells(np));
145
+
146
+ if (cell->of_reg != of_node_addr)
147
+ /* No match */
148
+ return -EAGAIN;
149
+
150
+allocate_of_node:
151
+ of_entry = kzalloc(sizeof(*of_entry), GFP_KERNEL);
152
+ if (!of_entry)
153
+ return -ENOMEM;
154
+
155
+ of_entry->dev = &pdev->dev;
156
+ of_entry->np = np;
157
+ list_add_tail(&of_entry->list, &mfd_of_node_list);
158
+
159
+ pdev->dev.of_node = np;
160
+ pdev->dev.fwnode = &np->fwnode;
161
+#endif
162
+ return 0;
163
+}
164
+
150165 static int mfd_add_device(struct device *parent, int id,
151
- const struct mfd_cell *cell, atomic_t *usage_count,
166
+ const struct mfd_cell *cell,
152167 struct resource *mem_base,
153168 int irq_base, struct irq_domain *domain)
154169 {
155170 struct resource *res;
156171 struct platform_device *pdev;
157172 struct device_node *np = NULL;
173
+ struct mfd_of_node_entry *of_entry, *tmp;
158174 int ret = -ENOMEM;
159175 int platform_id;
160176 int r;
....@@ -167,6 +183,10 @@
167183 pdev = platform_device_alloc(cell->name, platform_id);
168184 if (!pdev)
169185 goto fail_alloc;
186
+
187
+ pdev->mfd_cell = kmemdup(cell, sizeof(*cell), GFP_KERNEL);
188
+ if (!pdev->mfd_cell)
189
+ goto fail_device;
170190
171191 res = kcalloc(cell->num_resources, sizeof(*res), GFP_KERNEL);
172192 if (!res)
....@@ -185,14 +205,30 @@
185205 if (ret < 0)
186206 goto fail_res;
187207
188
- if (parent->of_node && cell->of_compatible) {
208
+ if (IS_ENABLED(CONFIG_OF) && parent->of_node && cell->of_compatible) {
189209 for_each_child_of_node(parent->of_node, np) {
190210 if (of_device_is_compatible(np, cell->of_compatible)) {
191
- pdev->dev.of_node = np;
192
- pdev->dev.fwnode = &np->fwnode;
211
+ /* Ignore 'disabled' devices error free */
212
+ if (!of_device_is_available(np)) {
213
+ of_node_put(np);
214
+ ret = 0;
215
+ goto fail_alias;
216
+ }
217
+
218
+ ret = mfd_match_of_node_to_dev(pdev, np, cell);
219
+ if (ret == -EAGAIN)
220
+ continue;
221
+ of_node_put(np);
222
+ if (ret)
223
+ goto fail_alias;
224
+
193225 break;
194226 }
195227 }
228
+
229
+ if (!pdev->dev.of_node)
230
+ pr_warn("%s: Failed to locate of_node [id: %d]\n",
231
+ cell->name, platform_id);
196232 }
197233
198234 mfd_acpi_add_device(cell, pdev);
....@@ -201,18 +237,14 @@
201237 ret = platform_device_add_data(pdev,
202238 cell->platform_data, cell->pdata_size);
203239 if (ret)
204
- goto fail_alias;
240
+ goto fail_of_entry;
205241 }
206242
207243 if (cell->properties) {
208244 ret = platform_device_add_properties(pdev, cell->properties);
209245 if (ret)
210
- goto fail_alias;
246
+ goto fail_of_entry;
211247 }
212
-
213
- ret = mfd_platform_add_cell(pdev, cell, usage_count);
214
- if (ret)
215
- goto fail_alias;
216248
217249 for (r = 0; r < cell->num_resources; r++) {
218250 res[r].name = cell->resources[r].name;
....@@ -248,18 +280,18 @@
248280 if (has_acpi_companion(&pdev->dev)) {
249281 ret = acpi_check_resource_conflict(&res[r]);
250282 if (ret)
251
- goto fail_alias;
283
+ goto fail_of_entry;
252284 }
253285 }
254286 }
255287
256288 ret = platform_device_add_resources(pdev, res, cell->num_resources);
257289 if (ret)
258
- goto fail_alias;
290
+ goto fail_of_entry;
259291
260292 ret = platform_device_add(pdev);
261293 if (ret)
262
- goto fail_alias;
294
+ goto fail_of_entry;
263295
264296 if (cell->pm_runtime_no_callbacks)
265297 pm_runtime_no_callbacks(&pdev->dev);
....@@ -268,6 +300,12 @@
268300
269301 return 0;
270302
303
+fail_of_entry:
304
+ list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
305
+ if (of_entry->dev == &pdev->dev) {
306
+ list_del(&of_entry->list);
307
+ kfree(of_entry);
308
+ }
271309 fail_alias:
272310 regulator_bulk_unregister_supply_alias(&pdev->dev,
273311 cell->parent_supplies,
....@@ -280,6 +318,19 @@
280318 return ret;
281319 }
282320
321
+/**
322
+ * mfd_add_devices - register child devices
323
+ *
324
+ * @parent: Pointer to parent device.
325
+ * @id: Can be PLATFORM_DEVID_AUTO to let the Platform API take care
326
+ * of device numbering, or will be added to a device's cell_id.
327
+ * @cells: Array of (struct mfd_cell)s describing child devices.
328
+ * @n_devs: Number of child devices to register.
329
+ * @mem_base: Parent register range resource for child devices.
330
+ * @irq_base: Base of the range of virtual interrupt numbers allocated for
331
+ * this MFD device. Unused if @domain is specified.
332
+ * @domain: Interrupt domain to create mappings for hardware interrupts.
333
+ */
283334 int mfd_add_devices(struct device *parent, int id,
284335 const struct mfd_cell *cells, int n_devs,
285336 struct resource *mem_base,
....@@ -287,16 +338,9 @@
287338 {
288339 int i;
289340 int ret;
290
- atomic_t *cnts;
291
-
292
- /* initialize reference counting for all cells */
293
- cnts = kcalloc(n_devs, sizeof(*cnts), GFP_KERNEL);
294
- if (!cnts)
295
- return -ENOMEM;
296341
297342 for (i = 0; i < n_devs; i++) {
298
- atomic_set(&cnts[i], 0);
299
- ret = mfd_add_device(parent, id, cells + i, cnts + i, mem_base,
343
+ ret = mfd_add_device(parent, id, cells + i, mem_base,
300344 irq_base, domain);
301345 if (ret)
302346 goto fail;
....@@ -307,17 +351,16 @@
307351 fail:
308352 if (i)
309353 mfd_remove_devices(parent);
310
- else
311
- kfree(cnts);
354
+
312355 return ret;
313356 }
314357 EXPORT_SYMBOL(mfd_add_devices);
315358
316
-static int mfd_remove_devices_fn(struct device *dev, void *c)
359
+static int mfd_remove_devices_fn(struct device *dev, void *data)
317360 {
318361 struct platform_device *pdev;
319362 const struct mfd_cell *cell;
320
- atomic_t **usage_count = c;
363
+ int *level = data;
321364
322365 if (dev->type != &mfd_dev_type)
323366 return 0;
....@@ -325,23 +368,29 @@
325368 pdev = to_platform_device(dev);
326369 cell = mfd_get_cell(pdev);
327370
371
+ if (level && cell->level > *level)
372
+ return 0;
373
+
328374 regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
329375 cell->num_parent_supplies);
330
-
331
- /* find the base address of usage_count pointers (for freeing) */
332
- if (!*usage_count || (cell->usage_count < *usage_count))
333
- *usage_count = cell->usage_count;
334376
335377 platform_device_unregister(pdev);
336378 return 0;
337379 }
338380
381
+void mfd_remove_devices_late(struct device *parent)
382
+{
383
+ int level = MFD_DEP_LEVEL_HIGH;
384
+
385
+ device_for_each_child_reverse(parent, &level, mfd_remove_devices_fn);
386
+}
387
+EXPORT_SYMBOL(mfd_remove_devices_late);
388
+
339389 void mfd_remove_devices(struct device *parent)
340390 {
341
- atomic_t *cnts = NULL;
391
+ int level = MFD_DEP_LEVEL_NORMAL;
342392
343
- device_for_each_child_reverse(parent, &cnts, mfd_remove_devices_fn);
344
- kfree(cnts);
393
+ device_for_each_child_reverse(parent, &level, mfd_remove_devices_fn);
345394 }
346395 EXPORT_SYMBOL(mfd_remove_devices);
347396
....@@ -356,6 +405,16 @@
356405 * Returns 0 on success or an appropriate negative error number on failure.
357406 * All child-devices of the MFD will automatically be removed when it gets
358407 * unbinded.
408
+ *
409
+ * @dev: Pointer to parent device.
410
+ * @id: Can be PLATFORM_DEVID_AUTO to let the Platform API take care
411
+ * of device numbering, or will be added to a device's cell_id.
412
+ * @cells: Array of (struct mfd_cell)s describing child devices.
413
+ * @n_devs: Number of child devices to register.
414
+ * @mem_base: Parent register range resource for child devices.
415
+ * @irq_base: Base of the range of virtual interrupt numbers allocated for
416
+ * this MFD device. Unused if @domain is specified.
417
+ * @domain: Interrupt domain to create mappings for hardware interrupts.
359418 */
360419 int devm_mfd_add_devices(struct device *dev, int id,
361420 const struct mfd_cell *cells, int n_devs,
....@@ -382,39 +441,6 @@
382441 return ret;
383442 }
384443 EXPORT_SYMBOL(devm_mfd_add_devices);
385
-
386
-int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones)
387
-{
388
- struct mfd_cell cell_entry;
389
- struct device *dev;
390
- struct platform_device *pdev;
391
- int i;
392
-
393
- /* fetch the parent cell's device (should already be registered!) */
394
- dev = bus_find_device_by_name(&platform_bus_type, NULL, cell);
395
- if (!dev) {
396
- printk(KERN_ERR "failed to find device for cell %s\n", cell);
397
- return -ENODEV;
398
- }
399
- pdev = to_platform_device(dev);
400
- memcpy(&cell_entry, mfd_get_cell(pdev), sizeof(cell_entry));
401
-
402
- WARN_ON(!cell_entry.enable);
403
-
404
- for (i = 0; i < n_clones; i++) {
405
- cell_entry.name = clones[i];
406
- /* don't give up if a single call fails; just report error */
407
- if (mfd_add_device(pdev->dev.parent, -1, &cell_entry,
408
- cell_entry.usage_count, NULL, 0, NULL))
409
- dev_err(dev, "failed to create platform device '%s'\n",
410
- clones[i]);
411
- }
412
-
413
- put_device(dev);
414
-
415
- return 0;
416
-}
417
-EXPORT_SYMBOL(mfd_clone_cell);
418444
419445 MODULE_LICENSE("GPL");
420446 MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov");