CONFIG_OF_DYNAMIC allows runtime changes to the device tree. This patch adds a OF_RECONFIG handler to receive notifications on tree changes to support adding/removing cells from an nvmem device based on these changes. Signed-off-by: Michael Auchter <michael.auchter@xxxxxx> --- drivers/nvmem/core.c | 61 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 91979529cb07..859431c15d5b 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1629,6 +1629,53 @@ void nvmem_del_cell_lookups(struct nvmem_cell_lookup *entries, size_t nentries) } EXPORT_SYMBOL_GPL(nvmem_del_cell_lookups); +#if IS_ENABLED(CONFIG_OF_DYNAMIC) +static int of_nvmem_notify(struct notifier_block *nb, unsigned long action, + void *arg) +{ + + struct of_reconfig_data *rd = arg; + struct nvmem_device *nvmem; + struct nvmem_cell *cell; + int rval; + + switch (of_reconfig_get_state_change(action, rd)) { + case OF_RECONFIG_CHANGE_ADD: + if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) + return NOTIFY_OK; + + nvmem = __nvmem_device_get(rd->dn->parent, device_match_of_node); + if (IS_ERR(nvmem)) + return NOTIFY_OK; + + rval = nvmem_add_cell_from_of(nvmem, rd->dn); + return notifier_from_errno(rval); + break; + case OF_RECONFIG_CHANGE_REMOVE: + if (!of_node_check_flag(rd->dn, OF_POPULATED)) + return NOTIFY_OK; + + nvmem = __nvmem_device_get(rd->dn->parent, device_match_of_node); + if (IS_ERR(nvmem)) + return NOTIFY_OK; + + cell = nvmem_find_cell_by_node(nvmem, rd->dn); + if (!cell) + return NOTIFY_OK; + + nvmem_cell_drop(cell); + of_node_clear_flag(rd->dn, OF_POPULATED); + break; + } + + return NOTIFY_OK; +} + +struct notifier_block nvmem_of_notifier = { + .notifier_call = of_nvmem_notify, +}; +#endif /* CONFIG_OF_DYNAMIC */ + /** * nvmem_dev_name() - Get the name of a given nvmem device. * @@ -1644,11 +1691,23 @@ EXPORT_SYMBOL_GPL(nvmem_dev_name); static int __init nvmem_init(void) { - return bus_register(&nvmem_bus_type); + int rval; + + rval = bus_register(&nvmem_bus_type); + if (rval) + return rval; + + if (IS_ENABLED(CONFIG_OF_DYNAMIC)) + WARN_ON(of_reconfig_notifier_register(&nvmem_of_notifier)); + + return 0; } static void __exit nvmem_exit(void) { + if (IS_ENABLED(CONFIG_OF_DYNAMIC)) + WARN_ON(of_reconfig_notifier_unregister(&nvmem_of_notifier)); + bus_unregister(&nvmem_bus_type); } -- 2.25.4