aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPantelis Antoniou <pantelis.antoniou@konsulko.com>2014-10-28 16:36:01 -0400
committerGrant Likely <grant.likely@linaro.org>2014-11-24 17:25:06 -0500
commit801d728c10db4b28e01590b46bf1f0df930760cc (patch)
tree152e49c3417aa84cb204faefb50f0e0c23eb1867
parentf5242e5a883bf1c1aba6bfd87b85e7dda0e62191 (diff)
of/reconfig: Add OF_DYNAMIC notifier for platform_bus_type
Add OF notifier handler needed for creating/destroying platform devices according to dynamic runtime changes in the DT live tree. Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com> Signed-off-by: Grant Likely <grant.likely@linaro.org>
-rw-r--r--drivers/base/platform.c1
-rw-r--r--drivers/of/platform.c55
-rw-r--r--include/linux/of_platform.h6
3 files changed, 62 insertions, 0 deletions
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index b2afc29403f9..233ececd15a3 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -1006,6 +1006,7 @@ int __init platform_bus_init(void)
1006 error = bus_register(&platform_bus_type); 1006 error = bus_register(&platform_bus_type);
1007 if (error) 1007 if (error)
1008 device_unregister(&platform_bus); 1008 device_unregister(&platform_bus);
1009 of_platform_register_reconfig_notifier();
1009 return error; 1010 return error;
1010} 1011}
1011 1012
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}
551EXPORT_SYMBOL_GPL(of_platform_depopulate); 551EXPORT_SYMBOL_GPL(of_platform_depopulate);
552 552
553#ifdef CONFIG_OF_DYNAMIC
554static 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
598static struct notifier_block platform_of_notifier = {
599 .notifier_call = of_platform_notify,
600};
601
602void 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 */
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index c2b0627a2317..8a860f096c35 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -84,4 +84,10 @@ static inline int of_platform_populate(struct device_node *root,
84static inline void of_platform_depopulate(struct device *parent) { } 84static inline void of_platform_depopulate(struct device *parent) { }
85#endif 85#endif
86 86
87#ifdef CONFIG_OF_DYNAMIC
88extern void of_platform_register_reconfig_notifier(void);
89#else
90static inline void of_platform_register_reconfig_notifier(void) { }
91#endif
92
87#endif /* _LINUX_OF_PLATFORM_H */ 93#endif /* _LINUX_OF_PLATFORM_H */