diff options
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r-- | drivers/gpio/gpiolib.c | 546 |
1 files changed, 374 insertions, 172 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 0c00ed2ab431..fdafa0df1b43 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -26,6 +26,7 @@ #include <linux/slab.h> #include <linux/srcu.h> #include <linux/string.h> +#include <linux/string_choices.h> #include <linux/gpio.h> #include <linux/gpio/driver.h> @@ -265,6 +266,20 @@ struct gpio_device *gpiod_to_gpio_device(struct gpio_desc *desc) EXPORT_SYMBOL_GPL(gpiod_to_gpio_device); /** + * gpiod_is_equal() - Check if two GPIO descriptors refer to the same pin. + * @desc: Descriptor to compare. + * @other: The second descriptor to compare against. + * + * Returns: + * True if the descriptors refer to the same physical pin. False otherwise. + */ +bool gpiod_is_equal(struct gpio_desc *desc, struct gpio_desc *other) +{ + return desc == other; +} +EXPORT_SYMBOL_GPL(gpiod_is_equal); + +/** * gpio_device_get_base() - Get the base GPIO number allocated by this device * @gdev: GPIO device * @@ -341,6 +356,56 @@ static int gpiochip_find_base_unlocked(u16 ngpio) } } +/* + * This descriptor validation needs to be inserted verbatim into each + * function taking a descriptor, so we need to use a preprocessor + * macro to avoid endless duplication. If the desc is NULL it is an + * optional GPIO and calls should just bail out. + */ +static int validate_desc(const struct gpio_desc *desc, const char *func) +{ + if (!desc) + return 0; + + if (IS_ERR(desc)) { + pr_warn("%s: invalid GPIO (errorpointer: %pe)\n", func, desc); + return PTR_ERR(desc); + } + + return 1; +} + +#define VALIDATE_DESC(desc) do { \ + int __valid = validate_desc(desc, __func__); \ + if (__valid <= 0) \ + return __valid; \ + } while (0) + +#define VALIDATE_DESC_VOID(desc) do { \ + int __valid = validate_desc(desc, __func__); \ + if (__valid <= 0) \ + return; \ + } while (0) + +static int gpiochip_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + int ret; + + lockdep_assert_held(&gc->gpiodev->srcu); + + if (WARN_ON(!gc->get_direction)) + return -EOPNOTSUPP; + + ret = gc->get_direction(gc, offset); + if (ret < 0) + return ret; + + if (ret != GPIO_LINE_DIRECTION_OUT && ret != GPIO_LINE_DIRECTION_IN) + ret = -EBADE; + + return ret; +} + /** * gpiod_get_direction - return the current direction of a GPIO * @desc: GPIO to get the direction of @@ -356,11 +421,8 @@ int gpiod_get_direction(struct gpio_desc *desc) unsigned int offset; int ret; - /* - * We cannot use VALIDATE_DESC() as we must not return 0 for a NULL - * descriptor like we usually do. - */ - if (IS_ERR_OR_NULL(desc)) + ret = validate_desc(desc, __func__); + if (ret <= 0) return -EINVAL; CLASS(gpio_chip_guard, guard)(desc); @@ -381,7 +443,7 @@ int gpiod_get_direction(struct gpio_desc *desc) if (!guard.gc->get_direction) return -ENOTSUPP; - ret = guard.gc->get_direction(guard.gc, offset); + ret = gpiochip_get_direction(guard.gc, offset); if (ret < 0) return ret; @@ -652,7 +714,7 @@ static int gpiochip_apply_reserved_ranges(struct gpio_chip *gc) if (start >= gc->ngpio || start + count > gc->ngpio) continue; - bitmap_clear(gc->valid_mask, start, count); + bitmap_clear(gc->gpiodev->valid_mask, start, count); } kfree(ranges); @@ -666,8 +728,8 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gc) if (!(gpiochip_count_reserved_ranges(gc) || gc->init_valid_mask)) return 0; - gc->valid_mask = gpiochip_allocate_mask(gc); - if (!gc->valid_mask) + gc->gpiodev->valid_mask = gpiochip_allocate_mask(gc); + if (!gc->gpiodev->valid_mask) return -ENOMEM; ret = gpiochip_apply_reserved_ranges(gc); @@ -676,7 +738,7 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gc) if (gc->init_valid_mask) return gc->init_valid_mask(gc, - gc->valid_mask, + gc->gpiodev->valid_mask, gc->ngpio); return 0; @@ -684,7 +746,7 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gc) static void gpiochip_free_valid_mask(struct gpio_chip *gc) { - gpiochip_free_mask(&gc->valid_mask); + gpiochip_free_mask(&gc->gpiodev->valid_mask); } static int gpiochip_add_pin_ranges(struct gpio_chip *gc) @@ -703,13 +765,35 @@ static int gpiochip_add_pin_ranges(struct gpio_chip *gc) return 0; } +/** + * gpiochip_query_valid_mask - return the GPIO validity information + * @gc: gpio chip which validity information is queried + * + * Returns: bitmap representing valid GPIOs or NULL if all GPIOs are valid + * + * Some GPIO chips may support configurations where some of the pins aren't + * available. These chips can have valid_mask set to represent the valid + * GPIOs. This function can be used to retrieve this information. + */ +const unsigned long *gpiochip_query_valid_mask(const struct gpio_chip *gc) +{ + return gc->gpiodev->valid_mask; +} +EXPORT_SYMBOL_GPL(gpiochip_query_valid_mask); + bool gpiochip_line_is_valid(const struct gpio_chip *gc, unsigned int offset) { + /* + * hog pins are requested before registering GPIO chip + */ + if (!gc->gpiodev) + return true; + /* No mask means all valid */ - if (likely(!gc->valid_mask)) + if (likely(!gc->gpiodev->valid_mask)) return true; - return test_bit(offset, gc->valid_mask); + return test_bit(offset, gc->gpiodev->valid_mask); } EXPORT_SYMBOL_GPL(gpiochip_line_is_valid); @@ -838,14 +922,12 @@ static void machine_gpiochip_add(struct gpio_chip *gc) { struct gpiod_hog *hog; - mutex_lock(&gpio_machine_hogs_mutex); + guard(mutex)(&gpio_machine_hogs_mutex); list_for_each_entry(hog, &gpio_machine_hogs, list) { if (!strcmp(gc->label, hog->chip_label)) gpiochip_machine_hog(gc, hog); } - - mutex_unlock(&gpio_machine_hogs_mutex); } static void gpiochip_setup_devs(void) @@ -882,13 +964,29 @@ void *gpiochip_get_data(struct gpio_chip *gc) } EXPORT_SYMBOL_GPL(gpiochip_get_data); +/* + * If the calling driver provides the specific firmware node, + * use it. Otherwise use the one from the parent device, if any. + */ +static struct fwnode_handle *gpiochip_choose_fwnode(struct gpio_chip *gc) +{ + if (gc->fwnode) + return gc->fwnode; + + if (gc->parent) + return dev_fwnode(gc->parent); + + return NULL; +} + int gpiochip_get_ngpios(struct gpio_chip *gc, struct device *dev) { + struct fwnode_handle *fwnode = gpiochip_choose_fwnode(gc); u32 ngpios = gc->ngpio; int ret; if (ngpios == 0) { - ret = device_property_read_u32(dev, "ngpios", &ngpios); + ret = fwnode_property_read_u32(fwnode, "ngpios", &ngpios); if (ret == -ENODATA) /* * -ENODATA means that there is no property found and @@ -923,7 +1021,12 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, struct gpio_device *gdev; unsigned int desc_index; int base = 0; - int ret = 0; + int ret; + + /* Only allow one set() and one set_multiple(). */ + if ((gc->set && gc->set_rv) || + (gc->set_multiple && gc->set_multiple_rv)) + return -EINVAL; /* * First: allocate and populate the internal stat container, and @@ -941,20 +1044,12 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, gc->gpiodev = gdev; gpiochip_set_data(gc, data); - /* - * If the calling driver did not initialize firmware node, - * do it here using the parent device, if any. - */ - if (gc->fwnode) - device_set_node(&gdev->dev, gc->fwnode); - else if (gc->parent) - device_set_node(&gdev->dev, dev_fwnode(gc->parent)); + device_set_node(&gdev->dev, gpiochip_choose_fwnode(gc)); - gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL); - if (gdev->id < 0) { - ret = gdev->id; + ret = ida_alloc(&gpio_ida, GFP_KERNEL); + if (ret < 0) goto err_free_gdev; - } + gdev->id = ret; ret = dev_set_name(&gdev->dev, GPIOCHIP_NAME "%d", gdev->id); if (ret) @@ -1058,11 +1153,11 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, desc->gdev = gdev; /* - * We would typically want to check the return value of - * get_direction() here but we must not check the return value - * and bail-out as pin controllers can have pins configured to - * alternate functions and return -EINVAL. Also: there's no - * need to take the SRCU lock here. + * We would typically want to use gpiochip_get_direction() here + * but we must not check the return value and bail-out as pin + * controllers can have pins configured to alternate functions + * and return -EINVAL. Also: there's no need to take the SRCU + * lock here. */ if (gc->get_direction && gpiochip_line_is_valid(gc, desc_index)) assign_bit(FLAG_IS_OUT, &desc->flags, @@ -1457,9 +1552,8 @@ static int gpiochip_hierarchy_irq_domain_translate(struct irq_domain *d, unsigned int *type) { /* We support standard DT translation */ - if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) { - return irq_domain_translate_twocell(d, fwspec, hwirq, type); - } + if (is_of_node(fwspec->fwnode)) + return irq_domain_translate_twothreecell(d, fwspec, hwirq, type); /* This is for board files and others not using DT */ if (is_fwnode_irqchip(fwspec->fwnode)) { @@ -1761,11 +1855,26 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq) irq_set_chip_data(irq, NULL); } +static int gpiochip_irq_select(struct irq_domain *d, struct irq_fwspec *fwspec, + enum irq_domain_bus_token bus_token) +{ + struct fwnode_handle *fwnode = fwspec->fwnode; + struct gpio_chip *gc = d->host_data; + unsigned int index = fwspec->param[0]; + + if (fwspec->param_count == 3 && is_of_node(fwnode)) + return of_gpiochip_instance_match(gc, index); + + /* Fallback for twocells */ + return (fwnode && (d->fwnode == fwnode) && (d->bus_token == bus_token)); +} + static const struct irq_domain_ops gpiochip_domain_ops = { .map = gpiochip_irq_map, .unmap = gpiochip_irq_unmap, + .select = gpiochip_irq_select, /* Virtually all GPIO irqchips are twocell:ed */ - .xlate = irq_domain_xlate_twocell, + .xlate = irq_domain_xlate_twothreecell, }; static struct irq_domain *gpiochip_simple_create_domain(struct gpio_chip *gc) @@ -1785,7 +1894,6 @@ static int gpiochip_to_irq(struct gpio_chip *gc, unsigned int offset) { struct irq_domain *domain = gc->irq.domain; -#ifdef CONFIG_GPIOLIB_IRQCHIP /* * Avoid race condition with other code, which tries to lookup * an IRQ before the irqchip has been properly registered, @@ -1793,7 +1901,6 @@ static int gpiochip_to_irq(struct gpio_chip *gc, unsigned int offset) */ if (!gc->irq.initialized) return -EPROBE_DEFER; -#endif if (!gpiochip_irqchip_irq_valid(gc, offset)) return -ENXIO; @@ -2325,16 +2432,18 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) if (test_and_set_bit(FLAG_REQUESTED, &desc->flags)) return -EBUSY; + offset = gpio_chip_hwgpio(desc); + if (!gpiochip_line_is_valid(guard.gc, offset)) + return -EINVAL; + /* NOTE: gpio_request() can be called in early boot, * before IRQs are enabled, for non-sleeping (SOC) GPIOs. */ if (guard.gc->request) { - offset = gpio_chip_hwgpio(desc); - if (gpiochip_line_is_valid(guard.gc, offset)) - ret = guard.gc->request(guard.gc, offset); - else - ret = -EINVAL; + ret = guard.gc->request(guard.gc, offset); + if (ret > 0) + ret = -EBADE; if (ret) goto out_clear_bit; } @@ -2353,37 +2462,6 @@ out_clear_bit: return ret; } -/* - * This descriptor validation needs to be inserted verbatim into each - * function taking a descriptor, so we need to use a preprocessor - * macro to avoid endless duplication. If the desc is NULL it is an - * optional GPIO and calls should just bail out. - */ -static int validate_desc(const struct gpio_desc *desc, const char *func) -{ - if (!desc) - return 0; - - if (IS_ERR(desc)) { - pr_warn("%s: invalid GPIO (errorpointer)\n", func); - return PTR_ERR(desc); - } - - return 1; -} - -#define VALIDATE_DESC(desc) do { \ - int __valid = validate_desc(desc, __func__); \ - if (__valid <= 0) \ - return __valid; \ - } while (0) - -#define VALIDATE_DESC_VOID(desc) do { \ - int __valid = validate_desc(desc, __func__); \ - if (__valid <= 0) \ - return; \ - } while (0) - int gpiod_request(struct gpio_desc *desc, const char *label) { int ret = -EPROBE_DEFER; @@ -2577,6 +2655,9 @@ int gpio_do_set_config(struct gpio_desc *desc, unsigned long config) return -ENOTSUPP; ret = guard.gc->set_config(guard.gc, gpio_chip_hwgpio(desc), config); + if (ret > 0) + ret = -EBADE; + #ifdef CONFIG_GPIO_CDEV /* * Special case - if we're setting debounce period, we need to store @@ -2682,6 +2763,39 @@ int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce) return ret; } +static int gpiochip_direction_input(struct gpio_chip *gc, unsigned int offset) +{ + int ret; + + lockdep_assert_held(&gc->gpiodev->srcu); + + if (WARN_ON(!gc->direction_input)) + return -EOPNOTSUPP; + + ret = gc->direction_input(gc, offset); + if (ret > 0) + ret = -EBADE; + + return ret; +} + +static int gpiochip_direction_output(struct gpio_chip *gc, unsigned int offset, + int value) +{ + int ret; + + lockdep_assert_held(&gc->gpiodev->srcu); + + if (WARN_ON(!gc->direction_output)) + return -EOPNOTSUPP; + + ret = gc->direction_output(gc, offset, value); + if (ret > 0) + ret = -EBADE; + + return ret; +} + /** * gpiod_direction_input - set the GPIO direction to input * @desc: GPIO to set to input @@ -2733,11 +2847,10 @@ int gpiod_direction_input_nonotify(struct gpio_desc *desc) * assume we are in input mode after this. */ if (guard.gc->direction_input) { - ret = guard.gc->direction_input(guard.gc, - gpio_chip_hwgpio(desc)); + ret = gpiochip_direction_input(guard.gc, + gpio_chip_hwgpio(desc)); } else if (guard.gc->get_direction) { - dir = guard.gc->get_direction(guard.gc, - gpio_chip_hwgpio(desc)); + dir = gpiochip_get_direction(guard.gc, gpio_chip_hwgpio(desc)); if (dir < 0) return dir; @@ -2758,6 +2871,27 @@ int gpiod_direction_input_nonotify(struct gpio_desc *desc) return ret; } +static int gpiochip_set(struct gpio_chip *gc, unsigned int offset, int value) +{ + int ret; + + lockdep_assert_held(&gc->gpiodev->srcu); + + if (WARN_ON(unlikely(!gc->set && !gc->set_rv))) + return -EOPNOTSUPP; + + if (gc->set_rv) { + ret = gc->set_rv(gc, offset, value); + if (ret > 0) + ret = -EBADE; + + return ret; + } + + gc->set(gc, offset, value); + return 0; +} + static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) { int val = !!value, ret = 0, dir; @@ -2771,7 +2905,7 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) * output-only, but if there is then not even a .set() operation it * is pretty tricky to drive the output line. */ - if (!guard.gc->set && !guard.gc->direction_output) { + if (!guard.gc->set && !guard.gc->set_rv && !guard.gc->direction_output) { gpiod_warn(desc, "%s: missing set() and direction_output() operations\n", __func__); @@ -2779,13 +2913,13 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) } if (guard.gc->direction_output) { - ret = guard.gc->direction_output(guard.gc, - gpio_chip_hwgpio(desc), val); + ret = gpiochip_direction_output(guard.gc, + gpio_chip_hwgpio(desc), val); } else { /* Check that we are in output mode if we can */ if (guard.gc->get_direction) { - dir = guard.gc->get_direction(guard.gc, - gpio_chip_hwgpio(desc)); + dir = gpiochip_get_direction(guard.gc, + gpio_chip_hwgpio(desc)); if (dir < 0) return dir; @@ -2800,7 +2934,9 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) * If we can't actively set the direction, we are some * output-only chip, so just drive the output as desired. */ - guard.gc->set(guard.gc, gpio_chip_hwgpio(desc), val); + ret = gpiochip_set(guard.gc, gpio_chip_hwgpio(desc), val); + if (ret) + return ret; } if (!ret) @@ -2890,19 +3026,15 @@ int gpiod_direction_output_nonotify(struct gpio_desc *desc, int value) if (!ret) goto set_output_value; /* Emulate open drain by not actively driving the line high */ - if (value) { - ret = gpiod_direction_input_nonotify(desc); + if (value) goto set_output_flag; - } } else if (test_bit(FLAG_OPEN_SOURCE, &flags)) { ret = gpio_set_config(desc, PIN_CONFIG_DRIVE_OPEN_SOURCE); if (!ret) goto set_output_value; /* Emulate open source by not actively driving the line low */ - if (!value) { - ret = gpiod_direction_input_nonotify(desc); + if (!value) goto set_output_flag; - } } else { gpio_set_config(desc, PIN_CONFIG_DRIVE_PUSH_PULL); } @@ -2914,17 +3046,20 @@ set_output_value: return gpiod_direction_output_raw_commit(desc, value); set_output_flag: + ret = gpiod_direction_input_nonotify(desc); + if (ret) + return ret; /* * When emulating open-source or open-drain functionalities by not * actively driving the line (setting mode to input) we still need to * set the IS_OUT flag or otherwise we won't be able to set the line * value anymore. */ - if (ret == 0) - set_bit(FLAG_IS_OUT, &desc->flags); - return ret; + set_bit(FLAG_IS_OUT, &desc->flags); + return 0; } +#if IS_ENABLED(CONFIG_HTE) /** * gpiod_enable_hw_timestamp_ns - Enable hardware timestamp in nanoseconds. * @@ -2936,7 +3071,7 @@ set_output_flag: */ int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags) { - int ret = 0; + int ret; VALIDATE_DESC(desc); @@ -2969,7 +3104,7 @@ EXPORT_SYMBOL_GPL(gpiod_enable_hw_timestamp_ns); */ int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags) { - int ret = 0; + int ret; VALIDATE_DESC(desc); @@ -2990,6 +3125,7 @@ int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags) return ret; } EXPORT_SYMBOL_GPL(gpiod_disable_hw_timestamp_ns); +#endif /* CONFIG_HTE */ /** * gpiod_set_config - sets @config for a GPIO @@ -3096,9 +3232,23 @@ void gpiod_toggle_active_low(struct gpio_desc *desc) } EXPORT_SYMBOL_GPL(gpiod_toggle_active_low); +static int gpiochip_get(struct gpio_chip *gc, unsigned int offset) +{ + int ret; + + lockdep_assert_held(&gc->gpiodev->srcu); + + /* Make sure this is called after checking for gc->get(). */ + ret = gc->get(gc, offset); + if (ret > 1) + ret = -EBADE; + + return ret; +} + static int gpio_chip_get_value(struct gpio_chip *gc, const struct gpio_desc *desc) { - return gc->get ? gc->get(gc, gpio_chip_hwgpio(desc)) : -EIO; + return gc->get ? gpiochip_get(gc, gpio_chip_hwgpio(desc)) : -EIO; } /* I/O calls are only valid after configuration completed; the relevant @@ -3147,15 +3297,21 @@ static int gpiod_get_raw_value_commit(const struct gpio_desc *desc) static int gpio_chip_get_multiple(struct gpio_chip *gc, unsigned long *mask, unsigned long *bits) { + int ret; + lockdep_assert_held(&gc->gpiodev->srcu); - if (gc->get_multiple) - return gc->get_multiple(gc, mask, bits); + if (gc->get_multiple) { + ret = gc->get_multiple(gc, mask, bits); + if (ret > 0) + return -EBADE; + } + if (gc->get) { int i, value; for_each_set_bit(i, mask, gc->ngpio) { - value = gc->get(gc, i); + value = gpiochip_get(gc, i); if (value < 0) return value; __assign_bit(i, bits, value); @@ -3408,18 +3564,18 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value); * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherwise it will set to LOW. */ -static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) +static int gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) { int ret = 0, offset = gpio_chip_hwgpio(desc); CLASS(gpio_chip_guard, guard)(desc); if (!guard.gc) - return; + return -ENODEV; if (value) { - ret = guard.gc->direction_input(guard.gc, offset); + ret = gpiochip_direction_input(guard.gc, offset); } else { - ret = guard.gc->direction_output(guard.gc, offset, 0); + ret = gpiochip_direction_output(guard.gc, offset, 0); if (!ret) set_bit(FLAG_IS_OUT, &desc->flags); } @@ -3428,6 +3584,8 @@ static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) gpiod_err(desc, "%s: Error in set_value for open drain err %d\n", __func__, ret); + + return ret; } /* @@ -3435,36 +3593,41 @@ static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value) * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherwise it will set to LOW. */ -static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value) +static int gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value) { int ret = 0, offset = gpio_chip_hwgpio(desc); CLASS(gpio_chip_guard, guard)(desc); if (!guard.gc) - return; + return -ENODEV; if (value) { - ret = guard.gc->direction_output(guard.gc, offset, 1); + ret = gpiochip_direction_output(guard.gc, offset, 1); if (!ret) set_bit(FLAG_IS_OUT, &desc->flags); } else { - ret = guard.gc->direction_input(guard.gc, offset); + ret = gpiochip_direction_input(guard.gc, offset); } trace_gpio_direction(desc_to_gpio(desc), !value, ret); if (ret < 0) gpiod_err(desc, "%s: Error in set_value for open source err %d\n", __func__, ret); + + return ret; } -static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) +static int gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) { + if (unlikely(!test_bit(FLAG_IS_OUT, &desc->flags))) + return -EPERM; + CLASS(gpio_chip_guard, guard)(desc); if (!guard.gc) - return; + return -ENODEV; trace_gpio_value(desc_to_gpio(desc), 0, value); - guard.gc->set(guard.gc, gpio_chip_hwgpio(desc), value); + return gpiochip_set(guard.gc, gpio_chip_hwgpio(desc), value); } /* @@ -3476,21 +3639,38 @@ static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) * defines which outputs are to be changed * @bits: bit value array; one bit per output; BITS_PER_LONG bits per word * defines the values the outputs specified by mask are to be set to + * + * Returns: 0 on success, negative error number on failure. */ -static void gpio_chip_set_multiple(struct gpio_chip *gc, - unsigned long *mask, unsigned long *bits) +static int gpiochip_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) { + unsigned int i; + int ret; + lockdep_assert_held(&gc->gpiodev->srcu); + if (gc->set_multiple_rv) { + ret = gc->set_multiple_rv(gc, mask, bits); + if (ret > 0) + ret = -EBADE; + + return ret; + } + if (gc->set_multiple) { gc->set_multiple(gc, mask, bits); - } else { - unsigned int i; + return 0; + } - /* set outputs if the corresponding mask bit is set */ - for_each_set_bit(i, mask, gc->ngpio) - gc->set(gc, i, test_bit(i, bits)); + /* set outputs if the corresponding mask bit is set */ + for_each_set_bit(i, mask, gc->ngpio) { + ret = gpiochip_set(gc, i, test_bit(i, bits)); + if (ret) + break; } + + return ret; } int gpiod_set_array_value_complex(bool raw, bool can_sleep, @@ -3500,7 +3680,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, unsigned long *value_bitmap) { struct gpio_chip *gc; - int i = 0; + int i = 0, ret; /* * Validate array_info against desc_array and its size. @@ -3513,6 +3693,12 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, if (!can_sleep) WARN_ON(array_info->gdev->can_sleep); + for (i = 0; i < array_size; i++) { + if (unlikely(!test_bit(FLAG_IS_OUT, + &desc_array[i]->flags))) + return -EPERM; + } + guard(srcu)(&array_info->gdev->srcu); gc = srcu_dereference(array_info->gdev->chip, &array_info->gdev->srcu); @@ -3523,7 +3709,10 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, bitmap_xor(value_bitmap, value_bitmap, array_info->invert_mask, array_size); - gpio_chip_set_multiple(gc, array_info->set_mask, value_bitmap); + ret = gpiochip_set_multiple(gc, array_info->set_mask, + value_bitmap); + if (ret) + return ret; i = find_first_zero_bit(array_info->set_mask, array_size); if (i == array_size) @@ -3569,6 +3758,9 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, int hwgpio = gpio_chip_hwgpio(desc); int value = test_bit(i, value_bitmap); + if (unlikely(!test_bit(FLAG_IS_OUT, &desc->flags))) + return -EPERM; + /* * Pins applicable for fast input but not for * fast output processing may have been already @@ -3600,8 +3792,11 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, } while ((i < array_size) && gpio_device_chip_cmp(desc_array[i]->gdev, guard.gc)); /* push collected bits to outputs */ - if (count != 0) - gpio_chip_set_multiple(guard.gc, mask, bits); + if (count != 0) { + ret = gpiochip_set_multiple(guard.gc, mask, bits); + if (ret) + return ret; + } if (mask != fastpath_mask) bitmap_free(mask); @@ -3621,13 +3816,16 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, * * This function can be called from contexts where we cannot sleep, and will * complain if the GPIO chip functions potentially sleep. + * + * Returns: + * 0 on success, negative error number on failure. */ -void gpiod_set_raw_value(struct gpio_desc *desc, int value) +int gpiod_set_raw_value(struct gpio_desc *desc, int value) { - VALIDATE_DESC_VOID(desc); + VALIDATE_DESC(desc); /* Should be using gpiod_set_raw_value_cansleep() */ WARN_ON(desc->gdev->can_sleep); - gpiod_set_raw_value_commit(desc, value); + return gpiod_set_raw_value_commit(desc, value); } EXPORT_SYMBOL_GPL(gpiod_set_raw_value); @@ -3639,17 +3837,21 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_value); * This sets the value of a GPIO line backing a descriptor, applying * different semantic quirks like active low and open drain/source * handling. + * + * Returns: + * 0 on success, negative error number on failure. */ -static void gpiod_set_value_nocheck(struct gpio_desc *desc, int value) +static int gpiod_set_value_nocheck(struct gpio_desc *desc, int value) { if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; + if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) - gpio_set_open_drain_value_commit(desc, value); + return gpio_set_open_drain_value_commit(desc, value); else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) - gpio_set_open_source_value_commit(desc, value); - else - gpiod_set_raw_value_commit(desc, value); + return gpio_set_open_source_value_commit(desc, value); + + return gpiod_set_raw_value_commit(desc, value); } /** @@ -3662,13 +3864,16 @@ static void gpiod_set_value_nocheck(struct gpio_desc *desc, int value) * * This function can be called from contexts where we cannot sleep, and will * complain if the GPIO chip functions potentially sleep. + * + * Returns: + * 0 on success, negative error number on failure. */ -void gpiod_set_value(struct gpio_desc *desc, int value) +int gpiod_set_value(struct gpio_desc *desc, int value) { - VALIDATE_DESC_VOID(desc); + VALIDATE_DESC(desc); /* Should be using gpiod_set_value_cansleep() */ WARN_ON(desc->gdev->can_sleep); - gpiod_set_value_nocheck(desc, value); + return gpiod_set_value_nocheck(desc, value); } EXPORT_SYMBOL_GPL(gpiod_set_value); @@ -3777,13 +3982,10 @@ int gpiod_to_irq(const struct gpio_desc *desc) struct gpio_device *gdev; struct gpio_chip *gc; int offset; + int ret; - /* - * Cannot VALIDATE_DESC() here as gpiod_to_irq() consumer semantics - * requires this function to not return zero on an invalid descriptor - * but rather a negative error number. - */ - if (IS_ERR_OR_NULL(desc)) + ret = validate_desc(desc, __func__); + if (ret <= 0) return -EINVAL; gdev = desc->gdev; @@ -3795,13 +3997,12 @@ int gpiod_to_irq(const struct gpio_desc *desc) offset = gpio_chip_hwgpio(desc); if (gc->to_irq) { - int retirq = gc->to_irq(gc, offset); + ret = gc->to_irq(gc, offset); + if (ret) + return ret; /* Zero means NO_IRQ */ - if (!retirq) - return -ENXIO; - - return retirq; + return -ENXIO; } #ifdef CONFIG_GPIOLIB_IRQCHIP if (gc->irq.chip) { @@ -4086,12 +4287,15 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep); * regard for its ACTIVE_LOW status. * * This function is to be called from contexts that can sleep. + * + * Returns: + * 0 on success, negative error number on failure. */ -void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) +int gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) { might_sleep(); - VALIDATE_DESC_VOID(desc); - gpiod_set_raw_value_commit(desc, value); + VALIDATE_DESC(desc); + return gpiod_set_raw_value_commit(desc, value); } EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep); @@ -4104,12 +4308,15 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep); * account * * This function is to be called from contexts that can sleep. + * + * Returns: + * 0 on success, negative error number on failure. */ -void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) +int gpiod_set_value_cansleep(struct gpio_desc *desc, int value) { might_sleep(); - VALIDATE_DESC_VOID(desc); - gpiod_set_value_nocheck(desc, value); + VALIDATE_DESC(desc); + return gpiod_set_value_nocheck(desc, value); } EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); @@ -4150,12 +4357,10 @@ void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n) { unsigned int i; - mutex_lock(&gpio_lookup_lock); + guard(mutex)(&gpio_lookup_lock); for (i = 0; i < n; i++) list_add_tail(&tables[i]->list, &gpio_lookup_list); - - mutex_unlock(&gpio_lookup_lock); } /** @@ -4214,11 +4419,9 @@ void gpiod_remove_lookup_table(struct gpiod_lookup_table *table) if (!table) return; - mutex_lock(&gpio_lookup_lock); + guard(mutex)(&gpio_lookup_lock); list_del(&table->list); - - mutex_unlock(&gpio_lookup_lock); } EXPORT_SYMBOL_GPL(gpiod_remove_lookup_table); @@ -4230,7 +4433,7 @@ void gpiod_add_hogs(struct gpiod_hog *hogs) { struct gpiod_hog *hog; - mutex_lock(&gpio_machine_hogs_mutex); + guard(mutex)(&gpio_machine_hogs_mutex); for (hog = &hogs[0]; hog->chip_label; hog++) { list_add_tail(&hog->list, &gpio_machine_hogs); @@ -4244,8 +4447,6 @@ void gpiod_add_hogs(struct gpiod_hog *hogs) if (gdev) gpiochip_machine_hog(gpio_device_get_chip(gdev), hog); } - - mutex_unlock(&gpio_machine_hogs_mutex); } EXPORT_SYMBOL_GPL(gpiod_add_hogs); @@ -4253,10 +4454,10 @@ void gpiod_remove_hogs(struct gpiod_hog *hogs) { struct gpiod_hog *hog; - mutex_lock(&gpio_machine_hogs_mutex); + guard(mutex)(&gpio_machine_hogs_mutex); + for (hog = &hogs[0]; hog->chip_label; hog++) list_del(&hog->list); - mutex_unlock(&gpio_machine_hogs_mutex); } EXPORT_SYMBOL_GPL(gpiod_remove_hogs); @@ -4746,10 +4947,10 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, return ret; } - gpiod_dbg(desc, "hogged as %s%s\n", + gpiod_dbg(desc, "hogged as %s/%s\n", (dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input", (dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? - (dflags & GPIOD_FLAGS_BIT_DIR_VAL) ? "/high" : "/low" : ""); + str_high_low(dflags & GPIOD_FLAGS_BIT_DIR_VAL) : "?"); return 0; } @@ -4935,8 +5136,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_optional); */ void gpiod_put(struct gpio_desc *desc) { - if (desc) - gpiod_free(desc); + gpiod_free(desc); } EXPORT_SYMBOL_GPL(gpiod_put); @@ -5023,6 +5223,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) unsigned int gpio = gdev->base; struct gpio_desc *desc; struct gpio_chip *gc; + unsigned long flags; int value; guard(srcu)(&gdev->srcu); @@ -5035,16 +5236,17 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) for_each_gpio_desc(gc, desc) { guard(srcu)(&desc->gdev->desc_srcu); - is_irq = test_bit(FLAG_USED_AS_IRQ, &desc->flags); - if (is_irq || test_bit(FLAG_REQUESTED, &desc->flags)) { + flags = READ_ONCE(desc->flags); + is_irq = test_bit(FLAG_USED_AS_IRQ, &flags); + if (is_irq || test_bit(FLAG_REQUESTED, &flags)) { gpiod_get_direction(desc); - is_out = test_bit(FLAG_IS_OUT, &desc->flags); + is_out = test_bit(FLAG_IS_OUT, &flags); value = gpio_chip_get_value(gc, desc); - active_low = test_bit(FLAG_ACTIVE_LOW, &desc->flags); + active_low = test_bit(FLAG_ACTIVE_LOW, &flags); seq_printf(s, " gpio-%-3u (%-20.20s|%-20.20s) %s %s %s%s\n", gpio, desc->name ?: "", gpiod_get_label(desc), is_out ? "out" : "in ", - value >= 0 ? (value ? "hi" : "lo") : "? ", + value >= 0 ? str_hi_lo(value) : "? ", is_irq ? "IRQ " : "", active_low ? "ACTIVE LOW" : ""); } else if (desc->name) { |