]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
gpio: altera: Use generic MMIO GPIO
authorLinus Walleij <linus.walleij@linaro.org>
Mon, 27 Apr 2026 08:47:59 +0000 (10:47 +0200)
committerBartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Mon, 4 May 2026 07:32:54 +0000 (09:32 +0200)
If we use the generic GPIO lib for MMIO in the Altera driver
we do not only cut down on the code, we also get get/set_multiple
for free.

Keep the local raw spinlock instead of reusing the bgpio spinlock
because it makes the gpiochip and irqchip nicely orthogonal.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://patch.msgid.link/20260427-gpio-mmio-more-v3-3-fe1882351424@kernel.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
drivers/gpio/Kconfig
drivers/gpio/gpio-altera.c

index f86e25da964bff4269790dd92f7bf49a7085bffb..c56b00d77bf39c4a37ca4bb20a992908f080b8d9 100644 (file)
@@ -156,6 +156,7 @@ config GPIO_74XX_MMIO
 
 config GPIO_ALTERA
        tristate "Altera GPIO"
+       select GPIO_GENERIC
        select GPIOLIB_IRQCHIP
        help
          Say Y or M here to build support for the Altera PIO device.
index cb04700c8ccd8b5d82587620ed54e35fbe32b17c..fe144360a88d82ef4739d679d0c0007cd9960182 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/types.h>
 
 #include <linux/gpio/driver.h>
+#include <linux/gpio/generic.h>
 
 #define ALTERA_GPIO_MAX_NGPIO          32
 #define ALTERA_GPIO_DATA               0x0
@@ -26,7 +27,7 @@
 
 /**
 * struct altera_gpio_chip
-* @gc                  : GPIO chip structure.
+* @chip                        : Generic GPIO chip structure.
 * @regs                        : memory mapped IO address for the controller registers.
 * @gpio_lock           : synchronization lock so that new irq/set/get requests
 *                        will be blocked until the current one completes.
@@ -34,7 +35,7 @@
 *                        (rising, falling, both, high)
 */
 struct altera_gpio_chip {
-       struct gpio_chip gc;
+       struct gpio_generic_chip chip;
        void __iomem *regs;
        raw_spinlock_t gpio_lock;
        int interrupt_trigger;
@@ -106,72 +107,6 @@ static unsigned int altera_gpio_irq_startup(struct irq_data *d)
        return 0;
 }
 
-static int altera_gpio_get(struct gpio_chip *gc, unsigned offset)
-{
-       struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
-
-       return !!(readl(altera_gc->regs + ALTERA_GPIO_DATA) & BIT(offset));
-}
-
-static int altera_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
-{
-       struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
-       unsigned long flags;
-       unsigned int data_reg;
-
-       raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
-       data_reg = readl(altera_gc->regs + ALTERA_GPIO_DATA);
-       if (value)
-               data_reg |= BIT(offset);
-       else
-               data_reg &= ~BIT(offset);
-       writel(data_reg, altera_gc->regs + ALTERA_GPIO_DATA);
-       raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
-
-       return 0;
-}
-
-static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
-{
-       struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
-       unsigned long flags;
-       unsigned int gpio_ddr;
-
-       raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
-       /* Set pin as input, assumes software controlled IP */
-       gpio_ddr = readl(altera_gc->regs + ALTERA_GPIO_DIR);
-       gpio_ddr &= ~BIT(offset);
-       writel(gpio_ddr, altera_gc->regs + ALTERA_GPIO_DIR);
-       raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
-
-       return 0;
-}
-
-static int altera_gpio_direction_output(struct gpio_chip *gc,
-               unsigned offset, int value)
-{
-       struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc);
-       unsigned long flags;
-       unsigned int data_reg, gpio_ddr;
-
-       raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags);
-       /* Sets the GPIO value */
-       data_reg = readl(altera_gc->regs + ALTERA_GPIO_DATA);
-       if (value)
-               data_reg |= BIT(offset);
-       else
-               data_reg &= ~BIT(offset);
-       writel(data_reg, altera_gc->regs + ALTERA_GPIO_DATA);
-
-       /* Set pin as output, assumes software controlled IP */
-       gpio_ddr = readl(altera_gc->regs + ALTERA_GPIO_DIR);
-       gpio_ddr |= BIT(offset);
-       writel(gpio_ddr, altera_gc->regs + ALTERA_GPIO_DIR);
-       raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
-
-       return 0;
-}
-
 static void altera_gpio_irq_edge_handler(struct irq_desc *desc)
 {
        struct gpio_chip *gc = irq_desc_get_handler_data(desc);
@@ -231,9 +166,11 @@ static const struct irq_chip altera_gpio_irq_chip = {
 
 static int altera_gpio_probe(struct platform_device *pdev)
 {
+       struct gpio_generic_chip_config config;
        struct device *dev = &pdev->dev;
        int reg, ret;
        struct altera_gpio_chip *altera_gc;
+       struct gpio_generic_chip *chip;
        struct gpio_chip *gc;
        struct gpio_irq_chip *girq;
        int mapped_irq;
@@ -244,7 +181,26 @@ static int altera_gpio_probe(struct platform_device *pdev)
 
        raw_spin_lock_init(&altera_gc->gpio_lock);
 
-       gc = &altera_gc->gc;
+       altera_gc->regs = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(altera_gc->regs))
+               return dev_err_probe(dev, PTR_ERR(altera_gc->regs),
+                                    "failed to ioremap memory resource\n");
+
+       chip = &altera_gc->chip;
+
+       config = (struct gpio_generic_chip_config) {
+               .dev = dev,
+               .sz = 4,
+               .dat = altera_gc->regs + ALTERA_GPIO_DATA,
+               .set = altera_gc->regs + ALTERA_GPIO_DATA,
+               .dirout = altera_gc->regs + ALTERA_GPIO_DIR,
+       };
+
+       ret = gpio_generic_chip_init(chip, &config);
+       if (ret)
+               return dev_err_probe(dev, ret, "unable to init generic GPIO\n");
+
+       gc = &chip->gc;
 
        if (device_property_read_u32(dev, "altr,ngpio", &reg))
                /* By default assume maximum ngpio */
@@ -259,22 +215,11 @@ static int altera_gpio_probe(struct platform_device *pdev)
                gc->ngpio = ALTERA_GPIO_MAX_NGPIO;
        }
 
-       gc->direction_input     = altera_gpio_direction_input;
-       gc->direction_output    = altera_gpio_direction_output;
-       gc->get         = altera_gpio_get;
-       gc->set         = altera_gpio_set;
-       gc->owner               = THIS_MODULE;
-       gc->parent              = &pdev->dev;
-       gc->base                = -1;
-
+       gc->base = -1;
        gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", dev_fwnode(dev));
        if (!gc->label)
                return -ENOMEM;
 
-       altera_gc->regs = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(altera_gc->regs))
-               return dev_err_probe(dev, PTR_ERR(altera_gc->regs), "failed to ioremap memory resource\n");
-
        mapped_irq = platform_get_irq_optional(pdev, 0);
        if (mapped_irq < 0)
                goto skip_irq;
@@ -303,7 +248,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
        girq->parents[0] = mapped_irq;
 
 skip_irq:
-       ret = devm_gpiochip_add_data(dev, &altera_gc->gc, altera_gc);
+       ret = devm_gpiochip_add_data(dev, gc, altera_gc);
        if (ret) {
                dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n");
                return ret;