diff options
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/address.c | 35 | ||||
-rw-r--r-- | drivers/of/base.c | 23 | ||||
-rw-r--r-- | drivers/of/irq.c | 1 | ||||
-rw-r--r-- | drivers/of/of_i2c.c | 3 | ||||
-rw-r--r-- | drivers/of/platform.c | 16 |
5 files changed, 71 insertions, 7 deletions
diff --git a/drivers/of/address.c b/drivers/of/address.c index 7e262a6124c..72e496f1e9b 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -9,8 +9,8 @@ /* Max address size we deal with */ #define OF_MAX_ADDR_CELLS 4 -#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ - (ns) > 0) +#define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS) +#define OF_CHECK_COUNTS(na, ns) (OF_CHECK_ADDR_COUNT(na) && (ns) > 0) static struct of_bus *of_match_bus(struct device_node *np); static int __of_address_to_resource(struct device_node *dev, @@ -69,6 +69,14 @@ static u64 of_bus_default_map(u32 *addr, const __be32 *range, (unsigned long long)cp, (unsigned long long)s, (unsigned long long)da); + /* + * If the number of address cells is larger than 2 we assume the + * mapping doesn't specify a physical address. Rather, the address + * specifies an identifier that must match exactly. + */ + if (na > 2 && memcmp(range, addr, na * 4) != 0) + return OF_BAD_ADDR; + if (da < cp || da >= (cp + s)) return OF_BAD_ADDR; return da - cp; @@ -182,7 +190,7 @@ const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, } bus->count_cells(dev, &na, &ns); of_node_put(parent); - if (!OF_CHECK_COUNTS(na, ns)) + if (!OF_CHECK_ADDR_COUNT(na)) return NULL; /* Get "reg" or "assigned-addresses" property */ @@ -490,6 +498,25 @@ u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr) } EXPORT_SYMBOL(of_translate_dma_address); +bool of_can_translate_address(struct device_node *dev) +{ + struct device_node *parent; + struct of_bus *bus; + int na, ns; + + parent = of_get_parent(dev); + if (parent == NULL) + return false; + + bus = of_match_bus(parent); + bus->count_cells(dev, &na, &ns); + + of_node_put(parent); + + return OF_CHECK_COUNTS(na, ns); +} +EXPORT_SYMBOL(of_can_translate_address); + const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags) { @@ -506,7 +533,7 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, bus = of_match_bus(parent); bus->count_cells(dev, &na, &ns); of_node_put(parent); - if (!OF_CHECK_COUNTS(na, ns)) + if (!OF_CHECK_ADDR_COUNT(na)) return NULL; /* Get "reg" or "assigned-addresses" property */ diff --git a/drivers/of/base.c b/drivers/of/base.c index d4a1c9a043e..af3b22ac762 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -391,6 +391,29 @@ struct device_node *of_get_next_available_child(const struct device_node *node, EXPORT_SYMBOL(of_get_next_available_child); /** + * of_get_child_by_name - Find the child node by name for a given parent + * @node: parent node + * @name: child name to look for. + * + * This function looks for child node for given matching name + * + * Returns a node pointer if found, with refcount incremented, use + * of_node_put() on it when done. + * Returns NULL if node is not found. + */ +struct device_node *of_get_child_by_name(const struct device_node *node, + const char *name) +{ + struct device_node *child; + + for_each_child_of_node(node, child) + if (child->name && (of_node_cmp(child->name, name) == 0)) + break; + return child; +} +EXPORT_SYMBOL(of_get_child_by_name); + +/** * of_find_node_by_path - Find a node matching a full OF path * @path: The full path to match * diff --git a/drivers/of/irq.c b/drivers/of/irq.c index ff8ab7b2737..a23ec777999 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -392,6 +392,7 @@ int of_irq_to_resource_table(struct device_node *dev, struct resource *res, return i; } +EXPORT_SYMBOL_GPL(of_irq_to_resource_table); struct intc_desc { struct list_head list; diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c index 1e173f35767..3550f3bf4f9 100644 --- a/drivers/of/of_i2c.c +++ b/drivers/of/of_i2c.c @@ -61,6 +61,9 @@ void of_i2c_register_devices(struct i2c_adapter *adap) 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); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index e44f8c2d239..9bdeaf30b17 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -78,6 +78,7 @@ void of_device_make_bus_id(struct device *dev) struct device_node *node = dev->of_node; const u32 *reg; u64 addr; + const __be32 *addrp; int magic; #ifdef CONFIG_PPC_DCR @@ -105,7 +106,15 @@ void of_device_make_bus_id(struct device *dev) */ reg = of_get_property(node, "reg", NULL); if (reg) { - addr = of_translate_address(node, reg); + if (of_can_translate_address(node)) { + addr = of_translate_address(node, reg); + } else { + addrp = of_get_address(node, 0, NULL, NULL); + if (addrp) + addr = of_read_number(addrp, 1); + else + addr = OF_BAD_ADDR; + } if (addr != OF_BAD_ADDR) { dev_set_name(dev, "%llx.%s", (unsigned long long)addr, node->name); @@ -140,8 +149,9 @@ struct platform_device *of_device_alloc(struct device_node *np, return NULL; /* count the io and irq resources */ - while (of_address_to_resource(np, num_reg, &temp_res) == 0) - num_reg++; + if (of_can_translate_address(np)) + while (of_address_to_resource(np, num_reg, &temp_res) == 0) + num_reg++; num_irq = of_irq_count(np); /* Populate the resource table */ |