]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
gpio: mmio: Add flag for calling pinctrl back-end
authorLinus Walleij <linus.walleij@linaro.org>
Wed, 19 Feb 2025 21:04:33 +0000 (22:04 +0100)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Mon, 24 Feb 2025 19:49:20 +0000 (20:49 +0100)
It turns out that with this flag we can switch over an entire
driver to use gpio-mmio instead of a bunch of custom code,
also providing get/set_multiple() to it in the process, so it
seems like a reasonable feature to add.

The generic pin control backend requires us to call the
gpiochip_generic_request(), gpiochip_generic_free(),
pinctrl_gpio_direction_output() and pinctrl_gpio_direction_input()
callbacks, so if the new flag for a pin control back-end
is set, we make sure these functions get called as
expected.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20250219-vf610-mmio-v3-1-588b64f0b689@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
drivers/gpio/gpio-mmio.c
include/linux/gpio/driver.h

index d89e78f0ead31f30c014b201cca4e32ecb377118..4841e4ebe7a67d0f954e9a6f995ec5758f124edd 100644 (file)
@@ -49,6 +49,7 @@ o        `                     ~~~~\___/~~~~    ` controller in FPGA is ,.`
 #include <linux/log2.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/slab.h>
@@ -323,9 +324,20 @@ static void bgpio_set_multiple_with_clear(struct gpio_chip *gc,
                gc->write_reg(gc->reg_clr, clear_mask);
 }
 
+static int bgpio_dir_return(struct gpio_chip *gc, unsigned int gpio, bool dir_out)
+{
+       if (!gc->bgpio_pinctrl)
+               return 0;
+
+       if (dir_out)
+               return pinctrl_gpio_direction_output(gc, gpio);
+       else
+               return pinctrl_gpio_direction_input(gc, gpio);
+}
+
 static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
 {
-       return 0;
+       return bgpio_dir_return(gc, gpio, false);
 }
 
 static int bgpio_dir_out_err(struct gpio_chip *gc, unsigned int gpio,
@@ -339,7 +351,7 @@ static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio,
 {
        gc->set(gc, gpio, val);
 
-       return 0;
+       return bgpio_dir_return(gc, gpio, true);
 }
 
 static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
@@ -357,7 +369,7 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
 
        raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 
-       return 0;
+       return bgpio_dir_return(gc, gpio, false);
 }
 
 static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
@@ -403,7 +415,7 @@ static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio,
 {
        bgpio_dir_out(gc, gpio, val);
        gc->set(gc, gpio, val);
-       return 0;
+       return bgpio_dir_return(gc, gpio, true);
 }
 
 static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio,
@@ -411,7 +423,7 @@ static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio,
 {
        gc->set(gc, gpio, val);
        bgpio_dir_out(gc, gpio, val);
-       return 0;
+       return bgpio_dir_return(gc, gpio, true);
 }
 
 static int bgpio_setup_accessors(struct device *dev,
@@ -562,10 +574,13 @@ static int bgpio_setup_direction(struct gpio_chip *gc,
 
 static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin)
 {
-       if (gpio_pin < chip->ngpio)
-               return 0;
+       if (gpio_pin >= chip->ngpio)
+               return -EINVAL;
 
-       return -EINVAL;
+       if (chip->bgpio_pinctrl)
+               return gpiochip_generic_request(chip, gpio_pin);
+
+       return 0;
 }
 
 /**
@@ -632,6 +647,12 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
        if (ret)
                return ret;
 
+       if (flags & BGPIOF_PINCTRL_BACKEND) {
+               gc->bgpio_pinctrl = true;
+               /* Currently this callback is only used for pincontrol */
+               gc->free = gpiochip_generic_free;
+       }
+
        gc->bgpio_data = gc->read_reg(gc->reg_dat);
        if (gc->set == bgpio_set_set &&
                        !(flags & BGPIOF_UNREADABLE_REG_SET))
index f2145e938b293cc412ac47cb0c857699c90accf0..ae96a2f260fbb63d504c4bef4e86dcc1ded75b2b 100644 (file)
@@ -397,6 +397,7 @@ struct gpio_irq_chip {
  * @reg_dir_in: direction in setting register for generic GPIO
  * @bgpio_dir_unreadable: indicates that the direction register(s) cannot
  *     be read and we need to rely on out internal state tracking.
+ * @bgpio_pinctrl: the generic GPIO uses a pin control backend.
  * @bgpio_bits: number of register bits used for a generic GPIO i.e.
  *     <register width> * 8
  * @bgpio_lock: used to lock chip->bgpio_data. Also, this is needed to keep
@@ -481,6 +482,7 @@ struct gpio_chip {
        void __iomem *reg_dir_out;
        void __iomem *reg_dir_in;
        bool bgpio_dir_unreadable;
+       bool bgpio_pinctrl;
        int bgpio_bits;
        raw_spinlock_t bgpio_lock;
        unsigned long bgpio_data;
@@ -721,6 +723,7 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
 #define BGPIOF_READ_OUTPUT_REG_SET     BIT(4) /* reg_set stores output value */
 #define BGPIOF_NO_OUTPUT               BIT(5) /* only input */
 #define BGPIOF_NO_SET_ON_INPUT         BIT(6)
+#define BGPIOF_PINCTRL_BACKEND         BIT(7) /* Call pinctrl direction setters */
 
 #ifdef CONFIG_GPIOLIB_IRQCHIP
 int gpiochip_irqchip_add_domain(struct gpio_chip *gc,