aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/of/platform.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of/platform.c')
-rw-r--r--drivers/of/platform.c74
1 files changed, 69 insertions, 5 deletions
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index bd47fbc53dc9..e8376d646d98 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -206,12 +206,13 @@ static struct platform_device *of_platform_device_create_pdata(
206{ 206{
207 struct platform_device *dev; 207 struct platform_device *dev;
208 208
209 if (!of_device_is_available(np)) 209 if (!of_device_is_available(np) ||
210 of_node_test_and_set_flag(np, OF_POPULATED))
210 return NULL; 211 return NULL;
211 212
212 dev = of_device_alloc(np, bus_id, parent); 213 dev = of_device_alloc(np, bus_id, parent);
213 if (!dev) 214 if (!dev)
214 return NULL; 215 goto err_clear_flag;
215 216
216#if defined(CONFIG_MICROBLAZE) 217#if defined(CONFIG_MICROBLAZE)
217 dev->archdata.dma_mask = 0xffffffffUL; 218 dev->archdata.dma_mask = 0xffffffffUL;
@@ -229,10 +230,14 @@ static struct platform_device *of_platform_device_create_pdata(
229 230
230 if (of_device_add(dev) != 0) { 231 if (of_device_add(dev) != 0) {
231 platform_device_put(dev); 232 platform_device_put(dev);
232 return NULL; 233 goto err_clear_flag;
233 } 234 }
234 235
235 return dev; 236 return dev;
237
238err_clear_flag:
239 of_node_clear_flag(np, OF_POPULATED);
240 return NULL;
236} 241}
237 242
238/** 243/**
@@ -264,14 +269,15 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
264 269
265 pr_debug("Creating amba device %s\n", node->full_name); 270 pr_debug("Creating amba device %s\n", node->full_name);
266 271
267 if (!of_device_is_available(node)) 272 if (!of_device_is_available(node) ||
273 of_node_test_and_set_flag(node, OF_POPULATED))
268 return NULL; 274 return NULL;
269 275
270 dev = amba_device_alloc(NULL, 0, 0); 276 dev = amba_device_alloc(NULL, 0, 0);
271 if (!dev) { 277 if (!dev) {
272 pr_err("%s(): amba_device_alloc() failed for %s\n", 278 pr_err("%s(): amba_device_alloc() failed for %s\n",
273 __func__, node->full_name); 279 __func__, node->full_name);
274 return NULL; 280 goto err_clear_flag;
275 } 281 }
276 282
277 /* setup generic device info */ 283 /* setup generic device info */
@@ -311,6 +317,8 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
311 317
312err_free: 318err_free:
313 amba_device_put(dev); 319 amba_device_put(dev);
320err_clear_flag:
321 of_node_clear_flag(node, OF_POPULATED);
314 return NULL; 322 return NULL;
315} 323}
316#else /* CONFIG_ARM_AMBA */ 324#else /* CONFIG_ARM_AMBA */
@@ -487,4 +495,60 @@ int of_platform_populate(struct device_node *root,
487 return rc; 495 return rc;
488} 496}
489EXPORT_SYMBOL_GPL(of_platform_populate); 497EXPORT_SYMBOL_GPL(of_platform_populate);
498
499static int of_platform_device_destroy(struct device *dev, void *data)
500{
501 bool *children_left = data;
502
503 /* Do not touch devices not populated from the device tree */
504 if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED)) {
505 *children_left = true;
506 return 0;
507 }
508
509 /* Recurse, but don't touch this device if it has any children left */
510 if (of_platform_depopulate(dev) != 0) {
511 *children_left = true;
512 return 0;
513 }
514
515 if (dev->bus == &platform_bus_type)
516 platform_device_unregister(to_platform_device(dev));
517#ifdef CONFIG_ARM_AMBA
518 else if (dev->bus == &amba_bustype)
519 amba_device_unregister(to_amba_device(dev));
520#endif
521 else {
522 *children_left = true;
523 return 0;
524 }
525
526 of_node_clear_flag(dev->of_node, OF_POPULATED);
527
528 return 0;
529}
530
531/**
532 * of_platform_depopulate() - Remove devices populated from device tree
533 * @parent: device which childred will be removed
534 *
535 * Complementary to of_platform_populate(), this function removes children
536 * of the given device (and, recurrently, their children) that have been
537 * created from their respective device tree nodes (and only those,
538 * leaving others - eg. manually created - unharmed).
539 *
540 * Returns 0 when all children devices have been removed or
541 * -EBUSY when some children remained.
542 */
543int of_platform_depopulate(struct device *parent)
544{
545 bool children_left = false;
546
547 device_for_each_child(parent, &children_left,
548 of_platform_device_destroy);
549
550 return children_left ? -EBUSY : 0;
551}
552EXPORT_SYMBOL_GPL(of_platform_depopulate);
553
490#endif /* CONFIG_OF_ADDRESS */ 554#endif /* CONFIG_OF_ADDRESS */