]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
gpiolib: rework the wrapper around gpio_chip::set_multiple()
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Thu, 20 Feb 2025 09:57:01 +0000 (10:57 +0100)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Wed, 26 Feb 2025 10:17:39 +0000 (11:17 +0100)
Make the existing wrapper around gpio_chip::set_multiple() consistent
with the one for gpio_chip::set(): make it return int, add a lockdep
assertion, warn on missing set callback and move the code a bit for
better readability.

Add return value checks in all call places.

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-4-bc4cfd38dae3@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
drivers/gpio/gpiolib.c

index a83494dd3e123d8d4f31685bffe669b3a6b05bcf..d26cad6442bfd99a801e152e348ad49d2aa53fb3 100644 (file)
@@ -3582,21 +3582,33 @@ static int 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 (WARN_ON(unlikely(!gc->set_multiple && !gc->set)))
+               return -EOPNOTSUPP;
+
        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)
-                       gpiochip_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,
@@ -3606,7 +3618,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.
@@ -3629,7 +3641,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)
@@ -3706,8 +3721,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);