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>
This commit is contained in:
parent
f5242e5a88
commit
801d728c10
|
@ -1006,6 +1006,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -550,4 +550,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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue