diff options
Diffstat (limited to 'drivers/gpio/gpiolib.c')
| -rw-r--r-- | drivers/gpio/gpiolib.c | 295 | 
1 files changed, 155 insertions, 140 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index a70522aef355..939c776b9488 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -26,6 +26,7 @@  #include "gpiolib.h"  #include "gpiolib-of.h"  #include "gpiolib-acpi.h" +#include "gpiolib-swnode.h"  #include "gpiolib-cdev.h"  #include "gpiolib-sysfs.h" @@ -183,14 +184,14 @@ EXPORT_SYMBOL_GPL(gpiod_to_chip);  static int gpiochip_find_base(int ngpio)  {  	struct gpio_device *gdev; -	int base = ARCH_NR_GPIOS - ngpio; +	int base = GPIO_DYNAMIC_BASE; -	list_for_each_entry_reverse(gdev, &gpio_devices, list) { +	list_for_each_entry(gdev, &gpio_devices, list) {  		/* found a free space? */ -		if (gdev->base + gdev->ngpio <= base) +		if (gdev->base >= base + ngpio)  			break; -		/* nope, check the space right before the chip */ -		base = gdev->base - ngpio; +		/* nope, check the space right after the chip */ +		base = gdev->base + gdev->ngpio;  	}  	if (gpio_is_valid(base)) { @@ -366,12 +367,12 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)  static int devprop_gpiochip_set_names(struct gpio_chip *chip)  {  	struct gpio_device *gdev = chip->gpiodev; -	struct fwnode_handle *fwnode = dev_fwnode(&gdev->dev); +	struct device *dev = &gdev->dev;  	const char **names;  	int ret, i;  	int count; -	count = fwnode_property_string_array_count(fwnode, "gpio-line-names"); +	count = device_property_string_array_count(dev, "gpio-line-names");  	if (count < 0)  		return 0; @@ -384,7 +385,7 @@ static int devprop_gpiochip_set_names(struct gpio_chip *chip)  	 * gpiochips.  	 */  	if (count <= chip->offset) { -		dev_warn(&gdev->dev, "gpio-line-names too short (length %d), cannot map names for the gpiochip at offset %u\n", +		dev_warn(dev, "gpio-line-names too short (length %d), cannot map names for the gpiochip at offset %u\n",  			 count, chip->offset);  		return 0;  	} @@ -393,10 +394,10 @@ static int devprop_gpiochip_set_names(struct gpio_chip *chip)  	if (!names)  		return -ENOMEM; -	ret = fwnode_property_read_string_array(fwnode, "gpio-line-names", +	ret = device_property_read_string_array(dev, "gpio-line-names",  						names, count);  	if (ret < 0) { -		dev_warn(&gdev->dev, "failed to read GPIO line names\n"); +		dev_warn(dev, "failed to read GPIO line names\n");  		kfree(names);  		return ret;  	} @@ -445,9 +446,22 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *gc)  	return p;  } +static unsigned int gpiochip_count_reserved_ranges(struct gpio_chip *gc) +{ +	struct device *dev = &gc->gpiodev->dev; +	int size; + +	/* Format is "start, count, ..." */ +	size = device_property_count_u32(dev, "gpio-reserved-ranges"); +	if (size > 0 && size % 2 == 0) +		return size; + +	return 0; +} +  static int gpiochip_alloc_valid_mask(struct gpio_chip *gc)  { -	if (!(of_gpio_need_valid_mask(gc) || gc->init_valid_mask)) +	if (!(gpiochip_count_reserved_ranges(gc) || gc->init_valid_mask))  		return 0;  	gc->valid_mask = gpiochip_allocate_mask(gc); @@ -457,8 +471,50 @@ static int gpiochip_alloc_valid_mask(struct gpio_chip *gc)  	return 0;  } +static int gpiochip_apply_reserved_ranges(struct gpio_chip *gc) +{ +	struct device *dev = &gc->gpiodev->dev; +	unsigned int size; +	u32 *ranges; +	int ret; + +	size = gpiochip_count_reserved_ranges(gc); +	if (size == 0) +		return 0; + +	ranges = kmalloc_array(size, sizeof(*ranges), GFP_KERNEL); +	if (!ranges) +		return -ENOMEM; + +	ret = device_property_read_u32_array(dev, "gpio-reserved-ranges", +					     ranges, size); +	if (ret) { +		kfree(ranges); +		return ret; +	} + +	while (size) { +		u32 count = ranges[--size]; +		u32 start = ranges[--size]; + +		if (start >= gc->ngpio || start + count > gc->ngpio) +			continue; + +		bitmap_clear(gc->valid_mask, start, count); +	} + +	kfree(ranges); +	return 0; +} +  static int gpiochip_init_valid_mask(struct gpio_chip *gc)  { +	int ret; + +	ret = gpiochip_apply_reserved_ranges(gc); +	if (ret) +		return ret; +  	if (gc->init_valid_mask)  		return gc->init_valid_mask(gc,  					   gc->valid_mask, @@ -493,7 +549,7 @@ EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);  static void gpiodevice_release(struct device *dev)  { -	struct gpio_device *gdev = container_of(dev, struct gpio_device, dev); +	struct gpio_device *gdev = to_gpio_device(dev);  	unsigned long flags;  	spin_lock_irqsave(&gpio_lock, flags); @@ -627,7 +683,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,  	 * Assign fwnode depending on the result of the previous calls,  	 * if none of them succeed, assign it to the parent's one.  	 */ -	gdev->dev.fwnode = dev_fwnode(&gdev->dev) ?: fwnode; +	gc->fwnode = gdev->dev.fwnode = dev_fwnode(&gdev->dev) ?: fwnode;  	gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL);  	if (gdev->id < 0) { @@ -719,6 +775,9 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,  		 * a poison instead.  		 */  		gc->base = base; +	} else { +		dev_warn(&gdev->dev, +			 "Static allocation of GPIO base is deprecated, use dynamic allocation.\n");  	}  	gdev->base = base; @@ -735,6 +794,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,  	spin_unlock_irqrestore(&gpio_lock, flags);  	BLOCKING_INIT_NOTIFIER_HEAD(&gdev->notifier); +	init_rwsem(&gdev->sem);  #ifdef CONFIG_PINCTRL  	INIT_LIST_HEAD(&gdev->pin_ranges); @@ -875,6 +935,8 @@ void gpiochip_remove(struct gpio_chip *gc)  	unsigned long	flags;  	unsigned int	i; +	down_write(&gdev->sem); +  	/* FIXME: should the legacy sysfs handling be moved to gpio_device? */  	gpiochip_sysfs_unregister(gdev);  	gpiochip_free_hogs(gc); @@ -909,6 +971,7 @@ void gpiochip_remove(struct gpio_chip *gc)  	 * gone.  	 */  	gcdev_unregister(gdev); +	up_write(&gdev->sem);  	put_device(&gdev->dev);  }  EXPORT_SYMBOL_GPL(gpiochip_remove); @@ -3808,62 +3871,88 @@ static int platform_gpio_count(struct device *dev, const char *con_id)  	return count;  } -/** - * fwnode_get_named_gpiod - obtain a GPIO from firmware node - * @fwnode:	handle of the firmware node - * @propname:	name of the firmware property representing the GPIO - * @index:	index of the GPIO to obtain for the consumer - * @dflags:	GPIO initialization flags - * @label:	label to attach to the requested GPIO - * - * This function can be used for drivers that get their configuration - * from opaque firmware. - * - * The function properly finds the corresponding GPIO using whatever is the - * underlying firmware interface and then makes sure that the GPIO - * descriptor is requested before it is returned to the caller. - * - * Returns: - * On successful request the GPIO pin is configured in accordance with - * provided @dflags. - * - * In case of error an ERR_PTR() is returned. - */ -static struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, -						const char *propname, int index, -						enum gpiod_flags dflags, -						const char *label) +static struct gpio_desc *gpiod_find_by_fwnode(struct fwnode_handle *fwnode, +					      struct device *consumer, +					      const char *con_id, +					      unsigned int idx, +					      enum gpiod_flags *flags, +					      unsigned long *lookupflags)  { -	unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT; -	struct gpio_desc *desc = ERR_PTR(-ENODEV); -	int ret; +	struct gpio_desc *desc = ERR_PTR(-ENOENT);  	if (is_of_node(fwnode)) { -		desc = gpiod_get_from_of_node(to_of_node(fwnode), -					      propname, index, -					      dflags, -					      label); -		return desc; +		dev_dbg(consumer, "using DT '%pfw' for '%s' GPIO lookup\n", +			fwnode, con_id); +		desc = of_find_gpio(to_of_node(fwnode), con_id, idx, lookupflags);  	} else if (is_acpi_node(fwnode)) { -		struct acpi_gpio_info info; +		dev_dbg(consumer, "using ACPI '%pfw' for '%s' GPIO lookup\n", +			fwnode, con_id); +		desc = acpi_find_gpio(fwnode, con_id, idx, flags, lookupflags); +	} else if (is_software_node(fwnode)) { +		dev_dbg(consumer, "using swnode '%pfw' for '%s' GPIO lookup\n", +			fwnode, con_id); +		desc = swnode_find_gpio(fwnode, con_id, idx, lookupflags); +	} + +	return desc; +} -		desc = acpi_node_get_gpiod(fwnode, propname, index, &info); -		if (IS_ERR(desc)) -			return desc; +static struct gpio_desc *gpiod_find_and_request(struct device *consumer, +						struct fwnode_handle *fwnode, +						const char *con_id, +						unsigned int idx, +						enum gpiod_flags flags, +						const char *label, +						bool platform_lookup_allowed) +{ +	unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT; +	struct gpio_desc *desc = ERR_PTR(-ENOENT); +	int ret; -		acpi_gpio_update_gpiod_flags(&dflags, &info); -		acpi_gpio_update_gpiod_lookup_flags(&lflags, &info); -	} else { -		return ERR_PTR(-EINVAL); +	if (!IS_ERR_OR_NULL(fwnode)) +		desc = gpiod_find_by_fwnode(fwnode, consumer, con_id, idx, +					    &flags, &lookupflags); + +	if (gpiod_not_found(desc) && platform_lookup_allowed) { +		/* +		 * 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. +		 */ +		dev_dbg(consumer, "using lookup tables for GPIO lookup\n"); +		desc = gpiod_find(consumer, con_id, idx, &lookupflags);  	} -	/* Currently only ACPI takes this path */ +	if (IS_ERR(desc)) { +		dev_dbg(consumer, "No GPIO consumer %s found\n", con_id); +		return desc; +	} + +	/* +	 * If a connection label was passed use that, else attempt to use +	 * the device name as label +	 */  	ret = gpiod_request(desc, label); -	if (ret) -		return ERR_PTR(ret); +	if (ret) { +		if (!(ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE)) +			return ERR_PTR(ret); -	ret = gpiod_configure_flags(desc, propname, lflags, dflags); +		/* +		 * This happens when there are several consumers for +		 * the same GPIO line: we just return here without +		 * further initialization. It is a bit of a hack. +		 * This is necessary to support fixed regulators. +		 * +		 * FIXME: Make this more sane and safe. +		 */ +		dev_info(consumer, +			 "nonexclusive access to GPIO for %s\n", con_id); +		return desc; +	} + +	ret = gpiod_configure_flags(desc, con_id, lookupflags, flags);  	if (ret < 0) { +		dev_dbg(consumer, "setup of GPIO %s failed\n", con_id);  		gpiod_put(desc);  		return ERR_PTR(ret);  	} @@ -3896,29 +3985,12 @@ static struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,   * In case of error an ERR_PTR() is returned.   */  struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode, -					 const char *con_id, int index, +					 const char *con_id, +					 int index,  					 enum gpiod_flags flags,  					 const char *label)  { -	struct gpio_desc *desc; -	char prop_name[32]; /* 32 is max size of property name */ -	unsigned int i; - -	for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { -		if (con_id) -			snprintf(prop_name, sizeof(prop_name), "%s-%s", -					    con_id, gpio_suffixes[i]); -		else -			snprintf(prop_name, sizeof(prop_name), "%s", -					    gpio_suffixes[i]); - -		desc = fwnode_get_named_gpiod(fwnode, prop_name, index, flags, -					      label); -		if (!gpiod_not_found(desc)) -			break; -	} - -	return desc; +	return gpiod_find_and_request(NULL, fwnode, con_id, index, flags, label, false);  }  EXPORT_SYMBOL_GPL(fwnode_gpiod_get_index); @@ -3937,6 +4009,8 @@ int gpiod_count(struct device *dev, const char *con_id)  		count = of_gpio_get_count(dev, con_id);  	else if (is_acpi_node(fwnode))  		count = acpi_gpio_count(dev, con_id); +	else if (is_software_node(fwnode)) +		count = swnode_gpio_count(fwnode, con_id);  	if (count < 0)  		count = platform_gpio_count(dev, con_id); @@ -4072,70 +4146,11 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,  					       unsigned int idx,  					       enum gpiod_flags flags)  { -	unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT; -	struct gpio_desc *desc = NULL; -	int ret; -	/* Maybe we have a device name, maybe not */ +	struct fwnode_handle *fwnode = dev ? dev_fwnode(dev) : NULL;  	const char *devname = dev ? dev_name(dev) : "?"; -	const struct fwnode_handle *fwnode = dev ? dev_fwnode(dev) : NULL; +	const char *label = con_id ?: devname; -	dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id); - -	/* Using device tree? */ -	if (is_of_node(fwnode)) { -		dev_dbg(dev, "using device tree for GPIO lookup\n"); -		desc = of_find_gpio(dev, con_id, idx, &lookupflags); -	} else if (is_acpi_node(fwnode)) { -		dev_dbg(dev, "using ACPI for GPIO lookup\n"); -		desc = acpi_find_gpio(dev, con_id, idx, &flags, &lookupflags); -	} - -	/* -	 * 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 || gpiod_not_found(desc)) { -		dev_dbg(dev, "using lookup tables for GPIO lookup\n"); -		desc = gpiod_find(dev, con_id, idx, &lookupflags); -	} - -	if (IS_ERR(desc)) { -		dev_dbg(dev, "No GPIO consumer %s found\n", con_id); -		return desc; -	} - -	/* -	 * If a connection label was passed use that, else attempt to use -	 * the device name as label -	 */ -	ret = gpiod_request(desc, con_id ?: devname); -	if (ret) { -		if (!(ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE)) -			return ERR_PTR(ret); - -		/* -		 * This happens when there are several consumers for -		 * the same GPIO line: we just return here without -		 * further initialization. It is a bit of a hack. -		 * This is necessary to support fixed regulators. -		 * -		 * FIXME: Make this more sane and safe. -		 */ -		dev_info(dev, "nonexclusive access to GPIO for %s\n", con_id ?: devname); -		return desc; -	} - -	ret = gpiod_configure_flags(desc, con_id, lookupflags, flags); -	if (ret < 0) { -		dev_dbg(dev, "setup of GPIO %s failed\n", con_id); -		gpiod_put(desc); -		return ERR_PTR(ret); -	} - -	blocking_notifier_call_chain(&desc->gdev->notifier, -				     GPIOLINE_CHANGED_REQUESTED, desc); - -	return desc; +	return gpiod_find_and_request(dev, fwnode, con_id, idx, flags, label, true);  }  EXPORT_SYMBOL_GPL(gpiod_get_index);  | 
