diff options
| -rw-r--r-- | drivers/gpio/gpio-stmpe.c | 6 | ||||
| -rw-r--r-- | drivers/gpio/gpio-wm831x.c | 14 | ||||
| -rw-r--r-- | drivers/gpio/gpio-wm8994.c | 13 | ||||
| -rw-r--r-- | drivers/gpio/gpiolib.c | 35 | ||||
| -rw-r--r-- | drivers/pinctrl/intel/pinctrl-baytrail.c | 11 | ||||
| -rw-r--r-- | drivers/pinctrl/nomadik/pinctrl-abx500.c | 9 | ||||
| -rw-r--r-- | drivers/pinctrl/nomadik/pinctrl-nomadik.c | 6 | ||||
| -rw-r--r-- | drivers/pinctrl/sunplus/sppctl.c | 10 | ||||
| -rw-r--r-- | include/linux/gpio/driver.h | 39 | 
9 files changed, 96 insertions, 47 deletions
| diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 27cc4da53565..6c5ee81d71b3 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -5,6 +5,7 @@   * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson   */ +#include <linux/cleanup.h>  #include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/slab.h> @@ -255,7 +256,6 @@ static void stmpe_dbg_show_one(struct seq_file *s,  {  	struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);  	struct stmpe *stmpe = stmpe_gpio->stmpe; -	const char *label = gpiochip_is_requested(gc, offset);  	bool val = !!stmpe_gpio_get(gc, offset);  	u8 bank = offset / 8;  	u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB + bank]; @@ -263,6 +263,10 @@ static void stmpe_dbg_show_one(struct seq_file *s,  	int ret;  	u8 dir; +	char *label __free(kfree) = gpiochip_dup_line_label(gc, offset); +	if (IS_ERR(label)) +		return; +  	ret = stmpe_reg_read(stmpe, dir_reg);  	if (ret < 0)  		return; diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index 7eaf8a28638c..f7d5120ff8f1 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -8,6 +8,7 @@   *   */ +#include <linux/cleanup.h>  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/module.h> @@ -160,18 +161,21 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)  	for (i = 0; i < chip->ngpio; i++) {  		int gpio = i + chip->base;  		int reg; -		const char *label, *pull, *powerdomain; +		const char *pull, *powerdomain;  		/* We report the GPIO even if it's not requested since  		 * we're also reporting things like alternate  		 * functions which apply even when the GPIO is not in  		 * use as a GPIO.  		 */ -		label = gpiochip_is_requested(chip, i); -		if (!label) -			label = "Unrequested"; +		char *label __free(kfree) = gpiochip_dup_line_label(chip, i); +		if (IS_ERR(label)) { +			dev_err(wm831x->dev, "Failed to duplicate label\n"); +			continue; +		} -		seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, label); +		seq_printf(s, " gpio-%-3d (%-20.20s) ", +			   gpio, label ?: "Unrequested");  		reg = wm831x_reg_read(wm831x, WM831X_GPIO1_CONTROL + i);  		if (reg < 0) { diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index f4a474cef32d..bf05c9b5882b 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -8,6 +8,7 @@   *   */ +#include <linux/cleanup.h>  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/module.h> @@ -193,18 +194,20 @@ static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)  	for (i = 0; i < chip->ngpio; i++) {  		int gpio = i + chip->base;  		int reg; -		const char *label;  		/* We report the GPIO even if it's not requested since  		 * we're also reporting things like alternate  		 * functions which apply even when the GPIO is not in  		 * use as a GPIO.  		 */ -		label = gpiochip_is_requested(chip, i); -		if (!label) -			label = "Unrequested"; +		char *label __free(kfree) = gpiochip_dup_line_label(chip, i); +		if (IS_ERR(label)) { +			dev_err(wm8994->dev, "Failed to duplicate label\n"); +			continue; +		} -		seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, label); +		seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, +			   label ?: "Unrequested");  		reg = wm8994_reg_read(wm8994, WM8994_GPIO_1 + i);  		if (reg < 0) { diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index a5faaea6915d..4e190be75dc2 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1085,7 +1085,7 @@ void gpiochip_remove(struct gpio_chip *gc)  	spin_lock_irqsave(&gpio_lock, flags);  	for (i = 0; i < gdev->ngpio; i++) { -		if (gpiochip_is_requested(gc, i)) +		if (test_bit(FLAG_REQUESTED, &gdev->descs[i].flags))  			break;  	}  	spin_unlock_irqrestore(&gpio_lock, flags); @@ -2374,31 +2374,38 @@ void gpiod_free(struct gpio_desc *desc)  }  /** - * gpiochip_is_requested - return string iff signal was requested - * @gc: controller managing the signal - * @offset: of signal within controller's 0..(ngpio - 1) range + * gpiochip_dup_line_label - Get a copy of the consumer label. + * @gc: GPIO chip controlling this line. + * @offset: Hardware offset of the line.   * - * Returns NULL if the GPIO is not currently requested, else a string. - * The string returned is the label passed to gpio_request(); if none has been - * passed it is a meaningless, non-NULL constant. + * Returns: + * Pointer to a copy of the consumer label if the line is requested or NULL + * if it's not. If a valid pointer was returned, it must be freed using + * kfree(). In case of a memory allocation error, the function returns %ENOMEM.   * - * This function is for use by GPIO controller drivers.  The label can - * help with diagnostics, and knowing that the signal is used as a GPIO - * can help avoid accidentally multiplexing it to another controller. + * Must not be called from atomic context.   */ -const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset) +char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset)  {  	struct gpio_desc *desc; +	char *label;  	desc = gpiochip_get_desc(gc, offset);  	if (IS_ERR(desc))  		return NULL; -	if (test_bit(FLAG_REQUESTED, &desc->flags) == 0) +	guard(spinlock_irqsave)(&gpio_lock); + +	if (!test_bit(FLAG_REQUESTED, &desc->flags))  		return NULL; -	return desc->label; + +	label = kstrdup(desc->label, GFP_KERNEL); +	if (!label) +		return ERR_PTR(-ENOMEM); + +	return label;  } -EXPORT_SYMBOL_GPL(gpiochip_is_requested); +EXPORT_SYMBOL_GPL(gpiochip_dup_line_label);  /**   * gpiochip_request_own_desc - Allow GPIO chip to request its own descriptor diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 3cd0798ee631..3c8c02043481 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -9,6 +9,7 @@  #include <linux/acpi.h>  #include <linux/array_size.h>  #include <linux/bitops.h> +#include <linux/cleanup.h>  #include <linux/gpio/driver.h>  #include <linux/init.h>  #include <linux/interrupt.h> @@ -1173,7 +1174,6 @@ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)  		const char *pull_str = NULL;  		const char *pull = NULL;  		unsigned long flags; -		const char *label;  		unsigned int pin;  		pin = vg->soc->pins[i].number; @@ -1200,9 +1200,10 @@ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)  			seq_printf(s, "Pin %i: can't retrieve community\n", pin);  			continue;  		} -		label = gpiochip_is_requested(chip, i); -		if (!label) -			label = "Unrequested"; + +		char *label __free(kfree) = gpiochip_dup_line_label(chip, i); +		if (IS_ERR(label)) +			continue;  		switch (conf0 & BYT_PULL_ASSIGN_MASK) {  		case BYT_PULL_ASSIGN_UP: @@ -1231,7 +1232,7 @@ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)  		seq_printf(s,  			   " gpio-%-3d (%-20.20s) %s %s %s pad-%-3d offset:0x%03x mux:%d %s%s%s",  			   pin, -			   label, +			   label ?: "Unrequested",  			   val & BYT_INPUT_EN ? "  " : "in",  			   val & BYT_OUTPUT_EN ? "   " : "out",  			   str_hi_lo(val & BYT_LEVEL), diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index d3c32d809bac..80e3ac333136 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -6,7 +6,9 @@   *   * Driver allows to use AxB5xx unused pins to be used as GPIO   */ +  #include <linux/bitops.h> +#include <linux/cleanup.h>  #include <linux/err.h>  #include <linux/gpio/driver.h>  #include <linux/init.h> @@ -453,12 +455,11 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s,  				     unsigned offset, unsigned gpio)  {  	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); -	const char *label = gpiochip_is_requested(chip, offset - 1);  	u8 gpio_offset = offset - 1;  	int mode = -1;  	bool is_out;  	bool pd; -	int ret; +	int ret = -ENOMEM;  	const char *modes[] = {  		[ABX500_DEFAULT]	= "default", @@ -474,6 +475,10 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s,  		[ABX500_GPIO_PULL_UP]		= "pull up",  	}; +	char *label __free(kfree) = gpiochip_dup_line_label(chip, offset - 1); +	if (IS_ERR(label)) +		goto out; +  	ret = abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG,  			gpio_offset, &is_out);  	if (ret < 0) diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 863732287b1e..7911353ac97d 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -8,6 +8,7 @@   * Copyright (C) 2011-2013 Linus Walleij <linus.walleij@linaro.org>   */  #include <linux/bitops.h> +#include <linux/cleanup.h>  #include <linux/clk.h>  #include <linux/device.h>  #include <linux/err.h> @@ -917,7 +918,6 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s,  	struct pinctrl_dev *pctldev, struct gpio_chip *chip,  	unsigned offset, unsigned gpio)  { -	const char *label = gpiochip_is_requested(chip, offset);  	struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip);  	int mode;  	bool is_out; @@ -934,6 +934,10 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s,  		[NMK_GPIO_ALT_C+4]	= "altC4",  	}; +	char *label = gpiochip_dup_line_label(chip, offset); +	if (IS_ERR(label)) +		return; +  	clk_enable(nmk_chip->clk);  	is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & BIT(offset));  	pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & BIT(offset)); diff --git a/drivers/pinctrl/sunplus/sppctl.c b/drivers/pinctrl/sunplus/sppctl.c index bb5ef391dbe4..ae156f779a16 100644 --- a/drivers/pinctrl/sunplus/sppctl.c +++ b/drivers/pinctrl/sunplus/sppctl.c @@ -4,6 +4,7 @@   * Copyright (C) Sunplus Tech / Tibbo Tech.   */ +#include <linux/cleanup.h>  #include <linux/bitfield.h>  #include <linux/device.h>  #include <linux/err.h> @@ -500,16 +501,15 @@ static int sppctl_gpio_set_config(struct gpio_chip *chip, unsigned int offset,  static void sppctl_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)  { -	const char *label;  	int i;  	for (i = 0; i < chip->ngpio; i++) { -		label = gpiochip_is_requested(chip, i); -		if (!label) -			label = ""; +		char *label __free(kfree) = gpiochip_dup_line_label(chip, i); +		if (IS_ERR(label)) +			continue;  		seq_printf(s, " gpio-%03d (%-16.16s | %-16.16s)", i + chip->base, -			   chip->names[i], label); +			   chip->names[i], label ?: "");  		seq_printf(s, " %c", sppctl_gpio_get_direction(chip, i) ? 'I' : 'O');  		seq_printf(s, ":%d", sppctl_gpio_get(chip, i));  		seq_printf(s, " %s", sppctl_first_get(chip, i) ? "gpi" : "mux"); diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 100c329dc986..bd9bea7cb270 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -531,19 +531,40 @@ struct gpio_chip {  #endif /* CONFIG_OF_GPIO */  }; -const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset); +char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset); + + +struct _gpiochip_for_each_data { +	const char **label; +	unsigned int *i; +}; + +DEFINE_CLASS(_gpiochip_for_each_data, +	     struct _gpiochip_for_each_data, +	     if (*_T.label) kfree(*_T.label), +	     ({ +		struct _gpiochip_for_each_data _data = { label, i }; +		*_data.i = 0; +		_data; +	     }), +	     const char **label, int *i)  /**   * for_each_requested_gpio_in_range - iterates over requested GPIOs in a given range - * @chip:	the chip to query - * @i:		loop variable - * @base:	first GPIO in the range - * @size:	amount of GPIOs to check starting from @base - * @label:	label of current GPIO + * @_chip:	the chip to query + * @_i:		loop variable + * @_base:	first GPIO in the range + * @_size:	amount of GPIOs to check starting from @base + * @_label:	label of current GPIO   */ -#define for_each_requested_gpio_in_range(chip, i, base, size, label)			\ -	for (i = 0; i < size; i++)							\ -		if ((label = gpiochip_is_requested(chip, base + i)) == NULL) {} else +#define for_each_requested_gpio_in_range(_chip, _i, _base, _size, _label)		\ +	for (CLASS(_gpiochip_for_each_data, _data)(&_label, &_i);			\ +	     *_data.i < _size;								\ +	     (*_data.i)++, kfree(*(_data.label)), *_data.label = NULL)			\ +		if ((*_data.label =							\ +			gpiochip_dup_line_label(_chip, _base + *_data.i)) == NULL) {}	\ +		else if (IS_ERR(*_data.label)) {}					\ +		else  /* Iterates over all requested GPIO of the given @chip */  #define for_each_requested_gpio(chip, i, label)						\ | 
