]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
gpio: vf610: Switch to gpio-mmio
authorLinus Walleij <linus.walleij@linaro.org>
Wed, 19 Feb 2025 21:04:34 +0000 (22:04 +0100)
committerBartosz Golaszewski <bartosz.golaszewski@linaro.org>
Mon, 24 Feb 2025 19:49:43 +0000 (20:49 +0100)
After adding a pinctrl flag to gpio-mmio we can use it
for driving gpio-vf610.

The existing code has the same semantics and the generic
gpio-mmio, including reading from the data out register
when the direction is set to input, and it can also handle
the absence of the direction register better than the
current driver: we get the direction from the shadow
direction registers in gpio-mmio instead.

Since gpio-mmio has an internal spinlock we can drop the
direction-protecting spinlock from the driver.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Haibo Chen <haibo.chen@nxp.com>
Tested-by: Haibo Chen <haibo.chen@nxp.com>
Link: https://lore.kernel.org/r/20250219-vf610-mmio-v3-2-588b64f0b689@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
drivers/gpio/Kconfig
drivers/gpio/gpio-vf610.c

index 06cc9b826483db9d5125b6ecf4fe9da7baafe3df..3e9b174fee84142a8b50cdca5b967671eeda6dd3 100644 (file)
@@ -757,6 +757,7 @@ config GPIO_VF610
        default y if SOC_VF610
        depends on ARCH_MXC || COMPILE_TEST
        select GPIOLIB_IRQCHIP
+       select GPIO_GENERIC
        help
          Say yes here to support i.MX or Vybrid vf610 GPIOs.
 
index c36a9dbccd4dd5415ed3b90b87afb47e7634c025..4dad7ce0c4dc6a3f412081c7502c0ce6dd5740da 100644 (file)
@@ -36,7 +36,6 @@ struct vf610_gpio_port {
        struct clk *clk_port;
        struct clk *clk_gpio;
        int irq;
-       spinlock_t lock; /* protect gpio direction registers */
 };
 
 #define GPIO_PDOR              0x00
@@ -94,78 +93,6 @@ static inline u32 vf610_gpio_readl(void __iomem *reg)
        return readl_relaxed(reg);
 }
 
-static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio)
-{
-       struct vf610_gpio_port *port = gpiochip_get_data(gc);
-       u32 mask = BIT(gpio);
-       unsigned long offset = GPIO_PDIR;
-
-       if (port->sdata->have_paddr) {
-               mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
-               if (mask)
-                       offset = GPIO_PDOR;
-       }
-
-       return !!(vf610_gpio_readl(port->gpio_base + offset) & BIT(gpio));
-}
-
-static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
-{
-       struct vf610_gpio_port *port = gpiochip_get_data(gc);
-       u32 mask = BIT(gpio);
-       unsigned long offset = val ? GPIO_PSOR : GPIO_PCOR;
-
-       vf610_gpio_writel(mask, port->gpio_base + offset);
-}
-
-static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
-{
-       struct vf610_gpio_port *port = gpiochip_get_data(chip);
-       u32 mask = BIT(gpio);
-       u32 val;
-
-       if (port->sdata->have_paddr) {
-               guard(spinlock_irqsave)(&port->lock);
-               val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
-               val &= ~mask;
-               vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR);
-       }
-
-       return pinctrl_gpio_direction_input(chip, gpio);
-}
-
-static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
-                                      int value)
-{
-       struct vf610_gpio_port *port = gpiochip_get_data(chip);
-       u32 mask = BIT(gpio);
-       u32 val;
-
-       vf610_gpio_set(chip, gpio, value);
-
-       if (port->sdata->have_paddr) {
-               guard(spinlock_irqsave)(&port->lock);
-               val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
-               val |= mask;
-               vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR);
-       }
-
-       return pinctrl_gpio_direction_output(chip, gpio);
-}
-
-static int vf610_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
-{
-       struct vf610_gpio_port *port = gpiochip_get_data(gc);
-       u32 mask = BIT(gpio);
-
-       mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
-
-       if (mask)
-               return GPIO_LINE_DIRECTION_OUT;
-
-       return GPIO_LINE_DIRECTION_IN;
-}
-
 static void vf610_gpio_irq_handler(struct irq_desc *desc)
 {
        struct vf610_gpio_port *port =
@@ -291,6 +218,7 @@ static int vf610_gpio_probe(struct platform_device *pdev)
        struct vf610_gpio_port *port;
        struct gpio_chip *gc;
        struct gpio_irq_chip *girq;
+       unsigned long flags;
        int i;
        int ret;
        bool dual_base;
@@ -300,7 +228,6 @@ static int vf610_gpio_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        port->sdata = device_get_match_data(dev);
-       spin_lock_init(&port->lock);
 
        dual_base = port->sdata->have_dual_base;
 
@@ -367,23 +294,25 @@ static int vf610_gpio_probe(struct platform_device *pdev)
        }
 
        gc = &port->gc;
-       gc->parent = dev;
-       gc->label = dev_name(dev);
-       gc->ngpio = VF610_GPIO_PER_PORT;
-       gc->base = -1;
-
-       gc->request = gpiochip_generic_request;
-       gc->free = gpiochip_generic_free;
-       gc->direction_input = vf610_gpio_direction_input;
-       gc->get = vf610_gpio_get;
-       gc->direction_output = vf610_gpio_direction_output;
-       gc->set = vf610_gpio_set;
+       flags = BGPIOF_PINCTRL_BACKEND;
        /*
-        * only IP has Port Data Direction Register(PDDR) can
-        * support get direction
+        * We only read the output register for current value on output
+        * lines if the direction register is available so we can switch
+        * direction.
         */
        if (port->sdata->have_paddr)
-               gc->get_direction = vf610_gpio_get_direction;
+               flags |= BGPIOF_READ_OUTPUT_REG_SET;
+       ret = bgpio_init(gc, dev, 4,
+                        port->gpio_base + GPIO_PDIR,
+                        port->gpio_base + GPIO_PDOR,
+                        NULL,
+                        port->sdata->have_paddr ? port->gpio_base + GPIO_PDDR : NULL,
+                        NULL,
+                        flags);
+       if (ret)
+               return dev_err_probe(dev, ret, "unable to init generic GPIO\n");
+       gc->label = dev_name(dev);
+       gc->base = -1;
 
        /* Mask all GPIO interrupts */
        for (i = 0; i < gc->ngpio; i++)