Skip to content

Commit

Permalink
of/reconfig: Add OF_DYNAMIC notifier for platform_bus_type
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Pantelis Antoniou authored and Grant Likely committed Nov 24, 2014
1 parent f5242e5 commit 801d728
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/base/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
55 changes: 55 additions & 0 deletions drivers/of/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
6 changes: 6 additions & 0 deletions include/linux/of_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

0 comments on commit 801d728

Please sign in to comment.