diff options
Diffstat (limited to 'drivers/gpio/gpiolib.c')
| -rw-r--r-- | drivers/gpio/gpiolib.c | 255 | 
1 files changed, 139 insertions, 116 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 85f772c0b26a..50c4922fe53a 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -10,12 +10,13 @@  #include <linux/seq_file.h>  #include <linux/gpio.h>  #include <linux/of_gpio.h> -#include <linux/acpi_gpio.h>  #include <linux/idr.h>  #include <linux/slab.h>  #include <linux/acpi.h>  #include <linux/gpio/driver.h> +#include "gpiolib.h" +  #define CREATE_TRACE_POINTS  #include <trace/events/gpio.h> @@ -84,40 +85,57 @@ static DEFINE_IDR(dirent_idr);  static int gpiod_request(struct gpio_desc *desc, const char *label);  static void gpiod_free(struct gpio_desc *desc); +/* With descriptor prefix */ +  #ifdef CONFIG_DEBUG_FS -#define gpiod_emerg(desc, fmt, ...)			                \ -	pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ +#define gpiod_emerg(desc, fmt, ...)					       \ +	pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\                   ##__VA_ARGS__) -#define gpiod_crit(desc, fmt, ...)			                \ -	pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label,  \ +#define gpiod_crit(desc, fmt, ...)					       \ +	pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \                   ##__VA_ARGS__) -#define gpiod_err(desc, fmt, ...)				        \ -	pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label,   \ +#define gpiod_err(desc, fmt, ...)					       \ +	pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",  \                   ##__VA_ARGS__) -#define gpiod_warn(desc, fmt, ...)				        \ -	pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label,  \ +#define gpiod_warn(desc, fmt, ...)					       \ +	pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \                   ##__VA_ARGS__) -#define gpiod_info(desc, fmt, ...)				        \ -	pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label,  \ +#define gpiod_info(desc, fmt, ...)					       \ +	pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \                  ##__VA_ARGS__) -#define gpiod_dbg(desc, fmt, ...)				   \ -	pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ +#define gpiod_dbg(desc, fmt, ...)					       \ +	pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\                   ##__VA_ARGS__)  #else -#define gpiod_emerg(desc, fmt, ...)			           \ +#define gpiod_emerg(desc, fmt, ...)					\  	pr_emerg("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_crit(desc, fmt, ...)			           \ +#define gpiod_crit(desc, fmt, ...)					\  	pr_crit("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_err(desc, fmt, ...)				   \ +#define gpiod_err(desc, fmt, ...)					\  	pr_err("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_warn(desc, fmt, ...)				   \ +#define gpiod_warn(desc, fmt, ...)					\  	pr_warn("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_info(desc, fmt, ...)				   \ +#define gpiod_info(desc, fmt, ...)					\  	pr_info("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) -#define gpiod_dbg(desc, fmt, ...)				   \ +#define gpiod_dbg(desc, fmt, ...)					\  	pr_debug("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)  #endif +/* With chip prefix */ + +#define chip_emerg(chip, fmt, ...)					\ +	pr_emerg("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_crit(chip, fmt, ...)					\ +	pr_crit("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_err(chip, fmt, ...)					\ +	pr_err("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_warn(chip, fmt, ...)					\ +	pr_warn("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_info(chip, fmt, ...)					\ +	pr_info("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +#define chip_dbg(chip, fmt, ...)					\ +	pr_debug("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__) +  static inline void desc_set_label(struct gpio_desc *d, const char *label)  {  #ifdef CONFIG_DEBUG_FS @@ -151,9 +169,10 @@ EXPORT_SYMBOL_GPL(gpio_to_desc);  static struct gpio_desc *gpiochip_offset_to_desc(struct gpio_chip *chip,  						 unsigned int offset)  { -	unsigned int gpio = chip->base + offset; +	if (offset >= chip->ngpio) +		return ERR_PTR(-EINVAL); -	return gpio_to_desc(gpio); +	return &chip->desc[offset];  }  /** @@ -187,7 +206,8 @@ static int gpio_ensure_requested(struct gpio_desc *desc)  	if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0,  			"autorequest GPIO-%d\n", gpio)) {  		if (!try_module_get(chip->owner)) { -			pr_err("GPIO-%d: module can't be gotten \n", gpio); +			gpiod_err(desc, "%s: module can't be gotten\n", +					__func__);  			clear_bit(FLAG_REQUESTED, &desc->flags);  			/* lose */  			return -EIO; @@ -393,7 +413,7 @@ static const DEVICE_ATTR(value, 0644,  static irqreturn_t gpio_sysfs_irq(int irq, void *priv)  { -	struct sysfs_dirent	*value_sd = priv; +	struct kernfs_node	*value_sd = priv;  	sysfs_notify_dirent(value_sd);  	return IRQ_HANDLED; @@ -402,7 +422,7 @@ static irqreturn_t gpio_sysfs_irq(int irq, void *priv)  static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,  		unsigned long gpio_flags)  { -	struct sysfs_dirent	*value_sd; +	struct kernfs_node	*value_sd;  	unsigned long		irq_flags;  	int			ret, irq, id; @@ -808,8 +828,8 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)  	if (!test_bit(FLAG_REQUESTED, &desc->flags) ||  	     test_bit(FLAG_EXPORT, &desc->flags)) {  		spin_unlock_irqrestore(&gpio_lock, flags); -		pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n", -				__func__, desc_to_gpio(desc), +		gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n", +				__func__,  				test_bit(FLAG_REQUESTED, &desc->flags),  				test_bit(FLAG_EXPORT, &desc->flags));  		status = -EPERM; @@ -857,8 +877,7 @@ fail_unregister_device:  	device_unregister(dev);  fail_unlock:  	mutex_unlock(&sysfs_lock); -	pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), -		 status); +	gpiod_dbg(desc, "%s: status %d\n", __func__, status);  	return status;  }  EXPORT_SYMBOL_GPL(gpiod_export); @@ -906,8 +925,7 @@ int gpiod_export_link(struct device *dev, const char *name,  	mutex_unlock(&sysfs_lock);  	if (status) -		pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), -			 status); +		gpiod_dbg(desc, "%s: status %d\n", __func__, status);  	return status;  } @@ -951,8 +969,7 @@ unlock:  	mutex_unlock(&sysfs_lock);  	if (status) -		pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), -			 status); +		gpiod_dbg(desc, "%s: status %d\n", __func__, status);  	return status;  } @@ -994,8 +1011,7 @@ void gpiod_unexport(struct gpio_desc *desc)  	}  	if (status) -		pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), -			 status); +		gpiod_dbg(desc, "%s: status %d\n", __func__, status);  }  EXPORT_SYMBOL_GPL(gpiod_unexport); @@ -1034,8 +1050,7 @@ static int gpiochip_export(struct gpio_chip *chip)  			chip->desc[gpio++].chip = NULL;  		spin_unlock_irqrestore(&gpio_lock, flags); -		pr_debug("%s: chip %s status %d\n", __func__, -				chip->label, status); +		chip_dbg(chip, "%s: status %d\n", __func__, status);  	}  	return status; @@ -1051,15 +1066,14 @@ static void gpiochip_unexport(struct gpio_chip *chip)  	if (dev) {  		put_device(dev);  		device_unregister(dev); -		chip->exported = 0; +		chip->exported = false;  		status = 0;  	} else  		status = -ENODEV;  	mutex_unlock(&sysfs_lock);  	if (status) -		pr_debug("%s: chip %s status %d\n", __func__, -				chip->label, status); +		chip_dbg(chip, "%s: status %d\n", __func__, status);  }  static int __init gpiolib_sysfs_init(void) @@ -1213,6 +1227,7 @@ int gpiochip_add(struct gpio_chip *chip)  #endif  	of_gpiochip_add(chip); +	acpi_gpiochip_add(chip);  	if (status)  		goto fail; @@ -1221,7 +1236,7 @@ int gpiochip_add(struct gpio_chip *chip)  	if (status)  		goto fail; -	pr_debug("gpiochip_add: registered GPIOs %d to %d on device: %s\n", +	pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__,  		chip->base, chip->base + chip->ngpio - 1,  		chip->label ? : "generic"); @@ -1231,7 +1246,7 @@ unlock:  	spin_unlock_irqrestore(&gpio_lock, flags);  fail:  	/* failures here can mean systems won't boot... */ -	pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n", +	pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__,  		chip->base, chip->base + chip->ngpio - 1,  		chip->label ? : "generic");  	return status; @@ -1254,6 +1269,7 @@ int gpiochip_remove(struct gpio_chip *chip)  	gpiochip_remove_pin_ranges(chip);  	of_gpiochip_remove(chip); +	acpi_gpiochip_remove(chip);  	for (id = 0; id < chip->ngpio; id++) {  		if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) { @@ -1339,8 +1355,7 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip,  	pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL);  	if (!pin_range) { -		pr_err("%s: GPIO chip: failed to allocate pin ranges\n", -				chip->label); +		chip_err(chip, "failed to allocate pin ranges\n");  		return -ENOMEM;  	} @@ -1361,9 +1376,8 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip,  	pinctrl_add_gpio_range(pctldev, &pin_range->range); -	pr_debug("GPIO chip %s: created GPIO range %d->%d ==> %s PINGRP %s\n", -		 chip->label, gpio_offset, -		 gpio_offset + pin_range->range.npins - 1, +	chip_dbg(chip, "created GPIO range %d->%d ==> %s PINGRP %s\n", +		 gpio_offset, gpio_offset + pin_range->range.npins - 1,  		 pinctrl_dev_get_devname(pctldev), pin_group);  	list_add_tail(&pin_range->node, &chip->pin_ranges); @@ -1390,8 +1404,7 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,  	pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL);  	if (!pin_range) { -		pr_err("%s: GPIO chip: failed to allocate pin ranges\n", -				chip->label); +		chip_err(chip, "failed to allocate pin ranges\n");  		return -ENOMEM;  	} @@ -1406,13 +1419,12 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,  			&pin_range->range);  	if (IS_ERR(pin_range->pctldev)) {  		ret = PTR_ERR(pin_range->pctldev); -		pr_err("%s: GPIO chip: could not create pin range\n", -		       chip->label); +		chip_err(chip, "could not create pin range\n");  		kfree(pin_range);  		return ret;  	} -	pr_debug("GPIO chip %s: created GPIO range %d->%d ==> %s PIN %d->%d\n", -		 chip->label, gpio_offset, gpio_offset + npins - 1, +	chip_dbg(chip, "created GPIO range %d->%d ==> %s PIN %d->%d\n", +		 gpio_offset, gpio_offset + npins - 1,  		 pinctl_name,  		 pin_offset, pin_offset + npins - 1); @@ -1499,8 +1511,7 @@ static int gpiod_request(struct gpio_desc *desc, const char *label)  	}  done:  	if (status) -		pr_debug("_gpio_request: gpio-%d (%s) status %d\n", -			 desc_to_gpio(desc), label ? : "?", status); +		gpiod_dbg(desc, "%s: status %d\n", __func__, status);  	spin_unlock_irqrestore(&gpio_lock, flags);  	return status;  } @@ -1701,7 +1712,7 @@ int gpiod_direction_input(struct gpio_desc *desc)  	if (!chip->get || !chip->direction_input) {  		gpiod_warn(desc,  			"%s: missing get() or direction_input() operations\n", -			 __func__); +			__func__);  		return -EIO;  	} @@ -1721,7 +1732,8 @@ int gpiod_direction_input(struct gpio_desc *desc)  	if (status) {  		status = chip->request(chip, offset);  		if (status < 0) { -			gpiod_dbg(desc, "chip request fail, %d\n", status); +			gpiod_dbg(desc, "%s: chip request fail, %d\n", +					__func__, status);  			/* and it's not available to anyone else ...  			 * gpio_request() is the fully clean solution.  			 */ @@ -1739,7 +1751,7 @@ lose:  fail:  	spin_unlock_irqrestore(&gpio_lock, flags);  	if (status) -		gpiod_dbg(desc, "%s status %d\n", __func__, status); +		gpiod_dbg(desc, "%s: status %d\n", __func__, status);  	return status;  }  EXPORT_SYMBOL_GPL(gpiod_direction_input); @@ -1806,7 +1818,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)  	if (status) {  		status = chip->request(chip, offset);  		if (status < 0) { -			gpiod_dbg(desc, "chip request fail, %d\n", status); +			gpiod_dbg(desc, "%s: chip request fail, %d\n", +					__func__, status);  			/* and it's not available to anyone else ...  			 * gpio_request() is the fully clean solution.  			 */ @@ -2259,18 +2272,14 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)  EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);  /** - * gpiod_add_table() - register GPIO device consumers - * @table: array of consumers to register - * @num: number of consumers in table + * gpiod_add_lookup_table() - register GPIO device consumers + * @table: table of consumers to register   */ -void gpiod_add_table(struct gpiod_lookup *table, size_t size) +void gpiod_add_lookup_table(struct gpiod_lookup_table *table)  {  	mutex_lock(&gpio_lookup_lock); -	while (size--) { -		list_add_tail(&table->list, &gpio_lookup_list); -		table++; -	} +	list_add_tail(&table->list, &gpio_lookup_list);  	mutex_unlock(&gpio_lookup_lock);  } @@ -2326,76 +2335,92 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,  	return desc;  } -static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, -				    unsigned int idx, -				    enum gpio_lookup_flags *flags) +static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)  {  	const char *dev_id = dev ? dev_name(dev) : NULL; -	struct gpio_desc *desc = ERR_PTR(-ENODEV); -	unsigned int match, best = 0; -	struct gpiod_lookup *p; +	struct gpiod_lookup_table *table;  	mutex_lock(&gpio_lookup_lock); -	list_for_each_entry(p, &gpio_lookup_list, list) { -		match = 0; +	list_for_each_entry(table, &gpio_lookup_list, list) { +		if (table->dev_id && dev_id) { +			/* +			 * Valid strings on both ends, must be identical to have +			 * a match +			 */ +			if (!strcmp(table->dev_id, dev_id)) +				goto found; +		} else { +			/* +			 * One of the pointers is NULL, so both must be to have +			 * a match +			 */ +			if (dev_id == table->dev_id) +				goto found; +		} +	} +	table = NULL; -		if (p->dev_id) { -			if (!dev_id || strcmp(p->dev_id, dev_id)) -				continue; +found: +	mutex_unlock(&gpio_lookup_lock); +	return table; +} -			match += 2; -		} +static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, +				    unsigned int idx, +				    enum gpio_lookup_flags *flags) +{ +	struct gpio_desc *desc = ERR_PTR(-ENOENT); +	struct gpiod_lookup_table *table; +	struct gpiod_lookup *p; -		if (p->con_id) { -			if (!con_id || strcmp(p->con_id, con_id)) -				continue; +	table = gpiod_find_lookup_table(dev); +	if (!table) +		return desc; -			match += 1; -		} +	for (p = &table->table[0]; p->chip_label; p++) { +		struct gpio_chip *chip; +		/* idx must always match exactly */  		if (p->idx != idx)  			continue; -		if (match > best) { -			struct gpio_chip *chip; +		/* If the lookup entry has a con_id, require exact match */ +		if (p->con_id && (!con_id || strcmp(p->con_id, con_id))) +			continue; -			chip = find_chip_by_name(p->chip_label); +		chip = find_chip_by_name(p->chip_label); -			if (!chip) { -				dev_warn(dev, "cannot find GPIO chip %s\n", -					 p->chip_label); -				continue; -			} +		if (!chip) { +			dev_err(dev, "cannot find GPIO chip %s\n", +				p->chip_label); +			return ERR_PTR(-ENODEV); +		} -			if (chip->ngpio <= p->chip_hwnum) { -				dev_warn(dev, "GPIO chip %s has %d GPIOs\n", -					 chip->label, chip->ngpio); -				continue; -			} +		if (chip->ngpio <= p->chip_hwnum) { +			dev_err(dev, +				"requested GPIO %d is out of range [0..%d] for chip %s\n", +				idx, chip->ngpio, chip->label); +			return ERR_PTR(-EINVAL); +		} -			desc = gpio_to_desc(chip->base + p->chip_hwnum); -			*flags = p->flags; +		desc = gpiochip_offset_to_desc(chip, p->chip_hwnum); +		*flags = p->flags; -			if (match != 3) -				best = match; -			else -				break; -		} +		return desc;  	} -	mutex_unlock(&gpio_lookup_lock); -  	return desc;  }  /**   * gpio_get - obtain a GPIO for a given GPIO function - * @dev:	GPIO consumer + * @dev:	GPIO consumer, can be NULL for system-global GPIOs   * @con_id:	function within the GPIO consumer   *   * Return the GPIO descriptor corresponding to the function con_id of device - * dev, or an IS_ERR() condition if an error occured. + * dev, -ENOENT if no GPIO has been assigned to the requested function, or + * another IS_ERR() code if an error occured while trying to acquire the GPIO.   */  struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id)  { @@ -2405,14 +2430,16 @@ EXPORT_SYMBOL_GPL(gpiod_get);  /**   * gpiod_get_index - obtain a GPIO from a multi-index GPIO function - * @dev:	GPIO consumer + * @dev:	GPIO consumer, can be NULL for system-global GPIOs   * @con_id:	function within the GPIO consumer   * @idx:	index of the GPIO to obtain in the consumer   *   * This variant of gpiod_get() allows to access GPIOs other than the first   * defined one for functions that define several GPIOs.   * - * Return a valid GPIO descriptor, or an IS_ERR() condition in case of error. + * Return a valid GPIO descriptor, -ENOENT if no GPIO has been assigned to the + * requested function and/or index, or another IS_ERR() code if an error + * occured while trying to acquire the GPIO.   */  struct gpio_desc *__must_check gpiod_get_index(struct device *dev,  					       const char *con_id, @@ -2437,13 +2464,9 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,  	 * Either we are not using DT or ACPI, or their lookup did not return  	 * a result. In that case, use platform lookup as a fallback.  	 */ -	if (!desc || IS_ERR(desc)) { -		struct gpio_desc *pdesc; +	if (!desc || desc == ERR_PTR(-ENOENT)) {  		dev_dbg(dev, "using lookup tables for GPIO lookup"); -		pdesc = gpiod_find(dev, con_id, idx, &flags); -		/* If used as fallback, do not replace the previous error */ -		if (!IS_ERR(pdesc) || !desc) -			desc = pdesc; +		desc = gpiod_find(dev, con_id, idx, &flags);  	}  	if (IS_ERR(desc)) {  |