diff options
Diffstat (limited to 'drivers/of/platform.c')
-rw-r--r-- | drivers/of/platform.c | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 656cccf0e680..cd87a36495be 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c | |||
@@ -550,4 +550,59 @@ void of_platform_depopulate(struct device *parent) | |||
550 | } | 550 | } |
551 | EXPORT_SYMBOL_GPL(of_platform_depopulate); | 551 | EXPORT_SYMBOL_GPL(of_platform_depopulate); |
552 | 552 | ||
553 | #ifdef CONFIG_OF_DYNAMIC | ||
554 | static int of_platform_notify(struct notifier_block *nb, | ||
555 | unsigned long action, void *arg) | ||
556 | { | ||
557 | struct of_reconfig_data *rd = arg; | ||
558 | struct platform_device *pdev_parent, *pdev; | ||
559 | bool children_left; | ||
560 | |||
561 | switch (of_reconfig_get_state_change(action, rd)) { | ||
562 | case OF_RECONFIG_CHANGE_ADD: | ||
563 | /* verify that the parent is a bus */ | ||
564 | if (!of_node_check_flag(rd->dn->parent, OF_POPULATED_BUS)) | ||
565 | return NOTIFY_OK; /* not for us */ | ||
566 | |||
567 | /* pdev_parent may be NULL when no bus platform device */ | ||
568 | pdev_parent = of_find_device_by_node(rd->dn->parent); | ||
569 | pdev = of_platform_device_create(rd->dn, NULL, | ||
570 | pdev_parent ? &pdev_parent->dev : NULL); | ||
571 | of_dev_put(pdev_parent); | ||
572 | |||
573 | if (pdev == NULL) { | ||
574 | pr_err("%s: failed to create for '%s'\n", | ||
575 | __func__, rd->dn->full_name); | ||
576 | /* of_platform_device_create tosses the error code */ | ||
577 | return notifier_from_errno(-EINVAL); | ||
578 | } | ||
579 | break; | ||
580 | |||
581 | case OF_RECONFIG_CHANGE_REMOVE: | ||
582 | /* find our device by node */ | ||
583 | pdev = of_find_device_by_node(rd->dn); | ||
584 | if (pdev == NULL) | ||
585 | return NOTIFY_OK; /* no? not meant for us */ | ||
586 | |||
587 | /* unregister takes one ref away */ | ||
588 | of_platform_device_destroy(&pdev->dev, &children_left); | ||
589 | |||
590 | /* and put the reference of the find */ | ||
591 | of_dev_put(pdev); | ||
592 | break; | ||
593 | } | ||
594 | |||
595 | return NOTIFY_OK; | ||
596 | } | ||
597 | |||
598 | static struct notifier_block platform_of_notifier = { | ||
599 | .notifier_call = of_platform_notify, | ||
600 | }; | ||
601 | |||
602 | void of_platform_register_reconfig_notifier(void) | ||
603 | { | ||
604 | WARN_ON(of_reconfig_notifier_register(&platform_of_notifier)); | ||
605 | } | ||
606 | #endif /* CONFIG_OF_DYNAMIC */ | ||
607 | |||
553 | #endif /* CONFIG_OF_ADDRESS */ | 608 | #endif /* CONFIG_OF_ADDRESS */ |