diff options
Diffstat (limited to 'drivers/gpio/gpiolib-of.c')
| -rw-r--r-- | drivers/gpio/gpiolib-of.c | 104 | 
1 files changed, 86 insertions, 18 deletions
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 0dfaf20e4da..af7e25c9a9a 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -12,22 +12,25 @@   */  #include <linux/device.h> +#include <linux/err.h>  #include <linux/errno.h>  #include <linux/module.h>  #include <linux/io.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h>  #include <linux/of.h>  #include <linux/of_address.h>  #include <linux/of_gpio.h>  #include <linux/pinctrl/pinctrl.h>  #include <linux/slab.h> +struct gpio_desc; +  /* Private data structure for of_gpiochip_find_and_xlate */  struct gg_data {  	enum of_gpio_flags *flags;  	struct of_phandle_args gpiospec; -	int out_gpio; +	struct gpio_desc *out_gpio;  };  /* Private function for resolving node pointer to gpio_chip */ @@ -45,28 +48,31 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)  	if (ret < 0)  		return false; -	gg_data->out_gpio = ret + gc->base; +	gg_data->out_gpio = gpiochip_get_desc(gc, ret);  	return true;  }  /** - * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API + * of_get_named_gpiod_flags() - Get a GPIO descriptor and flags for GPIO API   * @np:		device node to get GPIO from   * @propname:	property name containing gpio specifier(s)   * @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 + * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno   * value on the error condition. If @flags is not NULL the function also fills   * in flags for the GPIO.   */ -int of_get_named_gpio_flags(struct device_node *np, const char *propname, -			   int index, enum of_gpio_flags *flags) +struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, +		     const char *propname, int index, enum of_gpio_flags *flags)  {  	/* Return -EPROBE_DEFER to support probe() functions to be called  	 * later when the GPIO actually becomes available  	 */ -	struct gg_data gg_data = { .flags = flags, .out_gpio = -EPROBE_DEFER }; +	struct gg_data gg_data = { +		.flags = flags, +		.out_gpio = ERR_PTR(-EPROBE_DEFER) +	};  	int ret;  	/* .of_xlate might decide to not fill in the flags, so clear it. */ @@ -78,15 +84,30 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname,  	if (ret) {  		pr_debug("%s: can't parse gpios property of node '%s[%d]'\n",  			__func__, np->full_name, index); -		return ret; +		return ERR_PTR(ret);  	}  	gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);  	of_node_put(gg_data.gpiospec.np); -	pr_debug("%s exited with status %d\n", __func__, gg_data.out_gpio); +	pr_debug("%s exited with status %d\n", __func__, +		 PTR_ERR_OR_ZERO(gg_data.out_gpio));  	return gg_data.out_gpio;  } +EXPORT_SYMBOL(of_get_named_gpiod_flags); + +int of_get_named_gpio_flags(struct device_node *np, const char *list_name, +			    int index, enum of_gpio_flags *flags) +{ +	struct gpio_desc *desc; + +	desc = of_get_named_gpiod_flags(np, list_name, index, flags); + +	if (IS_ERR(desc)) +		return PTR_ERR(desc); +	else +		return desc_to_gpio(desc); +}  EXPORT_SYMBOL(of_get_named_gpio_flags);  /** @@ -190,10 +211,15 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)  	struct of_phandle_args pinspec;  	struct pinctrl_dev *pctldev;  	int index = 0, ret; +	const char *name; +	static const char group_names_propname[] = "gpio-ranges-group-names"; +	struct property *group_names;  	if (!np)  		return; +	group_names = of_find_property(np, group_names_propname, NULL); +  	for (;; index++) {  		ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,  				index, &pinspec); @@ -204,14 +230,56 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)  		if (!pctldev)  			break; -		ret = gpiochip_add_pin_range(chip, -					     pinctrl_dev_get_devname(pctldev), -					     pinspec.args[0], -					     pinspec.args[1], -					     pinspec.args[2]); - -		if (ret) -			break; +		if (pinspec.args[2]) { +			if (group_names) { +				ret = of_property_read_string_index(np, +						group_names_propname, +						index, &name); +				if (strlen(name)) { +					pr_err("%s: Group name of numeric GPIO ranges must be the empty string.\n", +						np->full_name); +					break; +				} +			} +			/* npins != 0: linear range */ +			ret = gpiochip_add_pin_range(chip, +					pinctrl_dev_get_devname(pctldev), +					pinspec.args[0], +					pinspec.args[1], +					pinspec.args[2]); +			if (ret) +				break; +		} else { +			/* npins == 0: special range */ +			if (pinspec.args[1]) { +				pr_err("%s: Illegal gpio-range format.\n", +					np->full_name); +				break; +			} + +			if (!group_names) { +				pr_err("%s: GPIO group range requested but no %s property.\n", +					np->full_name, group_names_propname); +				break; +			} + +			ret = of_property_read_string_index(np, +						group_names_propname, +						index, &name); +			if (ret) +				break; + +			if (!strlen(name)) { +				pr_err("%s: Group name of GPIO group range cannot be the empty string.\n", +				np->full_name); +				break; +			} + +			ret = gpiochip_add_pingroup_range(chip, pctldev, +						pinspec.args[0], name); +			if (ret) +				break; +		}  	}  }  | 
