gpio: pl061: ipipe: enable pipelined interrupts
authorGilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>
Sun, 3 Dec 2017 16:17:19 +0000 (17:17 +0100)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Fri, 27 Apr 2018 09:21:34 +0000 (11:21 +0200)
drivers/gpio/gpio-pl061.c

index 6aaaab79c20579a9248c6a80a65e090ff2d692c8..bb8a14acf46e0e40d4548edcc08e33110a43575a 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/pm.h>
+#include <linux/ipipe.h>
 
 #define GPIODIR 0x400
 #define GPIOIS  0x404
@@ -50,7 +51,11 @@ struct pl061_context_save_regs {
 #endif
 
 struct pl061 {
+#ifdef CONFIG_IPIPE
+       ipipe_spinlock_t        lock;
+#else
        raw_spinlock_t          lock;
+#endif
 
        void __iomem            *base;
        struct gpio_chip        gc;
@@ -221,14 +226,30 @@ static void pl061_irq_handler(struct irq_desc *desc)
        pending = readb(pl061->base + GPIOMIS);
        if (pending) {
                for_each_set_bit(offset, &pending, PL061_GPIO_NR)
-                       generic_handle_irq(irq_find_mapping(gc->irqdomain,
-                                                           offset));
+                       ipipe_handle_demuxed_irq(irq_find_mapping(gc->irqdomain,
+                                                                 offset));
        }
 
        chained_irq_exit(irqchip, desc);
 }
 
 static void pl061_irq_mask(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct pl061 *pl061 = gpiochip_get_data(gc);
+       u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
+       unsigned long flags;
+       u8 gpioie;
+
+       raw_spin_lock_irqsave(&pl061->lock, flags);
+       gpioie = readb(pl061->base + GPIOIE) & ~mask;
+       writeb(gpioie, pl061->base + GPIOIE);
+       ipipe_lock_irq(d->irq);
+       raw_spin_unlock_irqrestore(&pl061->lock, flags);
+}
+
+#ifdef CONFIG_IPIPE
+static void pl061_irq_mask_ack(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct pl061 *pl061 = gpiochip_get_data(gc);
@@ -240,7 +261,7 @@ static void pl061_irq_mask(struct irq_data *d)
        writeb(gpioie, pl061->base + GPIOIE);
        raw_spin_unlock(&pl061->lock);
 }
-
+#endif
 static void pl061_irq_unmask(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
@@ -288,6 +309,10 @@ static struct irq_chip pl061_irqchip = {
        .irq_unmask     = pl061_irq_unmask,
        .irq_set_type   = pl061_irq_type,
        .irq_set_wake   = pl061_irq_set_wake,
+#ifdef CONFIG_IPIPE
+       .irq_mask_ack   = pl061_irq_mask_ack,
+       .flags          = IRQCHIP_PIPELINE_SAFE,
+#endif
 };
 
 static int pl061_probe(struct amba_device *adev, const struct amba_id *id)