]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
gpio: mmio: handle "ngpios" properly in bgpio_init()
authorAsmaa Mnebhi <asmaa@nvidia.com>
Tue, 11 Jul 2023 15:12:48 +0000 (11:12 -0400)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Tue, 18 Jul 2023 18:59:25 +0000 (20:59 +0200)
bgpio_init() uses "sz" argument to populate ngpio, which is not
accurate. Instead, read the "ngpios" property from the DT and if it
doesn't exist, use the "sz" argument. With this change, drivers no
longer need to overwrite the ngpio variable after calling bgpio_init().

If the "ngpios" property is specified, bgpio_bits is calculated
as the round up value of ngpio. At the moment, the only requirement
specified is that the round up value must be a multiple of 8 but
it should also be a power of 2 because we provide accessors based
on the bank size in bgpio_setup_accessors().

Signed-off-by: Asmaa Mnebhi <asmaa@nvidia.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
drivers/gpio/gpio-mmio.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h

index d9dff3dc92ae574cba9cdae04b33af5324056554..74fdf0d87b2c8edc6993c67ed88d5cd6d2704c14 100644 (file)
@@ -60,6 +60,8 @@ o        `                     ~~~~\___/~~~~    ` controller in FPGA is ,.`
 #include <linux/of.h>
 #include <linux/of_device.h>
 
+#include "gpiolib.h"
+
 static void bgpio_write8(void __iomem *reg, unsigned long data)
 {
        writeb(data, reg);
@@ -614,10 +616,15 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
        gc->parent = dev;
        gc->label = dev_name(dev);
        gc->base = -1;
-       gc->ngpio = gc->bgpio_bits;
        gc->request = bgpio_request;
        gc->be_bits = !!(flags & BGPIOF_BIG_ENDIAN);
 
+       ret = gpiochip_get_ngpios(gc, dev);
+       if (ret)
+               gc->ngpio = gc->bgpio_bits;
+       else
+               gc->bgpio_bits = roundup_pow_of_two(round_up(gc->ngpio, 8));
+
        ret = bgpio_setup_io(gc, dat, set, clr, flags);
        if (ret)
                return ret;
index 62199ec96db2f2f6617d804b4d42a80c17553d65..edab00c9cb3c4425cb0c103f2974d8624b225b5f 100644 (file)
@@ -700,6 +700,40 @@ void *gpiochip_get_data(struct gpio_chip *gc)
 }
 EXPORT_SYMBOL_GPL(gpiochip_get_data);
 
+int gpiochip_get_ngpios(struct gpio_chip *gc, struct device *dev)
+{
+       u32 ngpios = gc->ngpio;
+       int ret;
+
+       if (ngpios == 0) {
+               ret = device_property_read_u32(dev, "ngpios", &ngpios);
+               if (ret == -ENODATA)
+                       /*
+                        * -ENODATA means that there is no property found and
+                        * we want to issue the error message to the user.
+                        * Besides that, we want to return different error code
+                        * to state that supplied value is not valid.
+                        */
+                       ngpios = 0;
+               else if (ret)
+                       return ret;
+
+               gc->ngpio = ngpios;
+       }
+
+       if (gc->ngpio == 0) {
+               chip_err(gc, "tried to insert a GPIO chip with zero lines\n");
+               return -EINVAL;
+       }
+
+       if (gc->ngpio > FASTPATH_NGPIO)
+               chip_warn(gc, "line cnt %u is greater than fast path cnt %u\n",
+                       gc->ngpio, FASTPATH_NGPIO);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gpiochip_get_ngpios);
+
 int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
                               struct lock_class_key *lock_key,
                               struct lock_class_key *request_key)
@@ -707,7 +741,6 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
        struct gpio_device *gdev;
        unsigned long flags;
        unsigned int i;
-       u32 ngpios = 0;
        int base = 0;
        int ret = 0;
 
@@ -753,36 +786,9 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
        else
                gdev->owner = THIS_MODULE;
 
-       /*
-        * Try the device properties if the driver didn't supply the number
-        * of GPIO lines.
-        */
-       ngpios = gc->ngpio;
-       if (ngpios == 0) {
-               ret = device_property_read_u32(&gdev->dev, "ngpios", &ngpios);
-               if (ret == -ENODATA)
-                       /*
-                        * -ENODATA means that there is no property found and
-                        * we want to issue the error message to the user.
-                        * Besides that, we want to return different error code
-                        * to state that supplied value is not valid.
-                        */
-                       ngpios = 0;
-               else if (ret)
-                       goto err_free_dev_name;
-
-               gc->ngpio = ngpios;
-       }
-
-       if (gc->ngpio == 0) {
-               chip_err(gc, "tried to insert a GPIO chip with zero lines\n");
-               ret = -EINVAL;
+       ret = gpiochip_get_ngpios(gc, &gdev->dev);
+       if (ret)
                goto err_free_dev_name;
-       }
-
-       if (gc->ngpio > FASTPATH_NGPIO)
-               chip_warn(gc, "line cnt %u is greater than fast path cnt %u\n",
-                         gc->ngpio, FASTPATH_NGPIO);
 
        gdev->descs = kcalloc(gc->ngpio, sizeof(*gdev->descs), GFP_KERNEL);
        if (!gdev->descs) {
@@ -947,7 +953,7 @@ err_print_message:
        /* failures here can mean systems won't boot... */
        if (ret != -EPROBE_DEFER) {
                pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
-                      base, base + (int)ngpios - 1,
+                      base, base + (int)gc->ngpio - 1,
                       gc->label ? : "generic", ret);
        }
        return ret;
index 7c562fbb9fb09ff99ebf6f507491f93238811034..08e8e827488390af42ccbd6327ebd14a8100113f 100644 (file)
@@ -218,6 +218,7 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
 int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce);
 int gpiod_hog(struct gpio_desc *desc, const char *name,
                unsigned long lflags, enum gpiod_flags dflags);
+int gpiochip_get_ngpios(struct gpio_chip *gc, struct device *dev);
 
 /*
  * Return the GPIO number of the passed descriptor relative to its chip