From 7f4270494946e86c1bdbd9d17161dc785c17c361 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Jul 2013 12:56:15 +0100 Subject: i2c: move OF helpers into the core I2C of helpers used to live in of_i2c.c but experience (from SPI) shows that it is much cleaner to have this in the core. This also removes a circular dependency between the helpers and the core, and so we can finally register child nodes in the core instead of doing this manually in each driver. So, fix the drivers and documentation, too. [Modified to keep a stub device registration API exposed to drivers in order to avoid disruption] Signed-off-by: Wolfram Sang (cherry picked from commit 687b81d083c082bc1e853032e3a2a54f8c251d27) Signed-off-by: Mark Brown Conflicts: drivers/i2c/busses/i2c-designware-platdrv.c drivers/i2c/busses/i2c-imx.c drivers/i2c/busses/i2c-stu300.c drivers/i2c/busses/i2c-wmt.c drivers/of/Kconfig drivers/of/Makefile drivers/staging/imx-drm/imx-tve.c sound/soc/fsl/imx-wm8962.c --- drivers/i2c/i2c-core.c | 109 +++++++++++++++++++++++++++++++++++++++++++++- drivers/i2c/i2c-mux.c | 3 -- drivers/of/Kconfig | 6 --- drivers/of/Makefile | 1 - drivers/of/of_i2c.c | 114 ------------------------------------------------- include/linux/i2c.h | 20 +++++++++ include/linux/of_i2c.h | 29 +------------ 7 files changed, 128 insertions(+), 154 deletions(-) delete mode 100644 drivers/of/of_i2c.c diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 48e31ed69dbf..c00292aa5221 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -23,7 +23,11 @@ SMBus 2.0 support by Mark Studebaker and Jean Delvare Mux support by Rodolfo Giometti and - Michael Lawnick */ + Michael Lawnick + OF support is copyright (c) 2008 Jochen Friedrich + (based on a previous patch from Jon Smirl ) and + (c) 2013 Wolfram Sang + */ #include #include @@ -35,7 +39,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -954,6 +960,104 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter) up_read(&__i2c_board_lock); } +/* OF support code */ + +#if IS_ENABLED(CONFIG_OF) +static void internal_of_i2c_register_devices(struct i2c_adapter *adap) +{ + void *result; + struct device_node *node; + + /* Only register child devices if the adapter has a node pointer set */ + if (!adap->dev.of_node) + return; + + dev_dbg(&adap->dev, "of_i2c: walking child nodes\n"); + + for_each_available_child_of_node(adap->dev.of_node, node) { + struct i2c_board_info info = {}; + struct dev_archdata dev_ad = {}; + const __be32 *addr; + int len; + + dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name); + + if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { + dev_err(&adap->dev, "of_i2c: modalias failure on %s\n", + node->full_name); + continue; + } + + addr = of_get_property(node, "reg", &len); + if (!addr || (len < sizeof(int))) { + dev_err(&adap->dev, "of_i2c: invalid reg on %s\n", + node->full_name); + continue; + } + + info.addr = be32_to_cpup(addr); + if (info.addr > (1 << 10) - 1) { + dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n", + info.addr, node->full_name); + continue; + } + + info.irq = irq_of_parse_and_map(node, 0); + info.of_node = of_node_get(node); + info.archdata = &dev_ad; + + if (of_get_property(node, "wakeup-source", NULL)) + info.flags |= I2C_CLIENT_WAKE; + + request_module("%s%s", I2C_MODULE_PREFIX, info.type); + + result = i2c_new_device(adap, &info); + if (result == NULL) { + dev_err(&adap->dev, "of_i2c: Failure registering %s\n", + node->full_name); + of_node_put(node); + irq_dispose_mapping(info.irq); + continue; + } + } +} + +static int of_dev_node_match(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +/* must call put_device() when done with returned i2c_client device */ +struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) +{ + struct device *dev; + + dev = bus_find_device(&i2c_bus_type, NULL, node, + of_dev_node_match); + if (!dev) + return NULL; + + return i2c_verify_client(dev); +} +EXPORT_SYMBOL(of_find_i2c_device_by_node); + +/* must call put_device() when done with returned i2c_adapter device */ +struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) +{ + struct device *dev; + + dev = bus_find_device(&i2c_bus_type, NULL, node, + of_dev_node_match); + if (!dev) + return NULL; + + return i2c_verify_adapter(dev); +} +EXPORT_SYMBOL(of_find_i2c_adapter_by_node); +#else +static void internal_of_i2c_register_devices(struct i2c_adapter *adap) { } +#endif /* CONFIG_OF */ + static int i2c_do_add_adapter(struct i2c_driver *driver, struct i2c_adapter *adap) { @@ -1058,6 +1162,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap) exit_recovery: /* create pre-declared device nodes */ + internal_of_i2c_register_devices(adap); + if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); @@ -1282,7 +1388,6 @@ void i2c_del_adapter(struct i2c_adapter *adap) } EXPORT_SYMBOL(i2c_del_adapter); - /* ------------------------------------------------------------------------- */ int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *)) diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 7409ebb33c47..797e3117bef7 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -25,7 +25,6 @@ #include #include #include -#include /* multiplexer per channel data */ struct i2c_mux_priv { @@ -185,8 +184,6 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent, dev_info(&parent->dev, "Added multiplexed i2c bus %d\n", i2c_adapter_id(&priv->adap)); - of_i2c_register_devices(&priv->adap); - return &priv->adap; } EXPORT_SYMBOL_GPL(i2c_add_mux_adapter); diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 841a16443b59..df876e1c3864 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -43,12 +43,6 @@ config OF_IRQ config OF_DEVICE def_bool y -config OF_I2C - def_tristate I2C - depends on I2C - help - OpenFirmware I2C accessors - config OF_NET depends on NETDEVICES def_bool y diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 14cb50372b3b..f5162cce7faf 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_OF_PROMTREE) += pdt.o obj-$(CONFIG_OF_ADDRESS) += address.o obj-$(CONFIG_OF_IRQ) += irq.o obj-$(CONFIG_OF_DEVICE) += device.o platform.o -obj-$(CONFIG_OF_I2C) += of_i2c.o obj-$(CONFIG_OF_NET) += of_net.o obj-$(CONFIG_OF_SELFTEST) += selftest.o obj-$(CONFIG_OF_MDIO) += of_mdio.o diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c deleted file mode 100644 index b667264222cc..000000000000 --- a/drivers/of/of_i2c.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * OF helpers for the I2C API - * - * Copyright (c) 2008 Jochen Friedrich - * - * Based on a previous patch from Jon Smirl - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include - -void of_i2c_register_devices(struct i2c_adapter *adap) -{ - void *result; - struct device_node *node; - - /* Only register child devices if the adapter has a node pointer set */ - if (!adap->dev.of_node) - return; - - dev_dbg(&adap->dev, "of_i2c: walking child nodes\n"); - - for_each_available_child_of_node(adap->dev.of_node, node) { - struct i2c_board_info info = {}; - struct dev_archdata dev_ad = {}; - const __be32 *addr; - int len; - - dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name); - - if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { - dev_err(&adap->dev, "of_i2c: modalias failure on %s\n", - node->full_name); - continue; - } - - addr = of_get_property(node, "reg", &len); - if (!addr || (len < sizeof(int))) { - dev_err(&adap->dev, "of_i2c: invalid reg on %s\n", - node->full_name); - continue; - } - - info.addr = be32_to_cpup(addr); - if (info.addr > (1 << 10) - 1) { - dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n", - info.addr, node->full_name); - continue; - } - - info.irq = irq_of_parse_and_map(node, 0); - info.of_node = of_node_get(node); - info.archdata = &dev_ad; - - if (of_get_property(node, "wakeup-source", NULL)) - info.flags |= I2C_CLIENT_WAKE; - - request_module("%s%s", I2C_MODULE_PREFIX, info.type); - - result = i2c_new_device(adap, &info); - if (result == NULL) { - dev_err(&adap->dev, "of_i2c: Failure registering %s\n", - node->full_name); - of_node_put(node); - irq_dispose_mapping(info.irq); - continue; - } - } -} -EXPORT_SYMBOL(of_i2c_register_devices); - -static int of_dev_node_match(struct device *dev, void *data) -{ - return dev->of_node == data; -} - -/* must call put_device() when done with returned i2c_client device */ -struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) -{ - struct device *dev; - - dev = bus_find_device(&i2c_bus_type, NULL, node, - of_dev_node_match); - if (!dev) - return NULL; - - return i2c_verify_client(dev); -} -EXPORT_SYMBOL(of_find_i2c_device_by_node); - -/* must call put_device() when done with returned i2c_adapter device */ -struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) -{ - struct device *dev; - - dev = bus_find_device(&i2c_bus_type, NULL, node, - of_dev_node_match); - if (!dev) - return NULL; - - return i2c_verify_adapter(dev); -} -EXPORT_SYMBOL(of_find_i2c_adapter_by_node); - -MODULE_LICENSE("GPL"); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index e988fa935b3c..21891898ced0 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -542,6 +542,26 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap) #endif /* I2C */ +#if IS_ENABLED(CONFIG_OF) +/* must call put_device() when done with returned i2c_client device */ +extern struct i2c_client *of_find_i2c_device_by_node(struct device_node *node); + +/* must call put_device() when done with returned i2c_adapter device */ +extern struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node); + +#else + +static inline struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) +{ + return NULL; +} + +static inline struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) +{ + return NULL; +} +#endif /* CONFIG_OF */ + #if IS_ENABLED(CONFIG_ACPI_I2C) extern void acpi_i2c_register_devices(struct i2c_adapter *adap); #else diff --git a/include/linux/of_i2c.h b/include/linux/of_i2c.h index cfb545cd86b5..686786c87c73 100644 --- a/include/linux/of_i2c.h +++ b/include/linux/of_i2c.h @@ -12,35 +12,8 @@ #ifndef __LINUX_OF_I2C_H #define __LINUX_OF_I2C_H -#if defined(CONFIG_OF_I2C) || defined(CONFIG_OF_I2C_MODULE) #include -extern void of_i2c_register_devices(struct i2c_adapter *adap); - -/* must call put_device() when done with returned i2c_client device */ -extern struct i2c_client *of_find_i2c_device_by_node(struct device_node *node); - -/* must call put_device() when done with returned i2c_adapter device */ -extern struct i2c_adapter *of_find_i2c_adapter_by_node( - struct device_node *node); - -#else -static inline void of_i2c_register_devices(struct i2c_adapter *adap) -{ - return; -} - -static inline struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) -{ - return NULL; -} - -/* must call put_device() when done with returned i2c_adapter device */ -static inline struct i2c_adapter *of_find_i2c_adapter_by_node( - struct device_node *node) -{ - return NULL; -} -#endif /* CONFIG_OF_I2C */ +static inline void of_i2c_register_devices(struct i2c_adapter *adap) { }; #endif /* __LINUX_OF_I2C_H */ -- cgit v1.2.3 From 4edb763a4caa7df6f60d132674c276bcf9135d72 Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Tue, 28 Oct 2014 22:36:02 +0200 Subject: i2c/of: Factor out Devicetree registration code Dynamically inserting i2c client device nodes requires the use of a single device registration method. Factor out the loop body of of_i2c_register_devices() so that it can be called for individual device_nodes instead of for all the children of a node. Note: The diff of this commit looks far more complicated than it actually is due the indentation being changed for a large block of code. When viewed using the diff -w flag to ignore whitespace changes it can be seen that the change is actually quite simple. Signed-off-by: Pantelis Antoniou [grant.likely: Made new function static and removed changes to header] Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Cc: Rob Herring Cc: linux-i2c@vger.kernel.org (cherry picked from commit a430a3455f2c48995e06b359a82a1109a419e9ef) Signed-off-by: Mark Brown Conflicts: drivers/i2c/i2c-core.c --- drivers/i2c/i2c-core.c | 97 +++++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 45 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index c00292aa5221..7620b0564baf 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -49,6 +49,7 @@ #include #include #include +#include #include "i2c-core.h" @@ -963,63 +964,69 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter) /* OF support code */ #if IS_ENABLED(CONFIG_OF) -static void internal_of_i2c_register_devices(struct i2c_adapter *adap) +static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, + struct device_node *node) { - void *result; - struct device_node *node; + struct i2c_client *result; + struct i2c_board_info info = {}; + struct dev_archdata dev_ad = {}; + const __be32 *addr; + int len; - /* Only register child devices if the adapter has a node pointer set */ - if (!adap->dev.of_node) - return; + dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name); - dev_dbg(&adap->dev, "of_i2c: walking child nodes\n"); + if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { + dev_err(&adap->dev, "of_i2c: modalias failure on %s\n", + node->full_name); + return ERR_PTR(-EINVAL); + } - for_each_available_child_of_node(adap->dev.of_node, node) { - struct i2c_board_info info = {}; - struct dev_archdata dev_ad = {}; - const __be32 *addr; - int len; + addr = of_get_property(node, "reg", &len); + if (!addr || (len < sizeof(int))) { + dev_err(&adap->dev, "of_i2c: invalid reg on %s\n", + node->full_name); + return ERR_PTR(-EINVAL); + } - dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name); + info.addr = be32_to_cpup(addr); + if (info.addr > (1 << 10) - 1) { + dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n", + info.addr, node->full_name); + return ERR_PTR(-EINVAL); + } - if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { - dev_err(&adap->dev, "of_i2c: modalias failure on %s\n", - node->full_name); - continue; - } + info.irq = irq_of_parse_and_map(node, 0); + info.of_node = of_node_get(node); + info.archdata = &dev_ad; - addr = of_get_property(node, "reg", &len); - if (!addr || (len < sizeof(int))) { - dev_err(&adap->dev, "of_i2c: invalid reg on %s\n", - node->full_name); - continue; - } + if (of_get_property(node, "wakeup-source", NULL)) + info.flags |= I2C_CLIENT_WAKE; - info.addr = be32_to_cpup(addr); - if (info.addr > (1 << 10) - 1) { - dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n", - info.addr, node->full_name); - continue; - } + request_module("%s%s", I2C_MODULE_PREFIX, info.type); - info.irq = irq_of_parse_and_map(node, 0); - info.of_node = of_node_get(node); - info.archdata = &dev_ad; + result = i2c_new_device(adap, &info); + if (result == NULL) { + dev_err(&adap->dev, "of_i2c: Failure registering %s\n", + node->full_name); + of_node_put(node); + irq_dispose_mapping(info.irq); + return ERR_PTR(-EINVAL); + } + return result; +} + +static void internal_of_i2c_register_devices(struct i2c_adapter *adap) +{ + struct device_node *node; - if (of_get_property(node, "wakeup-source", NULL)) - info.flags |= I2C_CLIENT_WAKE; + /* Only register child devices if the adapter has a node pointer set */ + if (!adap->dev.of_node) + return; - request_module("%s%s", I2C_MODULE_PREFIX, info.type); + dev_dbg(&adap->dev, "of_i2c: walking child nodes\n"); - result = i2c_new_device(adap, &info); - if (result == NULL) { - dev_err(&adap->dev, "of_i2c: Failure registering %s\n", - node->full_name); - of_node_put(node); - irq_dispose_mapping(info.irq); - continue; - } - } + for_each_available_child_of_node(adap->dev.of_node, node) + of_i2c_register_device(adap, node); } static int of_dev_node_match(struct device *dev, void *data) -- cgit v1.2.3 From 9f2de29f83de83f8ea7c7ce5f9afbecadd72b507 Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Tue, 28 Oct 2014 22:36:03 +0200 Subject: i2c/of: Add OF_RECONFIG notifier handler CONFIG_OF_DYNAMIC enables runtime changes to the device tree which in turn may trigger addition or removal of devices from Linux. Add an OF_RECONFIG notifier handler to receive tree change events and to creating or destroy i2c devices as required. Signed-off-by: Pantelis Antoniou [grant.likely: clean up #ifdefs and drop unneeded error handling] Signed-off-by: Grant Likely Reviewed-by: Wolfram Sang Cc: Rob Herring Cc: linux-i2c@vger.kernel.org (cherry picked from commit ea7513bbc04170f1cbf42953187a4d8b731c71c4) Signed-off-by: Mark Brown --- drivers/i2c/i2c-core.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 7620b0564baf..dac8cd5031e7 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1538,6 +1538,52 @@ void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) } EXPORT_SYMBOL(i2c_clients_command); +#if IS_ENABLED(CONFIG_OF_DYNAMIC) +static int of_i2c_notify(struct notifier_block *nb, unsigned long action, + void *arg) +{ + struct of_reconfig_data *rd = arg; + struct i2c_adapter *adap; + struct i2c_client *client; + + switch (of_reconfig_get_state_change(action, rd)) { + case OF_RECONFIG_CHANGE_ADD: + adap = of_find_i2c_adapter_by_node(rd->dn->parent); + if (adap == NULL) + return NOTIFY_OK; /* not for us */ + + client = of_i2c_register_device(adap, rd->dn); + put_device(&adap->dev); + + if (IS_ERR(client)) { + pr_err("%s: failed to create for '%s'\n", + __func__, rd->dn->full_name); + return notifier_from_errno(PTR_ERR(client)); + } + break; + case OF_RECONFIG_CHANGE_REMOVE: + /* find our device by node */ + client = of_find_i2c_device_by_node(rd->dn); + if (client == NULL) + return NOTIFY_OK; /* no? not meant for us */ + + /* unregister takes one ref away */ + i2c_unregister_device(client); + + /* and put the reference of the find */ + put_device(&client->dev); + break; + } + + return NOTIFY_OK; +} +static struct notifier_block i2c_of_notifier = { + .notifier_call = of_i2c_notify, +}; +#else +extern struct notifier_block i2c_of_notifier; +#endif /* CONFIG_OF_DYNAMIC */ + static int __init i2c_init(void) { int retval; @@ -1555,6 +1601,10 @@ static int __init i2c_init(void) retval = i2c_add_driver(&dummy_driver); if (retval) goto class_err; + + if (IS_ENABLED(CONFIG_OF_DYNAMIC)) + WARN_ON(of_reconfig_notifier_register(&i2c_of_notifier)); + return 0; class_err: @@ -1568,6 +1618,8 @@ bus_err: static void __exit i2c_exit(void) { + if (IS_ENABLED(CONFIG_OF_DYNAMIC)) + WARN_ON(of_reconfig_notifier_unregister(&i2c_of_notifier)); i2c_del_driver(&dummy_driver); #ifdef CONFIG_I2C_COMPAT class_compat_unregister(i2c_adapter_compat_class); -- cgit v1.2.3 From 5722d513b0d502b9d6bb08d16a1bd1da3c1f2fd7 Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Thu, 15 Jan 2015 18:33:55 +0200 Subject: i2c: Mark instantiated device nodes with OF_POPULATE Mark (and unmark) device nodes with the POPULATE flag as appropriate. This is required to avoid multi probing when using I2C and device overlays containing a mux. Signed-off-by: Pantelis Antoniou Signed-off-by: Wolfram Sang (cherry picked from commit d5285c36e6d27c1a411a3131c034641a5fa452cb) Signed-off-by: Mark Brown --- drivers/i2c/i2c-core.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index dac8cd5031e7..92588d3bae45 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -704,6 +704,8 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { + if (client->dev.of_node) + of_node_clear_flag(client->dev.of_node, OF_POPULATED); device_unregister(&client->dev); } EXPORT_SYMBOL_GPL(i2c_unregister_device); @@ -1025,8 +1027,11 @@ static void internal_of_i2c_register_devices(struct i2c_adapter *adap) dev_dbg(&adap->dev, "of_i2c: walking child nodes\n"); - for_each_available_child_of_node(adap->dev.of_node, node) + for_each_available_child_of_node(adap->dev.of_node, node) { + if (of_node_test_and_set_flag(node, OF_POPULATED)) + continue; of_i2c_register_device(adap, node); + } } static int of_dev_node_match(struct device *dev, void *data) @@ -1552,6 +1557,11 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, if (adap == NULL) return NOTIFY_OK; /* not for us */ + if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) { + put_device(&adap->dev); + return NOTIFY_OK; + } + client = of_i2c_register_device(adap, rd->dn); put_device(&adap->dev); @@ -1562,6 +1572,10 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, } break; case OF_RECONFIG_CHANGE_REMOVE: + /* already depopulated? */ + if (!of_node_check_flag(rd->dn, OF_POPULATED)) + return NOTIFY_OK; + /* find our device by node */ client = of_find_i2c_device_by_node(rd->dn); if (client == NULL) -- cgit v1.2.3 From 6f491cafa26fe73636523730bcffb4ee99f5f21c Mon Sep 17 00:00:00 2001 From: Pantelis Antoniou Date: Thu, 15 Jan 2015 20:33:18 +0200 Subject: i2c: Mark instantiated device nodes with OF_POPULATE Mark (and unmark) device nodes with the POPULATE flag as appropriate. This is required to avoid multi probing when using I2C and device overlays containing a mux. Signed-off-by: Pantelis Antoniou Signed-off-by: Wolfram Sang (cherry picked from commit 6d0a0d9ad09be16e3ca676b245643945b4bff47d) Signed-off-by: Mark Brown Conflicts: drivers/i2c/i2c-core.c --- drivers/i2c/i2c-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 92588d3bae45..780599ce4657 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -704,8 +704,10 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { +#if IS_ENABLED(CONFIG_OF_DYNAMIC) if (client->dev.of_node) of_node_clear_flag(client->dev.of_node, OF_POPULATED); +#endif device_unregister(&client->dev); } EXPORT_SYMBOL_GPL(i2c_unregister_device); -- cgit v1.2.3