diff options
Diffstat (limited to 'drivers/of/property.c')
-rw-r--r-- | drivers/of/property.c | 59 |
1 files changed, 52 insertions, 7 deletions
diff --git a/drivers/of/property.c b/drivers/of/property.c index 5f9eed79a8aa..5036a362f52e 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -24,6 +24,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_graph.h> +#include <linux/of_irq.h> #include <linux/string.h> #include <linux/moduleparam.h> @@ -1102,7 +1103,9 @@ static int of_link_to_phandle(struct device_node *con_np, * created for them. */ sup_dev = get_dev_from_fwnode(&sup_np->fwnode); - if (!sup_dev && of_node_check_flag(sup_np, OF_POPULATED)) { + if (!sup_dev && + (of_node_check_flag(sup_np, OF_POPULATED) || + sup_np->fwnode.flags & FWNODE_FLAG_NOT_DEVICE)) { pr_debug("Not linking %pOFP to %pOFP - No struct device\n", con_np, sup_np); of_node_put(sup_np); @@ -1232,6 +1235,7 @@ static struct device_node *parse_##fname(struct device_node *np, \ struct supplier_bindings { struct device_node *(*parse_prop)(struct device_node *np, const char *prop_name, int index); + bool optional; }; DEFINE_SIMPLE_PROP(clocks, "clocks", "#clock-cells") @@ -1244,8 +1248,6 @@ DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-cells") DEFINE_SIMPLE_PROP(power_domains, "power-domains", "#power-domain-cells") DEFINE_SIMPLE_PROP(hwlocks, "hwlocks", "#hwlock-cells") DEFINE_SIMPLE_PROP(extcon, "extcon", NULL) -DEFINE_SIMPLE_PROP(interrupts_extended, "interrupts-extended", - "#interrupt-cells") DEFINE_SIMPLE_PROP(nvmem_cells, "nvmem-cells", NULL) DEFINE_SIMPLE_PROP(phys, "phys", "#phy-cells") DEFINE_SIMPLE_PROP(wakeup_parent, "wakeup-parent", NULL) @@ -1271,19 +1273,55 @@ static struct device_node *parse_iommu_maps(struct device_node *np, return of_parse_phandle(np, prop_name, (index * 4) + 1); } +static struct device_node *parse_gpio_compat(struct device_node *np, + const char *prop_name, int index) +{ + struct of_phandle_args sup_args; + + if (strcmp(prop_name, "gpio") && strcmp(prop_name, "gpios")) + return NULL; + + /* + * Ignore node with gpio-hog property since its gpios are all provided + * by its parent. + */ + if (of_find_property(np, "gpio-hog", NULL)) + return NULL; + + if (of_parse_phandle_with_args(np, prop_name, "#gpio-cells", index, + &sup_args)) + return NULL; + + return sup_args.np; +} + +static struct device_node *parse_interrupts(struct device_node *np, + const char *prop_name, int index) +{ + struct of_phandle_args sup_args; + + if (!IS_ENABLED(CONFIG_OF_IRQ) || IS_ENABLED(CONFIG_PPC)) + return NULL; + + if (strcmp(prop_name, "interrupts") && + strcmp(prop_name, "interrupts-extended")) + return NULL; + + return of_irq_parse_one(np, index, &sup_args) ? NULL : sup_args.np; +} + static const struct supplier_bindings of_supplier_bindings[] = { { .parse_prop = parse_clocks, }, { .parse_prop = parse_interconnects, }, - { .parse_prop = parse_iommus, }, - { .parse_prop = parse_iommu_maps, }, + { .parse_prop = parse_iommus, .optional = true, }, + { .parse_prop = parse_iommu_maps, .optional = true, }, { .parse_prop = parse_mboxes, }, { .parse_prop = parse_io_channels, }, { .parse_prop = parse_interrupt_parent, }, - { .parse_prop = parse_dmas, }, + { .parse_prop = parse_dmas, .optional = true, }, { .parse_prop = parse_power_domains, }, { .parse_prop = parse_hwlocks, }, { .parse_prop = parse_extcon, }, - { .parse_prop = parse_interrupts_extended, }, { .parse_prop = parse_nvmem_cells, }, { .parse_prop = parse_phys, }, { .parse_prop = parse_wakeup_parent, }, @@ -1296,6 +1334,8 @@ static const struct supplier_bindings of_supplier_bindings[] = { { .parse_prop = parse_pinctrl6, }, { .parse_prop = parse_pinctrl7, }, { .parse_prop = parse_pinctrl8, }, + { .parse_prop = parse_gpio_compat, }, + { .parse_prop = parse_interrupts, }, { .parse_prop = parse_regulators, }, { .parse_prop = parse_gpio, }, { .parse_prop = parse_gpios, }, @@ -1332,6 +1372,11 @@ static int of_link_property(struct device_node *con_np, const char *prop_name) /* Do not stop at first failed link, link all available suppliers. */ while (!matched && s->parse_prop) { + if (s->optional && !fw_devlink_is_strict()) { + s++; + continue; + } + while ((phandle = s->parse_prop(con_np, prop_name, i))) { matched = true; i++; |