Skip to content

Commit 801d728

Browse files
pantoniouglikely
authored andcommitted
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>
1 parent f5242e5 commit 801d728

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

drivers/base/platform.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,7 @@ int __init platform_bus_init(void)
10061006
error = bus_register(&platform_bus_type);
10071007
if (error)
10081008
device_unregister(&platform_bus);
1009+
of_platform_register_reconfig_notifier();
10091010
return error;
10101011
}
10111012

drivers/of/platform.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,4 +550,59 @@ void of_platform_depopulate(struct device *parent)
550550
}
551551
EXPORT_SYMBOL_GPL(of_platform_depopulate);
552552

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+
553608
#endif /* CONFIG_OF_ADDRESS */

include/linux/of_platform.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,10 @@ static inline int of_platform_populate(struct device_node *root,
8484
static inline void of_platform_depopulate(struct device *parent) { }
8585
#endif
8686

87+
#ifdef CONFIG_OF_DYNAMIC
88+
extern void of_platform_register_reconfig_notifier(void);
89+
#else
90+
static inline void of_platform_register_reconfig_notifier(void) { }
91+
#endif
92+
8793
#endif /* _LINUX_OF_PLATFORM_H */

0 commit comments

Comments
 (0)