From 5d61b165c892853f2daf6220d2ec6577487e273a Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 25 Jul 2012 17:34:37 -0600 Subject: of: Allow busses with #size-cells=0 It's quite legitimate for a DT node to specify #size-cells=0. One example is a node that's used to collect a number of non-memory-mapped devices. In that scenario, there may be multiple child nodes with the same name (type) thus necessitating the use of unit addresses in node names, and reg properties: / { regulators { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <0>; regulator@0 { compatible = "regulator-fixed"; reg = <0>; ... }; regulator@1 { compatible = "regulator-fixed"; reg = <1>; ... }; ... }; }; However, #size-cells=0 prevents translation of reg property values into the parent node's address space. In turn, this triggers the kernel to emit error messages during boot, such as: prom_parse: Bad cell count for /regulators/regulator@0 To prevent printing these error messages for legitimate DT content, a number of changes are made: 1) of_get_address()/of_get_pci_address() are modified only to validate the value of #address-cells, and not #size-cells. 2) of_can_translate_address() is added to indicate whether address translation is possible. 3) of_device_make_bus_id() is modified to name devices based on the translated address only where possible, and otherwise fall back to using the (first cell of the) raw untranslated address. 4) of_device_alloc() is modified to create memory resources for a device only if the address can be translated into the CPU's address space. Signed-off-by: Stephen Warren Signed-off-by: Rob Herring --- drivers/of/address.c | 27 +++++++++++++++++++++++---- drivers/of/platform.c | 16 +++++++++++++--- 2 files changed, 36 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/of/address.c b/drivers/of/address.c index 7e262a6124c5..7a07751428de 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, @@ -182,7 +182,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 +490,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 +525,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/platform.c b/drivers/of/platform.c index e44f8c2d239d..9bdeaf30b17d 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 */ -- cgit v1.2.3 From a4f8bf220e415318c739243aaeb2471cf5e8c911 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 26 Aug 2012 09:13:09 +0200 Subject: DT: export of_irq_to_resource_table() Trivial patch that exports the of_irq_to_resource_table() symbol so that modules can use it. Signed-off-by: John Crispin Signed-off-by: Rob Herring --- drivers/of/irq.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/of/irq.c b/drivers/of/irq.c index ff8ab7b27373..a23ec7779997 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; -- cgit v1.2.3 From e38c0a1fbc5803cbacdaac0557c70ac8ca5152e7 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 26 Jul 2012 21:55:10 +0200 Subject: of/address: Handle #address-cells > 2 specially When a bus specifies #address-cells > 2, of_bus_default_map() now assumes that the mapping isn't for a physical address but rather an identifier that needs to match exactly. This is required by bindings that use multiple cells to translate a resource to the parent bus (device index, type, ...). See here for the discussion: https://lists.ozlabs.org/pipermail/devicetree-discuss/2012-June/016577.html Originally-by: Arnd Bergmann Signed-off-by: Thierry Reding Signed-off-by: Rob Herring --- drivers/of/address.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/of/address.c b/drivers/of/address.c index 7a07751428de..72e496f1e9b0 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -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; -- cgit v1.2.3 From ee67016fcc58998c44a9c99b0721568b3d2edc6e Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sat, 21 Jul 2012 11:47:25 -0700 Subject: of: i2c: add support for wakeup-source property Add support for specifying a generic "wakeup-source" property on i2c clients, which will set the I2C_CLIENT_WAKE flag, thus configuring the device to wake the system from suspend (via IRQ). This obviously doesn't make sense on devices lacking IRQ, but since we still allow that in the i2c_board_info case, I don't see a reason to restrict it here. Note: Since the generic i2c bindings aren't documented in the kernel, I didn't find a good place to add documentation for this binding extension. I still think it makes sense to have a generic property instead of having each device do its own binding for the same. Signed-off-by: Olof Johansson Signed-off-by: Rob Herring --- drivers/of/of_i2c.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c index 1e173f357674..3550f3bf4f92 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); -- cgit v1.2.3 From 9c19761a7ecdc86abb2fba0feb81e8952eccc1f1 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 18 Sep 2012 08:10:28 +0100 Subject: dt: introduce of_get_child_by_name to get child node by name This patch introduces of_get_child_by_name function to get a child node by its name in a given parent node. Without this patch each driver code has to iterate the parent and do a string compare, However having of_get_child_by_name libary function would avoid code duplication, errors and is more convenient. Signed-off-by: Srinivas Kandagatla Signed-off-by: Rob Herring --- drivers/of/base.c | 23 +++++++++++++++++++++++ include/linux/of.h | 2 ++ 2 files changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index c181b94abc36..e2e813624df5 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -363,6 +363,29 @@ struct device_node *of_get_next_child(const struct device_node *node, } EXPORT_SYMBOL(of_get_next_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/include/linux/of.h b/include/linux/of.h index 5919ee33f2b7..fabb524d3d75 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -190,6 +190,8 @@ extern struct device_node *of_get_parent(const struct device_node *node); extern struct device_node *of_get_next_parent(struct device_node *node); extern struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev); +extern struct device_node *of_get_child_by_name(const struct device_node *node, + const char *name); #define for_each_child_of_node(parent, child) \ for (child = of_get_next_child(parent, NULL); child != NULL; \ child = of_get_next_child(parent, child)) -- cgit v1.2.3 From 06455bbcab76e5f5225de5f38ab948d37a1c3587 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 18 Sep 2012 08:10:49 +0100 Subject: dt/s3c64xx/spi: Use of_get_child_by_name to get a named child As follow-up to "dt: introduce of_get_child_by_name to get child node by name." patch, This patch removes some of the code duplication in the driver by replacing it with of_get_child_by_name instead. Signed-off-by: Srinivas Kandagatla Signed-off-by: Rob Herring --- drivers/spi/spi-s3c64xx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 646a7657fe62..12b8c9c608ed 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -835,9 +835,7 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( return ERR_PTR(-EINVAL); } - for_each_child_of_node(slave_np, data_np) - if (!strcmp(data_np->name, "controller-data")) - break; + data_np = of_get_child_by_name(slave_np, "controller-data"); if (!data_np) { dev_err(&spi->dev, "child node 'controller-data' not found\n"); return ERR_PTR(-EINVAL); @@ -847,6 +845,7 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( if (!cs) { dev_err(&spi->dev, "could not allocate memory for controller" " data\n"); + of_node_put(data_np); return ERR_PTR(-ENOMEM); } @@ -855,11 +854,13 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( dev_err(&spi->dev, "chip select gpio is not specified or " "invalid\n"); kfree(cs); + of_node_put(data_np); return ERR_PTR(-EINVAL); } of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay); cs->fb_delay = fb_delay; + of_node_put(data_np); return cs; } -- cgit v1.2.3