diff options
author | Pantelis Antoniou <pantelis.antoniou@konsulko.com> | 2014-10-28 22:36:01 +0200 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-02-20 23:41:27 +0900 |
commit | 94b62a841aac10919826afaf3cdee118dbdabef2 (patch) | |
tree | 4634ee475570e0c82dd574390874b991abf46f32 | |
parent | 8a575393a241e60bdc35f21ebe6f112b8e087227 (diff) | |
download | linux-linaro-stable-94b62a841aac10919826afaf3cdee118dbdabef2.tar.gz |
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>
(cherry picked from commit 801d728c10db4b28e01590b46bf1f0df930760cc)
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | drivers/base/platform.c | 1 | ||||
-rw-r--r-- | drivers/of/platform.c | 55 | ||||
-rw-r--r-- | include/linux/of_platform.h | 6 |
3 files changed, 62 insertions, 0 deletions
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index bc78848dd59a..3b977de18bab 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -937,6 +937,7 @@ int __init platform_bus_init(void) error = bus_register(&platform_bus_type); if (error) device_unregister(&platform_bus); + of_platform_register_reconfig_notifier(); return error; } diff --git a/drivers/of/platform.c b/drivers/of/platform.c index b98e501588d3..ad662c6fa471 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -496,4 +496,59 @@ void of_platform_depopulate(struct device *parent) } EXPORT_SYMBOL_GPL(of_platform_depopulate); +#ifdef CONFIG_OF_DYNAMIC +static int of_platform_notify(struct notifier_block *nb, + unsigned long action, void *arg) +{ + struct of_reconfig_data *rd = arg; + struct platform_device *pdev_parent, *pdev; + bool children_left; + + switch (of_reconfig_get_state_change(action, rd)) { + case OF_RECONFIG_CHANGE_ADD: + /* verify that the parent is a bus */ + if (!of_node_check_flag(rd->dn->parent, OF_POPULATED_BUS)) + return NOTIFY_OK; /* not for us */ + + /* pdev_parent may be NULL when no bus platform device */ + pdev_parent = of_find_device_by_node(rd->dn->parent); + pdev = of_platform_device_create(rd->dn, NULL, + pdev_parent ? &pdev_parent->dev : NULL); + of_dev_put(pdev_parent); + + if (pdev == NULL) { + pr_err("%s: failed to create for '%s'\n", + __func__, rd->dn->full_name); + /* of_platform_device_create tosses the error code */ + return notifier_from_errno(-EINVAL); + } + break; + + case OF_RECONFIG_CHANGE_REMOVE: + /* find our device by node */ + pdev = of_find_device_by_node(rd->dn); + if (pdev == NULL) + return NOTIFY_OK; /* no? not meant for us */ + + /* unregister takes one ref away */ + of_platform_device_destroy(&pdev->dev, &children_left); + + /* and put the reference of the find */ + of_dev_put(pdev); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block platform_of_notifier = { + .notifier_call = of_platform_notify, +}; + +void of_platform_register_reconfig_notifier(void) +{ + WARN_ON(of_reconfig_notifier_register(&platform_of_notifier)); +} +#endif /* CONFIG_OF_DYNAMIC */ + #endif /* CONFIG_OF_ADDRESS */ diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index d0a441468294..9142922871a7 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, static inline void of_platform_depopulate(struct device *parent) { } #endif +#ifdef CONFIG_OF_DYNAMIC +extern void of_platform_register_reconfig_notifier(void); +#else +static inline void of_platform_register_reconfig_notifier(void) { } +#endif + #endif /* _LINUX_OF_PLATFORM_H */ |