diff options
| author | Dmitry Torokhov <[email protected]> | 2023-08-30 16:06:38 -0700 | 
|---|---|---|
| committer | Dmitry Torokhov <[email protected]> | 2023-08-30 16:06:38 -0700 | 
| commit | 1ac731c529cd4d6adbce134754b51ff7d822b145 (patch) | |
| tree | 143ab3f35ca5f3b69f583c84e6964b17139c2ec1 /drivers/gpio/gpiolib.c | |
| parent | 07b4c950f27bef0362dc6ad7ee713aab61d58149 (diff) | |
| parent | 54116d442e001e1b6bd482122043b1870998a1f3 (diff) | |
Merge branch 'next' into for-linus
Prepare input updates for 6.6 merge window.
Diffstat (limited to 'drivers/gpio/gpiolib.c')
| -rw-r--r-- | drivers/gpio/gpiolib.c | 186 | 
1 files changed, 105 insertions, 81 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 19bd23044b01..5be8ad61523e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -6,22 +6,25 @@  #include <linux/debugfs.h>  #include <linux/device.h>  #include <linux/err.h> +#include <linux/errno.h>  #include <linux/file.h>  #include <linux/fs.h> -#include <linux/gpio.h> -#include <linux/gpio/driver.h> -#include <linux/gpio/machine.h>  #include <linux/idr.h>  #include <linux/interrupt.h>  #include <linux/irq.h>  #include <linux/kernel.h>  #include <linux/list.h>  #include <linux/module.h> +#include <linux/of.h>  #include <linux/pinctrl/consumer.h>  #include <linux/seq_file.h>  #include <linux/slab.h>  #include <linux/spinlock.h> +#include <linux/gpio.h> +#include <linux/gpio/driver.h> +#include <linux/gpio/machine.h> +  #include <uapi/linux/gpio.h>  #include "gpiolib-acpi.h" @@ -58,7 +61,20 @@  static DEFINE_IDA(gpio_ida);  static dev_t gpio_devt;  #define GPIO_DEV_MAX 256 /* 256 GPIO chip devices supported */ -static int gpio_bus_match(struct device *dev, struct device_driver *drv); + +static int gpio_bus_match(struct device *dev, struct device_driver *drv) +{ +	struct fwnode_handle *fwnode = dev_fwnode(dev); + +	/* +	 * Only match if the fwnode doesn't already have a proper struct device +	 * created for it. +	 */ +	if (fwnode && fwnode->dev != dev) +		return 0; +	return 1; +} +  static struct bus_type gpio_bus_type = {  	.name = "gpio",  	.match = gpio_bus_match, @@ -193,6 +209,8 @@ static int gpiochip_find_base(int ngpio)  			break;  		/* nope, check the space right after the chip */  		base = gdev->base + gdev->ngpio; +		if (base < GPIO_DYNAMIC_BASE) +			base = GPIO_DYNAMIC_BASE;  	}  	if (gpio_is_valid(base)) { @@ -357,7 +375,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)  }  /* - * devprop_gpiochip_set_names - Set GPIO line names using device properties + * gpiochip_set_names - Set GPIO line names using device properties   * @chip: GPIO chip whose lines should be named, if possible   *   * Looks for device property "gpio-line-names" and if it exists assigns @@ -365,7 +383,7 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)   * names belong to the underlying firmware node and should not be released   * by the caller.   */ -static int devprop_gpiochip_set_names(struct gpio_chip *chip) +static int gpiochip_set_names(struct gpio_chip *chip)  {  	struct gpio_device *gdev = chip->gpiodev;  	struct device *dev = &gdev->dev; @@ -556,7 +574,7 @@ bool gpiochip_line_is_valid(const struct gpio_chip *gc,  }  EXPORT_SYMBOL_GPL(gpiochip_line_is_valid); -static void gpiodevice_release(struct device *dev) +static void gpiodev_release(struct device *dev)  {  	struct gpio_device *gdev = to_gpio_device(dev);  	unsigned long flags; @@ -585,21 +603,22 @@ static void gpiodevice_release(struct device *dev)  static int gpiochip_setup_dev(struct gpio_device *gdev)  { +	struct fwnode_handle *fwnode = dev_fwnode(&gdev->dev);  	int ret;  	/*  	 * If fwnode doesn't belong to another device, it's safe to clear its  	 * initialized flag.  	 */ -	if (gdev->dev.fwnode && !gdev->dev.fwnode->dev) -		fwnode_dev_initialized(gdev->dev.fwnode, false); +	if (fwnode && !fwnode->dev) +		fwnode_dev_initialized(fwnode, false);  	ret = gcdev_register(gdev, gpio_devt);  	if (ret)  		return ret;  	/* From this point, the .release() function cleans up gpio_device */ -	gdev->dev.release = gpiodevice_release; +	gdev->dev.release = gpiodev_release;  	ret = gpiochip_sysfs_register(gdev);  	if (ret) @@ -663,11 +682,28 @@ static void gpiochip_setup_devs(void)  	}  } +static void gpiochip_set_data(struct gpio_chip *gc, void *data) +{ +	gc->gpiodev->data = data; +} + +/** + * gpiochip_get_data() - get per-subdriver data for the chip + * @gc: GPIO chip + * + * Returns: + * The per-subdriver data for the chip. + */ +void *gpiochip_get_data(struct gpio_chip *gc) +{ +	return gc->gpiodev->data; +} +EXPORT_SYMBOL_GPL(gpiochip_get_data); +  int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,  			       struct lock_class_key *lock_key,  			       struct lock_class_key *request_key)  { -	struct fwnode_handle *fwnode = NULL;  	struct gpio_device *gdev;  	unsigned long flags;  	unsigned int i; @@ -675,12 +711,12 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,  	int base = 0;  	int ret = 0; -	/* If the calling driver did not initialize firmware node, do it here */ -	if (gc->fwnode) -		fwnode = gc->fwnode; -	else if (gc->parent) -		fwnode = dev_fwnode(gc->parent); -	gc->fwnode = fwnode; +	/* +	 * If the calling driver did not initialize firmware node, do it here +	 * using the parent device, if any. +	 */ +	if (!gc->fwnode && gc->parent) +		gc->fwnode = dev_fwnode(gc->parent);  	/*  	 * First: allocate and populate the internal stat container, and @@ -692,7 +728,9 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,  	gdev->dev.bus = &gpio_bus_type;  	gdev->dev.parent = gc->parent;  	gdev->chip = gc; +  	gc->gpiodev = gdev; +	gpiochip_set_data(gc, data);  	device_set_node(&gdev->dev, gc->fwnode); @@ -759,7 +797,6 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,  	}  	gdev->ngpio = gc->ngpio; -	gdev->data = data;  	spin_lock_irqsave(&gpio_lock, flags); @@ -816,7 +853,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,  		if (ret)  			goto err_remove_from_list;  	} -	ret = devprop_gpiochip_set_names(gc); +	ret = gpiochip_set_names(gc);  	if (ret)  		goto err_remove_from_list; @@ -922,19 +959,6 @@ err_print_message:  EXPORT_SYMBOL_GPL(gpiochip_add_data_with_key);  /** - * gpiochip_get_data() - get per-subdriver data for the chip - * @gc: GPIO chip - * - * Returns: - * The per-subdriver data for the chip. - */ -void *gpiochip_get_data(struct gpio_chip *gc) -{ -	return gc->gpiodev->data; -} -EXPORT_SYMBOL_GPL(gpiochip_get_data); - -/**   * gpiochip_remove() - unregister a gpio_chip   * @gc: the chip to unregister   * @@ -960,9 +984,9 @@ void gpiochip_remove(struct gpio_chip *gc)  	gpiochip_free_valid_mask(gc);  	/*  	 * We accept no more calls into the driver from this point, so -	 * NULL the driver data pointer +	 * NULL the driver data pointer.  	 */ -	gdev->data = NULL; +	gpiochip_set_data(gc, NULL);  	spin_lock_irqsave(&gpio_lock, flags);  	for (i = 0; i < gdev->ngpio; i++) { @@ -1201,7 +1225,7 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,  	if (ret)  		return ret; -	chip_dbg(gc, "allocate IRQ %d, hwirq %lu\n", irq,  hwirq); +	chip_dbg(gc, "allocate IRQ %d, hwirq %lu\n", irq, hwirq);  	ret = girq->child_to_parent_hwirq(gc, hwirq, type,  					  &parent_hwirq, &parent_type); @@ -1369,8 +1393,7 @@ static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)   * gpiochip by assigning the gpiochip as chip data, and using the irqchip   * stored inside the gpiochip.   */ -int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, -		     irq_hw_number_t hwirq) +int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq)  {  	struct gpio_chip *gc = d->host_data;  	int ret = 0; @@ -1446,8 +1469,9 @@ int gpiochip_irq_domain_activate(struct irq_domain *domain,  				 struct irq_data *data, bool reserve)  {  	struct gpio_chip *gc = domain->host_data; +	unsigned int hwirq = irqd_to_hwirq(data); -	return gpiochip_lock_as_irq(gc, data->hwirq); +	return gpiochip_lock_as_irq(gc, hwirq);  }  EXPORT_SYMBOL_GPL(gpiochip_irq_domain_activate); @@ -1464,8 +1488,9 @@ void gpiochip_irq_domain_deactivate(struct irq_domain *domain,  				    struct irq_data *data)  {  	struct gpio_chip *gc = domain->host_data; +	unsigned int hwirq = irqd_to_hwirq(data); -	return gpiochip_unlock_as_irq(gc, data->hwirq); +	return gpiochip_unlock_as_irq(gc, hwirq);  }  EXPORT_SYMBOL_GPL(gpiochip_irq_domain_deactivate); @@ -1505,33 +1530,37 @@ static int gpiochip_to_irq(struct gpio_chip *gc, unsigned int offset)  int gpiochip_irq_reqres(struct irq_data *d)  {  	struct gpio_chip *gc = irq_data_get_irq_chip_data(d); +	unsigned int hwirq = irqd_to_hwirq(d); -	return gpiochip_reqres_irq(gc, d->hwirq); +	return gpiochip_reqres_irq(gc, hwirq);  }  EXPORT_SYMBOL(gpiochip_irq_reqres);  void gpiochip_irq_relres(struct irq_data *d)  {  	struct gpio_chip *gc = irq_data_get_irq_chip_data(d); +	unsigned int hwirq = irqd_to_hwirq(d); -	gpiochip_relres_irq(gc, d->hwirq); +	gpiochip_relres_irq(gc, hwirq);  }  EXPORT_SYMBOL(gpiochip_irq_relres);  static void gpiochip_irq_mask(struct irq_data *d)  {  	struct gpio_chip *gc = irq_data_get_irq_chip_data(d); +	unsigned int hwirq = irqd_to_hwirq(d);  	if (gc->irq.irq_mask)  		gc->irq.irq_mask(d); -	gpiochip_disable_irq(gc, d->hwirq); +	gpiochip_disable_irq(gc, hwirq);  }  static void gpiochip_irq_unmask(struct irq_data *d)  {  	struct gpio_chip *gc = irq_data_get_irq_chip_data(d); +	unsigned int hwirq = irqd_to_hwirq(d); -	gpiochip_enable_irq(gc, d->hwirq); +	gpiochip_enable_irq(gc, hwirq);  	if (gc->irq.irq_unmask)  		gc->irq.irq_unmask(d);  } @@ -1539,17 +1568,19 @@ static void gpiochip_irq_unmask(struct irq_data *d)  static void gpiochip_irq_enable(struct irq_data *d)  {  	struct gpio_chip *gc = irq_data_get_irq_chip_data(d); +	unsigned int hwirq = irqd_to_hwirq(d); -	gpiochip_enable_irq(gc, d->hwirq); +	gpiochip_enable_irq(gc, hwirq);  	gc->irq.irq_enable(d);  }  static void gpiochip_irq_disable(struct irq_data *d)  {  	struct gpio_chip *gc = irq_data_get_irq_chip_data(d); +	unsigned int hwirq = irqd_to_hwirq(d);  	gc->irq.irq_disable(d); -	gpiochip_disable_irq(gc, d->hwirq); +	gpiochip_disable_irq(gc, hwirq);  }  static void gpiochip_set_irq_hooks(struct gpio_chip *gc) @@ -1714,7 +1745,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gc)  	}  	/* Remove all IRQ mappings and delete the domain */ -	if (gc->irq.domain) { +	if (!gc->irq.domain_is_allocated_externally && gc->irq.domain) {  		unsigned int irq;  		for (offset = 0; offset < gc->ngpio; offset++) { @@ -1760,6 +1791,15 @@ int gpiochip_irqchip_add_domain(struct gpio_chip *gc,  	gc->to_irq = gpiochip_to_irq;  	gc->irq.domain = domain; +	gc->irq.domain_is_allocated_externally = true; + +	/* +	 * Using barrier() here to prevent compiler from reordering +	 * gc->irq.initialized before adding irqdomain. +	 */ +	barrier(); + +	gc->irq.initialized = true;  	return 0;  } @@ -3909,13 +3949,10 @@ static struct gpio_desc *gpiod_find_and_request(struct device *consumer,  						bool platform_lookup_allowed)  {  	unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT; -	struct gpio_desc *desc = ERR_PTR(-ENOENT); +	struct gpio_desc *desc;  	int ret; -	if (!IS_ERR_OR_NULL(fwnode)) -		desc = gpiod_find_by_fwnode(fwnode, consumer, con_id, idx, -					    &flags, &lookupflags); - +	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 @@ -4256,16 +4293,18 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,  	struct gpio_array *array_info = NULL;  	struct gpio_chip *gc;  	int count, bitmap_size; +	size_t descs_size;  	count = gpiod_count(dev, con_id);  	if (count < 0)  		return ERR_PTR(count); -	descs = kzalloc(struct_size(descs, desc, count), GFP_KERNEL); +	descs_size = struct_size(descs, desc, count); +	descs = kzalloc(descs_size, GFP_KERNEL);  	if (!descs)  		return ERR_PTR(-ENOMEM); -	for (descs->ndescs = 0; descs->ndescs < count; ) { +	for (descs->ndescs = 0; descs->ndescs < count; descs->ndescs++) {  		desc = gpiod_get_index(dev, con_id, descs->ndescs, flags);  		if (IS_ERR(desc)) {  			gpiod_put_array(descs); @@ -4285,20 +4324,17 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,  			bitmap_size = BITS_TO_LONGS(gc->ngpio > count ?  						    gc->ngpio : count); -			array = kzalloc(struct_size(descs, desc, count) + -					struct_size(array_info, invert_mask, -					3 * bitmap_size), GFP_KERNEL); +			array = krealloc(descs, descs_size + +					 struct_size(array_info, invert_mask, 3 * bitmap_size), +					 GFP_KERNEL | __GFP_ZERO);  			if (!array) {  				gpiod_put_array(descs);  				return ERR_PTR(-ENOMEM);  			} -			memcpy(array, descs, -			       struct_size(descs, desc, descs->ndescs + 1)); -			kfree(descs); -  			descs = array; -			array_info = (void *)(descs->desc + count); + +			array_info = (void *)descs + descs_size;  			array_info->get_mask = array_info->invert_mask +  						  bitmap_size;  			array_info->set_mask = array_info->get_mask + @@ -4313,8 +4349,13 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,  				   count - descs->ndescs);  			descs->info = array_info;  		} + +		/* If there is no cache for fast bitmap processing path, continue */ +		if (!array_info) +			continue; +  		/* Unmark array members which don't belong to the 'fast' chip */ -		if (array_info && array_info->chip != gc) { +		if (array_info->chip != gc) {  			__clear_bit(descs->ndescs, array_info->get_mask);  			__clear_bit(descs->ndescs, array_info->set_mask);  		} @@ -4322,8 +4363,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,  		 * Detect array members which belong to the 'fast' chip  		 * but their pins are not in hardware order.  		 */ -		else if (array_info && -			   gpio_chip_hwgpio(desc) != descs->ndescs) { +		else if (gpio_chip_hwgpio(desc) != descs->ndescs) {  			/*  			 * Don't use fast path if all array members processed so  			 * far belong to the same chip as this one but its pin @@ -4337,7 +4377,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,  				__clear_bit(descs->ndescs,  					    array_info->set_mask);  			} -		} else if (array_info) { +		} else {  			/* Exclude open drain or open source from fast output */  			if (gpiochip_line_is_open_drain(gc, descs->ndescs) ||  			    gpiochip_line_is_open_source(gc, descs->ndescs)) @@ -4348,8 +4388,6 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,  				__set_bit(descs->ndescs,  					  array_info->invert_mask);  		} - -		descs->ndescs++;  	}  	if (array_info)  		dev_dbg(dev, @@ -4413,20 +4451,6 @@ void gpiod_put_array(struct gpio_descs *descs)  }  EXPORT_SYMBOL_GPL(gpiod_put_array); - -static int gpio_bus_match(struct device *dev, struct device_driver *drv) -{ -	struct fwnode_handle *fwnode = dev_fwnode(dev); - -	/* -	 * Only match if the fwnode doesn't already have a proper struct device -	 * created for it. -	 */ -	if (fwnode && fwnode->dev != dev) -		return 0; -	return 1; -} -  static int gpio_stub_drv_probe(struct device *dev)  {  	/*  |