Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpiolib: introduce gpio_chip setters that return values

Add new variants of the set() and set_multiple() callbacks that have
integer return values allowing to indicate failures to users of the GPIO
consumer API. Until we convert all GPIO providers treewide to using
them, they will live in parallel to the existing ones.

Make sure that providers cannot define both. Prefer the new ones and
only use the old ones as fallback.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Link: https://lore.kernel.org/r/20250220-gpio-set-retval-v2-5-bc4cfd38dae3@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

+35 -2
+25 -2
drivers/gpio/gpiolib.c
··· 958 958 int base = 0; 959 959 int ret = 0; 960 960 961 + /* Only allow one set() and one set_multiple(). */ 962 + if ((gc->set && gc->set_rv) || 963 + (gc->set_multiple && gc->set_multiple_rv)) 964 + return -EINVAL; 965 + 961 966 /* 962 967 * First: allocate and populate the internal stat container, and 963 968 * set up the struct device. ··· 2832 2827 2833 2828 static int gpiochip_set(struct gpio_chip *gc, unsigned int offset, int value) 2834 2829 { 2830 + int ret; 2831 + 2835 2832 lockdep_assert_held(&gc->gpiodev->srcu); 2836 2833 2837 - if (WARN_ON(unlikely(!gc->set))) 2834 + if (WARN_ON(unlikely(!gc->set && !gc->set_rv))) 2838 2835 return -EOPNOTSUPP; 2836 + 2837 + if (gc->set_rv) { 2838 + ret = gc->set_rv(gc, offset, value); 2839 + if (ret > 0) 2840 + ret = -EBADE; 2841 + 2842 + return ret; 2843 + } 2839 2844 2840 2845 gc->set(gc, offset, value); 2841 2846 return 0; ··· 3608 3593 3609 3594 lockdep_assert_held(&gc->gpiodev->srcu); 3610 3595 3611 - if (WARN_ON(unlikely(!gc->set_multiple && !gc->set))) 3596 + if (WARN_ON(unlikely(!gc->set_multiple && !gc->set_multiple_rv))) 3612 3597 return -EOPNOTSUPP; 3598 + 3599 + if (gc->set_multiple_rv) { 3600 + ret = gc->set_multiple_rv(gc, mask, bits); 3601 + if (ret > 0) 3602 + ret = -EBADE; 3603 + 3604 + return ret; 3605 + } 3613 3606 3614 3607 if (gc->set_multiple) { 3615 3608 gc->set_multiple(gc, mask, bits);
+10
include/linux/gpio/driver.h
··· 348 348 * stores them in "bits", returns 0 on success or negative error 349 349 * @set: assigns output value for signal "offset" 350 350 * @set_multiple: assigns output values for multiple signals defined by "mask" 351 + * @set_rv: assigns output value for signal "offset", returns 0 on success or 352 + * negative error value 353 + * @set_multiple_rv: assigns output values for multiple signals defined by 354 + * "mask", returns 0 on success or negative error value 351 355 * @set_config: optional hook for all kinds of settings. Uses the same 352 356 * packed config format as generic pinconf. Must return 0 on success and 353 357 * a negative error number on failure. ··· 449 445 void (*set_multiple)(struct gpio_chip *gc, 450 446 unsigned long *mask, 451 447 unsigned long *bits); 448 + int (*set_rv)(struct gpio_chip *gc, 449 + unsigned int offset, 450 + int value); 451 + int (*set_multiple_rv)(struct gpio_chip *gc, 452 + unsigned long *mask, 453 + unsigned long *bits); 452 454 int (*set_config)(struct gpio_chip *gc, 453 455 unsigned int offset, 454 456 unsigned long config);