diff options
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/base.c | 13 | ||||
-rw-r--r-- | drivers/of/of_gpio.c | 4 | ||||
-rw-r--r-- | drivers/of/platform.c | 171 |
3 files changed, 184 insertions, 4 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index b40bffe922..5756f8b60a 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -15,6 +15,7 @@ * GNU General Public License for more details. */ #include <common.h> +#include <deep-probe.h> #include <of.h> #include <of_address.h> #include <errno.h> @@ -1708,6 +1709,15 @@ int of_set_root_node(struct device_node *node) return 0; } +static int barebox_of_populate(void) +{ + if (IS_ENABLED(CONFIG_OFDEVICE) && deep_probe_is_supported()) + return of_probe(); + + return 0; +} +of_populate_initcall(barebox_of_populate); + int barebox_register_of(struct device_node *root) { if (root_node) @@ -1718,7 +1728,8 @@ int barebox_register_of(struct device_node *root) if (IS_ENABLED(CONFIG_OFDEVICE)) { of_clk_init(root, NULL); - return of_probe(); + if (!deep_probe_is_supported()) + return of_probe(); } return 0; diff --git a/drivers/of/of_gpio.c b/drivers/of/of_gpio.c index e1cafdc848..8c45bba8c1 100644 --- a/drivers/of/of_gpio.c +++ b/drivers/of/of_gpio.c @@ -70,6 +70,10 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname, return ret; } + ret = of_device_ensure_probed(out_args.np); + if (ret) + return ret; + dev = of_find_device_by_node(out_args.np); if (!dev) { pr_debug("%s: unable to find device of node %s\n", diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 01de6f98af..178251846e 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -15,6 +15,7 @@ * GNU General Public License for more details. */ #include <common.h> +#include <deep-probe.h> #include <malloc.h> #include <of.h> #include <of_address.h> @@ -29,6 +30,12 @@ struct device_d *of_find_device_by_node(struct device_node *np) { struct device_d *dev; + int ret; + + ret = of_device_ensure_probed(np); + if (ret) + return NULL; + for_each_device(dev) if (dev->device_node == np) return dev; @@ -147,11 +154,14 @@ struct device_d *of_platform_device_create(struct device_node *np, __func__, dev_name(dev), (num_reg) ? &dev->resource[0].start : &resinval); + BUG_ON(np->dev); + np->dev = dev; + ret = platform_device_register(dev); - if (!ret) { - np->dev = dev; + if (!ret) return dev; - } + + np->dev = NULL; free(dev); if (num_reg) @@ -353,3 +363,158 @@ int of_platform_populate(struct device_node *root, return rc; } EXPORT_SYMBOL_GPL(of_platform_populate); + +static struct device_d *of_device_create_on_demand(struct device_node *np) +{ + struct device_node *parent; + struct device_d *parent_dev, *dev; + + parent = of_get_parent(np); + if (!parent) + return NULL; + + if (!np->dev) + pr_debug("Creating device for %s\n", np->full_name); + + /* Create all parent devices needed for the requested device */ + parent_dev = parent->dev ? : of_device_create_on_demand(parent); + if (IS_ERR(parent_dev)) + return parent_dev; + + /* + * Parent devices like i2c/spi controllers are populating their own + * devices. So it can be that the requested device already exists after + * the parent device creation. + */ + if (np->dev) + return np->dev; + + if (of_device_is_compatible(np, "arm,primecell")) + dev = of_amba_device_create(np); + else + dev = of_platform_device_create(np, parent_dev); + + return dev ? : ERR_PTR(-ENODEV); +} + +/** + * of_device_ensure_probed() - ensures that a device is probed + * + * @np: the device_node handle which should be probed + * + * Ensures that the device is populated and probed so frameworks can make use of + * it. + * + * Return: %0 on success + * %-ENODEV if either the device can't be populated, the driver is + * missing or the driver probe returns an error. + */ +int of_device_ensure_probed(struct device_node *np) +{ + struct device_d *dev; + + if (!deep_probe_is_supported()) + return 0; + + dev = of_device_create_on_demand(np); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + BUG_ON(!dev); + + /* + * The deep-probe mechanism relies on the fact that all necessary + * drivers are added before the device creation. Furthermore deep-probe + * is the answer to the EPROBE_DEFER errno so we must ensure that the + * driver was probed successfully after the device creation. Both + * requirements are fulfilled if 'dev->driver' is not NULL. + */ + if (!dev->driver) + return -ENODEV; + + return 0; +} +EXPORT_SYMBOL_GPL(of_device_ensure_probed); + +/** + * of_device_ensure_probed_by_alias() - ensures that a device is probed + * + * @alias: the alias string to search for a device + * + * The function search for a given alias string and ensures that the device is + * populated and probed if found. + * + * Return: %0 on success + * %-ENODEV if either the device can't be populated, the driver is + * missing or the driver probe returns an error + * %-EINVAL if alias can't be found + */ +int of_device_ensure_probed_by_alias(const char *alias) +{ + struct device_node *dev_node; + + dev_node = of_find_node_by_alias(NULL, alias); + if (!dev_node) + return -EINVAL; + + return of_device_ensure_probed(dev_node); +} +EXPORT_SYMBOL_GPL(of_device_ensure_probed_by_alias); + +/** + * of_devices_ensure_probed_by_dev_id() - ensures that devices are probed + * + * @ids: the matching 'struct of_device_id' ids + * + * The function start searching the device tree from @np and populates and + * probes devices which match @ids. + * + * Return: %0 on success + * %-ENODEV if either the device wasn't found, can't be populated, + * the driver is missing or the driver probe returns an error + */ +int of_devices_ensure_probed_by_dev_id(const struct of_device_id *ids) +{ + struct device_node *np; + int err, ret = 0; + + for_each_matching_node(np, ids) { + if (!of_device_is_available(np)) + continue; + + err = of_device_ensure_probed(np); + if (err) + ret = err; + } + + return ret; +} +EXPORT_SYMBOL_GPL(of_devices_ensure_probed_by_dev_id); + +/** + * of_devices_ensure_probed_by_property() - ensures that devices are probed + * + * @property_name: The property name to search for + * + * The function starts searching the whole device tree and populates and probes + * devices which matches @property_name. + * + * Return: %0 on success + * %-ENODEV if either the device wasn't found, can't be populated, + * the driver is missing or the driver probe returns an error + */ +int of_devices_ensure_probed_by_property(const char *property_name) +{ + struct device_node *node; + + for_each_node_with_property(node, property_name) { + int ret; + + ret = of_device_ensure_probed(node); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(of_devices_ensure_probed_by_property); |