]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
gpio: tqmx86: store IRQ trigger type and unmask status separately
authorMatthias Schiffer <matthias.schiffer@ew.tq-group.com>
Thu, 30 May 2024 10:20:01 +0000 (12:20 +0200)
committerRoxana Nicolescu <roxana.nicolescu@canonical.com>
Fri, 2 Aug 2024 14:26:52 +0000 (16:26 +0200)
BugLink: https://bugs.launchpad.net/bugs/2074091
[ Upstream commit 08af509efdf8dad08e972b48de0e2c2a7919ea8b ]

irq_set_type() should not implicitly unmask the IRQ.

All accesses to the interrupt configuration register are moved to a new
helper tqmx86_gpio_irq_config(). We also introduce the new rule that
accessing irq_type must happen while locked, which will become
significant for fixing EDGE_BOTH handling.

Fixes: b868db94a6a7 ("gpio: tqmx86: Add GPIO from for this IO controller")
Signed-off-by: Matthias Schiffer <matthias.schiffer@ew.tq-group.com>
Link: https://lore.kernel.org/r/6aa4f207f77cb58ef64ffb947e91949b0f753ccd.1717063994.git.matthias.schiffer@ew.tq-group.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Portia Stephens <portia.stephens@canonical.com>
Signed-off-by: Roxana Nicolescu <roxana.nicolescu@canonical.com>
drivers/gpio/gpio-tqmx86.c

index b7e2dbbdc4ebe81bcf85b14db08ea8e71bdd0d7f..7e428c872a25794bc62293d6bcbbdc4a5b377a06 100644 (file)
 #define TQMX86_GPIIC   3       /* GPI Interrupt Configuration Register */
 #define TQMX86_GPIIS   4       /* GPI Interrupt Status Register */
 
+#define TQMX86_GPII_NONE       0
 #define TQMX86_GPII_FALLING    BIT(0)
 #define TQMX86_GPII_RISING     BIT(1)
 #define TQMX86_GPII_MASK       (BIT(0) | BIT(1))
 #define TQMX86_GPII_BITS       2
+/* Stored in irq_type with GPII bits */
+#define TQMX86_INT_UNMASKED    BIT(2)
 
 struct tqmx86_gpio_data {
        struct gpio_chip        chip;
        void __iomem            *io_base;
        int                     irq;
+       /* Lock must be held for accessing output and irq_type fields */
        raw_spinlock_t          spinlock;
        DECLARE_BITMAP(output, TQMX86_NGPIO);
        u8                      irq_type[TQMX86_NGPI];
@@ -104,21 +108,32 @@ static int tqmx86_gpio_get_direction(struct gpio_chip *chip,
        return GPIO_LINE_DIRECTION_OUT;
 }
 
+static void tqmx86_gpio_irq_config(struct tqmx86_gpio_data *gpio, int offset)
+       __must_hold(&gpio->spinlock)
+{
+       u8 type = TQMX86_GPII_NONE, gpiic;
+
+       if (gpio->irq_type[offset] & TQMX86_INT_UNMASKED)
+               type = gpio->irq_type[offset] & TQMX86_GPII_MASK;
+
+       gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC);
+       gpiic &= ~(TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS));
+       gpiic |= type << (offset * TQMX86_GPII_BITS);
+       tqmx86_gpio_write(gpio, gpiic, TQMX86_GPIIC);
+}
+
 static void tqmx86_gpio_irq_mask(struct irq_data *data)
 {
        unsigned int offset = (data->hwirq - TQMX86_NGPO);
        struct tqmx86_gpio_data *gpio = gpiochip_get_data(
                irq_data_get_irq_chip_data(data));
        unsigned long flags;
-       u8 gpiic, mask;
-
-       mask = TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS);
 
        raw_spin_lock_irqsave(&gpio->spinlock, flags);
-       gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC);
-       gpiic &= ~mask;
-       tqmx86_gpio_write(gpio, gpiic, TQMX86_GPIIC);
+       gpio->irq_type[offset] &= ~TQMX86_INT_UNMASKED;
+       tqmx86_gpio_irq_config(gpio, offset);
        raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
+
        gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(data));
 }
 
@@ -128,16 +143,12 @@ static void tqmx86_gpio_irq_unmask(struct irq_data *data)
        struct tqmx86_gpio_data *gpio = gpiochip_get_data(
                irq_data_get_irq_chip_data(data));
        unsigned long flags;
-       u8 gpiic, mask;
-
-       mask = TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS);
 
        gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(data));
+
        raw_spin_lock_irqsave(&gpio->spinlock, flags);
-       gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC);
-       gpiic &= ~mask;
-       gpiic |= gpio->irq_type[offset] << (offset * TQMX86_GPII_BITS);
-       tqmx86_gpio_write(gpio, gpiic, TQMX86_GPIIC);
+       gpio->irq_type[offset] |= TQMX86_INT_UNMASKED;
+       tqmx86_gpio_irq_config(gpio, offset);
        raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
 }
 
@@ -148,7 +159,7 @@ static int tqmx86_gpio_irq_set_type(struct irq_data *data, unsigned int type)
        unsigned int offset = (data->hwirq - TQMX86_NGPO);
        unsigned int edge_type = type & IRQF_TRIGGER_MASK;
        unsigned long flags;
-       u8 new_type, gpiic;
+       u8 new_type;
 
        switch (edge_type) {
        case IRQ_TYPE_EDGE_RISING:
@@ -164,13 +175,10 @@ static int tqmx86_gpio_irq_set_type(struct irq_data *data, unsigned int type)
                return -EINVAL; /* not supported */
        }
 
-       gpio->irq_type[offset] = new_type;
-
        raw_spin_lock_irqsave(&gpio->spinlock, flags);
-       gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC);
-       gpiic &= ~((TQMX86_GPII_MASK) << (offset * TQMX86_GPII_BITS));
-       gpiic |= new_type << (offset * TQMX86_GPII_BITS);
-       tqmx86_gpio_write(gpio, gpiic, TQMX86_GPIIC);
+       gpio->irq_type[offset] &= ~TQMX86_GPII_MASK;
+       gpio->irq_type[offset] |= new_type;
+       tqmx86_gpio_irq_config(gpio, offset);
        raw_spin_unlock_irqrestore(&gpio->spinlock, flags);
 
        return 0;