diff options
Diffstat (limited to 'drivers/gpio/gpiolib-of.c')
-rw-r--r-- | drivers/gpio/gpiolib-of.c | 87 |
1 files changed, 52 insertions, 35 deletions
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index f1a45997aea8..a71a54a3e3f7 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -19,6 +19,7 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_gpio.h> +#include <linux/pinctrl/pinctrl.h> #include <linux/slab.h> /* Private data structure for of_gpiochip_find_and_xlate */ @@ -88,41 +89,6 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname, EXPORT_SYMBOL(of_get_named_gpio_flags); /** - * of_gpio_named_count - Count GPIOs for a device - * @np: device node to count GPIOs for - * @propname: property name containing gpio specifier(s) - * - * 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_named_count(struct device_node *np, const char* propname) -{ - unsigned int cnt = 0; - - do { - int ret; - - ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", - cnt, NULL); - /* A hole in the gpios = <> counts anyway. */ - if (ret < 0 && ret != -EEXIST) - break; - } while (++cnt); - - return cnt; -} -EXPORT_SYMBOL(of_gpio_named_count); - -/** * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags * @gc: pointer to the gpio_chip structure * @np: device node of the GPIO chip @@ -216,6 +182,54 @@ err0: } EXPORT_SYMBOL(of_mm_gpiochip_add); +#ifdef CONFIG_PINCTRL +static void of_gpiochip_add_pin_range(struct gpio_chip *chip) +{ + struct device_node *np = chip->of_node; + struct of_phandle_args pinspec; + struct pinctrl_dev *pctldev; + int index = 0, ret; + + if (!np) + return; + + do { + ret = of_parse_phandle_with_args(np, "gpio-ranges", + "#gpio-range-cells", index, &pinspec); + if (ret) + break; + + pctldev = of_pinctrl_get(pinspec.np); + if (!pctldev) + break; + + /* + * This assumes that the n GPIO pins are consecutive in the + * GPIO number space, and that the pins are also consecutive + * in their local number space. Currently it is not possible + * to add different ranges for one and the same GPIO chip, + * as the code assumes that we have one consecutive range + * on both, mapping 1-to-1. + * + * TODO: make the OF bindings handle multiple sparse ranges + * on the same GPIO chip. + */ + ret = gpiochip_add_pin_range(chip, + pinctrl_dev_get_devname(pctldev), + 0, /* offset in gpiochip */ + pinspec.args[0], + pinspec.args[1]); + + if (ret) + break; + + } while (index++); +} + +#else +static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {} +#endif + void of_gpiochip_add(struct gpio_chip *chip) { if ((!chip->of_node) && (chip->dev)) @@ -229,11 +243,14 @@ void of_gpiochip_add(struct gpio_chip *chip) chip->of_xlate = of_gpio_simple_xlate; } + of_gpiochip_add_pin_range(chip); of_node_get(chip->of_node); } void of_gpiochip_remove(struct gpio_chip *chip) { + gpiochip_remove_pin_ranges(chip); + if (chip->of_node) of_node_put(chip->of_node); } |