diff options
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/base.c | 68 | ||||
-rw-r--r-- | drivers/of/gpio.c | 70 | ||||
-rw-r--r-- | drivers/of/of_i2c.c | 11 |
3 files changed, 129 insertions, 20 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index 7c79e94a35ea..cd17092b82bd 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -329,6 +329,41 @@ struct device_node *of_find_compatible_node(struct device_node *from, EXPORT_SYMBOL(of_find_compatible_node); /** + * of_find_node_with_property - Find a node which has a property with + * the given name. + * @from: The node to start searching from or NULL, the node + * you pass will not be searched, only the next one + * will; typically, you pass what the previous call + * returned. of_node_put() will be called on it + * @prop_name: The name of the property to look for. + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_find_node_with_property(struct device_node *from, + const char *prop_name) +{ + struct device_node *np; + struct property *pp; + + read_lock(&devtree_lock); + np = from ? from->allnext : allnodes; + for (; np; np = np->allnext) { + for (pp = np->properties; pp != 0; pp = pp->next) { + if (of_prop_cmp(pp->name, prop_name) == 0) { + of_node_get(np); + goto out; + } + } + } +out: + of_node_put(from); + read_unlock(&devtree_lock); + return np; +} +EXPORT_SYMBOL(of_find_node_with_property); + +/** * of_match_node - Tell if an device_node has a matching of_match structure * @matches: array of of device match structures to search in * @node: the of device structure to match against @@ -464,8 +499,8 @@ EXPORT_SYMBOL_GPL(of_modalias_node); * @list_name: property name that contains a list * @cells_name: property name that specifies phandles' arguments count * @index: index of a phandle to parse out - * @out_node: pointer to device_node struct pointer (will be filled) - * @out_args: pointer to arguments pointer (will be filled) + * @out_node: optional pointer to device_node struct pointer (will be filled) + * @out_args: optional pointer to arguments pointer (will be filled) * * This function is useful to parse lists of phandles and their arguments. * Returns 0 on success and fills out_node and out_args, on error returns @@ -499,7 +534,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, int size; int cur_index = 0; struct device_node *node = NULL; - const void *args; + const void *args = NULL; list = of_get_property(np, list_name, &size); if (!list) { @@ -512,14 +547,12 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, const u32 *cells; const phandle *phandle; - phandle = list; - args = list + 1; + phandle = list++; + args = list; /* one cell hole in the list = <>; */ - if (!*phandle) { - list++; + if (!*phandle) goto next; - } node = of_find_node_by_phandle(*phandle); if (!node) { @@ -535,8 +568,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, goto err1; } - /* Next phandle is at offset of one phandle cell + #cells */ - list += 1 + *cells; + list += *cells; if (list > list_end) { pr_debug("%s: insufficient arguments length\n", np->full_name); @@ -548,16 +580,26 @@ next: of_node_put(node); node = NULL; + args = NULL; cur_index++; } if (!node) { - ret = -ENOENT; + /* + * args w/o node indicates that the loop above has stopped at + * the 'hole' cell. Report this differently. + */ + if (args) + ret = -EEXIST; + else + ret = -ENOENT; goto err0; } - *out_node = node; - *out_args = args; + if (out_node) + *out_node = node; + if (out_args) + *out_args = args; return 0; err1: diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index 7cd7301b5839..6eea601a9204 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -19,14 +19,17 @@ #include <asm/prom.h> /** - * of_get_gpio - Get a GPIO number from the device tree to use with GPIO API + * of_get_gpio_flags - Get a GPIO number and flags to use with GPIO API * @np: device node to get GPIO from * @index: index of the GPIO + * @flags: a flags pointer to fill in * * Returns GPIO number to use with Linux generic GPIO API, or one of the errno - * value on the error condition. + * value on the error condition. If @flags is not NULL the function also fills + * in flags for the GPIO. */ -int of_get_gpio(struct device_node *np, int index) +int of_get_gpio_flags(struct device_node *np, int index, + enum of_gpio_flags *flags) { int ret; struct device_node *gc; @@ -59,7 +62,11 @@ int of_get_gpio(struct device_node *np, int index) goto err1; } - ret = of_gc->xlate(of_gc, np, gpio_spec); + /* .xlate might decide to not fill in the flags, so clear it. */ + if (flags) + *flags = 0; + + ret = of_gc->xlate(of_gc, np, gpio_spec, flags); if (ret < 0) goto err1; @@ -70,26 +77,75 @@ err0: pr_debug("%s exited with status %d\n", __func__, ret); return ret; } -EXPORT_SYMBOL(of_get_gpio); +EXPORT_SYMBOL(of_get_gpio_flags); /** - * of_gpio_simple_xlate - translate gpio_spec to the GPIO number + * of_gpio_count - Count GPIOs for a device + * @np: device node to count GPIOs for + * + * The function returns the count of GPIOs specified for a node. + * + * Note that the empty GPIO specifiers counts too. For example, + * + * gpios = <0 + * &pio1 1 2 + * 0 + * &pio2 3 4>; + * + * defines four GPIOs (so this function will return 4), two of which + * are not specified. + */ +unsigned int of_gpio_count(struct device_node *np) +{ + unsigned int cnt = 0; + + do { + int ret; + + ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", + cnt, NULL, NULL); + /* A hole in the gpios = <> counts anyway. */ + if (ret < 0 && ret != -EEXIST) + break; + } while (++cnt); + + return cnt; +} +EXPORT_SYMBOL(of_gpio_count); + +/** + * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags * @of_gc: pointer to the of_gpio_chip structure * @np: device node of the GPIO chip * @gpio_spec: gpio specifier as found in the device tree + * @flags: a flags pointer to fill in * * This is simple translation function, suitable for the most 1:1 mapped * gpio chips. This function performs only one sanity check: whether gpio * is less than ngpios (that is specified in the gpio_chip). */ int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np, - const void *gpio_spec) + const void *gpio_spec, enum of_gpio_flags *flags) { const u32 *gpio = gpio_spec; + /* + * We're discouraging gpio_cells < 2, since that way you'll have to + * write your own xlate function (that will have to retrive the GPIO + * number and the flags from a single gpio cell -- this is possible, + * but not recommended). + */ + if (of_gc->gpio_cells < 2) { + WARN_ON(1); + return -EINVAL; + } + if (*gpio > of_gc->gc.ngpio) return -EINVAL; + if (flags) + *flags = gpio[1]; + return *gpio; } EXPORT_SYMBOL(of_gpio_simple_xlate); diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c index 24bbef777c19..e1b0ad6e918f 100644 --- a/drivers/of/of_i2c.c +++ b/drivers/of/of_i2c.c @@ -24,6 +24,7 @@ void of_register_i2c_devices(struct i2c_adapter *adap, for_each_child_of_node(adap_node, node) { struct i2c_board_info info = {}; + struct dev_archdata dev_ad = {}; const u32 *addr; int len; @@ -41,6 +42,9 @@ void of_register_i2c_devices(struct i2c_adapter *adap, info.addr = *addr; + dev_archdata_set_node(&dev_ad, node); + info.archdata = &dev_ad; + request_module("%s", info.type); result = i2c_new_device(adap, &info); @@ -51,6 +55,13 @@ void of_register_i2c_devices(struct i2c_adapter *adap, irq_dispose_mapping(info.irq); continue; } + + /* + * Get the node to not lose the dev_archdata->of_node. + * Currently there is no way to put it back, as well as no + * of_unregister_i2c_devices() call. + */ + of_node_get(node); } } EXPORT_SYMBOL(of_register_i2c_devices); |