ARM: plat-versatile: move FPGA irq driver to drivers/irqchip
authorLinus Walleij <linus.walleij@linaro.org>
Wed, 31 Oct 2012 21:04:31 +0000 (22:04 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Sun, 4 Nov 2012 17:09:12 +0000 (18:09 +0100)
This moves the Versatile FPGA interrupt controller driver, used in
the Integrator/AP, Integrator/CP and some Versatile boards, out
of arch/arm/plat-versatile and down to drivers/irqchip where we
have consensus that such drivers belong. The header file is
consequently moved to <linux/platform_data/irq-versatile-fpga.h>.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
12 files changed:
arch/arm/Kconfig
arch/arm/mach-integrator/integrator_ap.c
arch/arm/mach-integrator/integrator_cp.c
arch/arm/mach-versatile/core.c
arch/arm/plat-versatile/Kconfig
arch/arm/plat-versatile/Makefile
arch/arm/plat-versatile/fpga-irq.c [deleted file]
arch/arm/plat-versatile/include/plat/fpga-irq.h [deleted file]
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/irq-versatile-fpga.c [new file with mode: 0644]
include/linux/irqchip/versatile-fpga.h [new file with mode: 0644]

index 73067efd484530d4021a220fecce329b4752b3c0..2205e3eb55bfa43c639fd23d398a3fc732c51edf 100644 (file)
@@ -284,8 +284,8 @@ config ARCH_INTEGRATOR
        select MULTI_IRQ_HANDLER
        select NEED_MACH_MEMORY_H
        select PLAT_VERSATILE
-       select PLAT_VERSATILE_FPGA_IRQ
        select SPARSE_IRQ
+       select VERSATILE_FPGA_IRQ
        help
          Support for ARM's Integrator platform.
 
@@ -318,7 +318,7 @@ config ARCH_VERSATILE
        select PLAT_VERSATILE
        select PLAT_VERSATILE_CLCD
        select PLAT_VERSATILE_CLOCK
-       select PLAT_VERSATILE_FPGA_IRQ
+       select VERSATILE_FPGA_IRQ
        help
          This enables support for ARM Ltd Versatile board.
 
index 4f13bc57e5a46104b85b925daa02dd3c70461529..e67a9fe18d1b89f5a2eac667394be99ce4c3cdce 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/irqchip/versatile-fpga.h>
 #include <linux/mtd/physmap.h>
 #include <linux/clk.h>
 #include <linux/platform_data/clk-integrator.h>
@@ -56,8 +57,6 @@
 #include <asm/mach/pci.h>
 #include <asm/mach/time.h>
 
-#include <plat/fpga-irq.h>
-
 #include "common.h"
 
 /* 
index 4423bc8e84c5911726554525a7020828664ff831..acecf04f50f75148b09611d7e8d46a303c98f5a5 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/amba/clcd.h>
 #include <linux/amba/mmci.h>
 #include <linux/io.h>
+#include <linux/irqchip/versatile-fpga.h>
 #include <linux/gfp.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_data/clk-integrator.h>
@@ -46,7 +47,6 @@
 #include <asm/hardware/timer-sp.h>
 
 #include <plat/clcd.h>
-#include <plat/fpga-irq.h>
 #include <plat/sched_clock.h>
 
 #include "common.h"
index 5b5c1eeb5b5c1c0d7517ba2b3c9849b07e045bdd..5d5929450366a894aa2abea0ecee82113c75ac67 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/amba/mmci.h>
 #include <linux/amba/pl022.h>
 #include <linux/io.h>
+#include <linux/irqchip/versatile-fpga.h>
 #include <linux/gfp.h>
 #include <linux/clkdev.h>
 #include <linux/mtd/physmap.h>
@@ -51,7 +52,6 @@
 #include <asm/hardware/timer-sp.h>
 
 #include <plat/clcd.h>
-#include <plat/fpga-irq.h>
 #include <plat/sched_clock.h>
 
 #include "core.h"
index 2a4ae8a6a08116466d5aa60662ceeb2e92f7ed2a..619f0fa0f06c135b22602027d3cc87b6f970ab8e 100644 (file)
@@ -6,15 +6,6 @@ config PLAT_VERSATILE_CLOCK
 config PLAT_VERSATILE_CLCD
        bool
 
-config PLAT_VERSATILE_FPGA_IRQ
-       bool
-       select IRQ_DOMAIN
-
-config PLAT_VERSATILE_FPGA_IRQ_NR
-       int
-       default 4
-       depends on PLAT_VERSATILE_FPGA_IRQ
-
 config PLAT_VERSATILE_LEDS
        def_bool y if NEW_LEDS
        depends on ARCH_REALVIEW || ARCH_VERSATILE
index 74cfd94cbf80b31a54d225120efec7505fc76112..f88d448b629caa43171f63b5c9bd9d9cf4bd1df0 100644 (file)
@@ -2,7 +2,6 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include
 
 obj-$(CONFIG_PLAT_VERSATILE_CLOCK) += clock.o
 obj-$(CONFIG_PLAT_VERSATILE_CLCD) += clcd.o
-obj-$(CONFIG_PLAT_VERSATILE_FPGA_IRQ) += fpga-irq.o
 obj-$(CONFIG_PLAT_VERSATILE_LEDS) += leds.o
 obj-$(CONFIG_PLAT_VERSATILE_SCHED_CLOCK) += sched-clock.o
 obj-$(CONFIG_SMP) += headsmp.o platsmp.o
diff --git a/arch/arm/plat-versatile/fpga-irq.c b/arch/arm/plat-versatile/fpga-irq.c
deleted file mode 100644 (file)
index dfe317c..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- *  Support for Versatile FPGA-based IRQ controllers
- */
-#include <linux/bitops.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/irqdomain.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-
-#include <asm/exception.h>
-#include <asm/mach/irq.h>
-#include <plat/fpga-irq.h>
-
-#define IRQ_STATUS             0x00
-#define IRQ_RAW_STATUS         0x04
-#define IRQ_ENABLE_SET         0x08
-#define IRQ_ENABLE_CLEAR       0x0c
-#define INT_SOFT_SET           0x10
-#define INT_SOFT_CLEAR         0x14
-#define FIQ_STATUS             0x20
-#define FIQ_RAW_STATUS         0x24
-#define FIQ_ENABLE             0x28
-#define FIQ_ENABLE_SET         0x28
-#define FIQ_ENABLE_CLEAR       0x2C
-
-/**
- * struct fpga_irq_data - irq data container for the FPGA IRQ controller
- * @base: memory offset in virtual memory
- * @chip: chip container for this instance
- * @domain: IRQ domain for this instance
- * @valid: mask for valid IRQs on this controller
- * @used_irqs: number of active IRQs on this controller
- */
-struct fpga_irq_data {
-       void __iomem *base;
-       struct irq_chip chip;
-       u32 valid;
-       struct irq_domain *domain;
-       u8 used_irqs;
-};
-
-/* we cannot allocate memory when the controllers are initially registered */
-static struct fpga_irq_data fpga_irq_devices[CONFIG_PLAT_VERSATILE_FPGA_IRQ_NR];
-static int fpga_irq_id;
-
-static void fpga_irq_mask(struct irq_data *d)
-{
-       struct fpga_irq_data *f = irq_data_get_irq_chip_data(d);
-       u32 mask = 1 << d->hwirq;
-
-       writel(mask, f->base + IRQ_ENABLE_CLEAR);
-}
-
-static void fpga_irq_unmask(struct irq_data *d)
-{
-       struct fpga_irq_data *f = irq_data_get_irq_chip_data(d);
-       u32 mask = 1 << d->hwirq;
-
-       writel(mask, f->base + IRQ_ENABLE_SET);
-}
-
-static void fpga_irq_handle(unsigned int irq, struct irq_desc *desc)
-{
-       struct fpga_irq_data *f = irq_desc_get_handler_data(desc);
-       u32 status = readl(f->base + IRQ_STATUS);
-
-       if (status == 0) {
-               do_bad_IRQ(irq, desc);
-               return;
-       }
-
-       do {
-               irq = ffs(status) - 1;
-               status &= ~(1 << irq);
-               generic_handle_irq(irq_find_mapping(f->domain, irq));
-       } while (status);
-}
-
-/*
- * Handle each interrupt in a single FPGA IRQ controller.  Returns non-zero
- * if we've handled at least one interrupt.  This does a single read of the
- * status register and handles all interrupts in order from LSB first.
- */
-static int handle_one_fpga(struct fpga_irq_data *f, struct pt_regs *regs)
-{
-       int handled = 0;
-       int irq;
-       u32 status;
-
-       while ((status  = readl(f->base + IRQ_STATUS))) {
-               irq = ffs(status) - 1;
-               handle_IRQ(irq_find_mapping(f->domain, irq), regs);
-               handled = 1;
-       }
-
-       return handled;
-}
-
-/*
- * Keep iterating over all registered FPGA IRQ controllers until there are
- * no pending interrupts.
- */
-asmlinkage void __exception_irq_entry fpga_handle_irq(struct pt_regs *regs)
-{
-       int i, handled;
-
-       do {
-               for (i = 0, handled = 0; i < fpga_irq_id; ++i)
-                       handled |= handle_one_fpga(&fpga_irq_devices[i], regs);
-       } while (handled);
-}
-
-static int fpga_irqdomain_map(struct irq_domain *d, unsigned int irq,
-               irq_hw_number_t hwirq)
-{
-       struct fpga_irq_data *f = d->host_data;
-
-       /* Skip invalid IRQs, only register handlers for the real ones */
-       if (!(f->valid & BIT(hwirq)))
-               return -ENOTSUPP;
-       irq_set_chip_data(irq, f);
-       irq_set_chip_and_handler(irq, &f->chip,
-                               handle_level_irq);
-       set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-       return 0;
-}
-
-static struct irq_domain_ops fpga_irqdomain_ops = {
-       .map = fpga_irqdomain_map,
-       .xlate = irq_domain_xlate_onetwocell,
-};
-
-void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start,
-                         int parent_irq, u32 valid, struct device_node *node)
-{
-       struct fpga_irq_data *f;
-       int i;
-
-       if (fpga_irq_id >= ARRAY_SIZE(fpga_irq_devices)) {
-               pr_err("%s: too few FPGA IRQ controllers, increase CONFIG_PLAT_VERSATILE_FPGA_IRQ_NR\n", __func__);
-               return;
-       }
-       f = &fpga_irq_devices[fpga_irq_id];
-       f->base = base;
-       f->chip.name = name;
-       f->chip.irq_ack = fpga_irq_mask;
-       f->chip.irq_mask = fpga_irq_mask;
-       f->chip.irq_unmask = fpga_irq_unmask;
-       f->valid = valid;
-
-       if (parent_irq != -1) {
-               irq_set_handler_data(parent_irq, f);
-               irq_set_chained_handler(parent_irq, fpga_irq_handle);
-       }
-
-       /* This will also allocate irq descriptors */
-       f->domain = irq_domain_add_simple(node, fls(valid), irq_start,
-                                         &fpga_irqdomain_ops, f);
-
-       /* This will allocate all valid descriptors in the linear case */
-       for (i = 0; i < fls(valid); i++)
-               if (valid & BIT(i)) {
-                       if (!irq_start)
-                               irq_create_mapping(f->domain, i);
-                       f->used_irqs++;
-               }
-
-       pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n",
-               fpga_irq_id, name, base, f->used_irqs);
-
-       fpga_irq_id++;
-}
-
-#ifdef CONFIG_OF
-int __init fpga_irq_of_init(struct device_node *node,
-                           struct device_node *parent)
-{
-       struct fpga_irq_data *f;
-       void __iomem *base;
-       u32 clear_mask;
-       u32 valid_mask;
-
-       if (WARN_ON(!node))
-               return -ENODEV;
-
-       base = of_iomap(node, 0);
-       WARN(!base, "unable to map fpga irq registers\n");
-
-       if (of_property_read_u32(node, "clear-mask", &clear_mask))
-               clear_mask = 0;
-
-       if (of_property_read_u32(node, "valid-mask", &valid_mask))
-               valid_mask = 0;
-
-       fpga_irq_init(base, node->name, 0, -1, valid_mask, node);
-
-       writel(clear_mask, base + IRQ_ENABLE_CLEAR);
-       writel(clear_mask, base + FIQ_ENABLE_CLEAR);
-
-       return 0;
-}
-#endif
diff --git a/arch/arm/plat-versatile/include/plat/fpga-irq.h b/arch/arm/plat-versatile/include/plat/fpga-irq.h
deleted file mode 100644 (file)
index 1fac965..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef PLAT_FPGA_IRQ_H
-#define PLAT_FPGA_IRQ_H
-
-struct device_node;
-struct pt_regs;
-
-void fpga_handle_irq(struct pt_regs *regs);
-void fpga_irq_init(void __iomem *, const char *, int, int, u32,
-               struct device_node *node);
-int fpga_irq_of_init(struct device_node *node,
-                    struct device_node *parent);
-
-#endif
index 1bb8bf6d7fd4c8d09aea89b47de20fb8bbb61626..62ca575701d34752d1cdd7c9c0ff699d9e8c6749 100644 (file)
@@ -1 +1,8 @@
-# empty
+config VERSATILE_FPGA_IRQ
+       bool
+       select IRQ_DOMAIN
+
+config VERSATILE_FPGA_IRQ_NR
+       int
+       default 4
+       depends on VERSATILE_FPGA_IRQ
index 054321db4350476f81260b9ca62a38ba7302fb20..e2e6eb5d32f4a9c250506119a5ec8b5711d3a8db 100644 (file)
@@ -1 +1,2 @@
 obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
+obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o
diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c
new file mode 100644 (file)
index 0000000..789b3e5
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ *  Support for Versatile FPGA-based IRQ controllers
+ */
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/irqchip/versatile-fpga.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <asm/exception.h>
+#include <asm/mach/irq.h>
+
+#define IRQ_STATUS             0x00
+#define IRQ_RAW_STATUS         0x04
+#define IRQ_ENABLE_SET         0x08
+#define IRQ_ENABLE_CLEAR       0x0c
+#define INT_SOFT_SET           0x10
+#define INT_SOFT_CLEAR         0x14
+#define FIQ_STATUS             0x20
+#define FIQ_RAW_STATUS         0x24
+#define FIQ_ENABLE             0x28
+#define FIQ_ENABLE_SET         0x28
+#define FIQ_ENABLE_CLEAR       0x2C
+
+/**
+ * struct fpga_irq_data - irq data container for the FPGA IRQ controller
+ * @base: memory offset in virtual memory
+ * @chip: chip container for this instance
+ * @domain: IRQ domain for this instance
+ * @valid: mask for valid IRQs on this controller
+ * @used_irqs: number of active IRQs on this controller
+ */
+struct fpga_irq_data {
+       void __iomem *base;
+       struct irq_chip chip;
+       u32 valid;
+       struct irq_domain *domain;
+       u8 used_irqs;
+};
+
+/* we cannot allocate memory when the controllers are initially registered */
+static struct fpga_irq_data fpga_irq_devices[CONFIG_VERSATILE_FPGA_IRQ_NR];
+static int fpga_irq_id;
+
+static void fpga_irq_mask(struct irq_data *d)
+{
+       struct fpga_irq_data *f = irq_data_get_irq_chip_data(d);
+       u32 mask = 1 << d->hwirq;
+
+       writel(mask, f->base + IRQ_ENABLE_CLEAR);
+}
+
+static void fpga_irq_unmask(struct irq_data *d)
+{
+       struct fpga_irq_data *f = irq_data_get_irq_chip_data(d);
+       u32 mask = 1 << d->hwirq;
+
+       writel(mask, f->base + IRQ_ENABLE_SET);
+}
+
+static void fpga_irq_handle(unsigned int irq, struct irq_desc *desc)
+{
+       struct fpga_irq_data *f = irq_desc_get_handler_data(desc);
+       u32 status = readl(f->base + IRQ_STATUS);
+
+       if (status == 0) {
+               do_bad_IRQ(irq, desc);
+               return;
+       }
+
+       do {
+               irq = ffs(status) - 1;
+               status &= ~(1 << irq);
+               generic_handle_irq(irq_find_mapping(f->domain, irq));
+       } while (status);
+}
+
+/*
+ * Handle each interrupt in a single FPGA IRQ controller.  Returns non-zero
+ * if we've handled at least one interrupt.  This does a single read of the
+ * status register and handles all interrupts in order from LSB first.
+ */
+static int handle_one_fpga(struct fpga_irq_data *f, struct pt_regs *regs)
+{
+       int handled = 0;
+       int irq;
+       u32 status;
+
+       while ((status  = readl(f->base + IRQ_STATUS))) {
+               irq = ffs(status) - 1;
+               handle_IRQ(irq_find_mapping(f->domain, irq), regs);
+               handled = 1;
+       }
+
+       return handled;
+}
+
+/*
+ * Keep iterating over all registered FPGA IRQ controllers until there are
+ * no pending interrupts.
+ */
+asmlinkage void __exception_irq_entry fpga_handle_irq(struct pt_regs *regs)
+{
+       int i, handled;
+
+       do {
+               for (i = 0, handled = 0; i < fpga_irq_id; ++i)
+                       handled |= handle_one_fpga(&fpga_irq_devices[i], regs);
+       } while (handled);
+}
+
+static int fpga_irqdomain_map(struct irq_domain *d, unsigned int irq,
+               irq_hw_number_t hwirq)
+{
+       struct fpga_irq_data *f = d->host_data;
+
+       /* Skip invalid IRQs, only register handlers for the real ones */
+       if (!(f->valid & BIT(hwirq)))
+               return -ENOTSUPP;
+       irq_set_chip_data(irq, f);
+       irq_set_chip_and_handler(irq, &f->chip,
+                               handle_level_irq);
+       set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+       return 0;
+}
+
+static struct irq_domain_ops fpga_irqdomain_ops = {
+       .map = fpga_irqdomain_map,
+       .xlate = irq_domain_xlate_onetwocell,
+};
+
+void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start,
+                         int parent_irq, u32 valid, struct device_node *node)
+{
+       struct fpga_irq_data *f;
+       int i;
+
+       if (fpga_irq_id >= ARRAY_SIZE(fpga_irq_devices)) {
+               pr_err("%s: too few FPGA IRQ controllers, increase CONFIG_PLAT_VERSATILE_FPGA_IRQ_NR\n", __func__);
+               return;
+       }
+       f = &fpga_irq_devices[fpga_irq_id];
+       f->base = base;
+       f->chip.name = name;
+       f->chip.irq_ack = fpga_irq_mask;
+       f->chip.irq_mask = fpga_irq_mask;
+       f->chip.irq_unmask = fpga_irq_unmask;
+       f->valid = valid;
+
+       if (parent_irq != -1) {
+               irq_set_handler_data(parent_irq, f);
+               irq_set_chained_handler(parent_irq, fpga_irq_handle);
+       }
+
+       /* This will also allocate irq descriptors */
+       f->domain = irq_domain_add_simple(node, fls(valid), irq_start,
+                                         &fpga_irqdomain_ops, f);
+
+       /* This will allocate all valid descriptors in the linear case */
+       for (i = 0; i < fls(valid); i++)
+               if (valid & BIT(i)) {
+                       if (!irq_start)
+                               irq_create_mapping(f->domain, i);
+                       f->used_irqs++;
+               }
+
+       pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n",
+               fpga_irq_id, name, base, f->used_irqs);
+
+       fpga_irq_id++;
+}
+
+#ifdef CONFIG_OF
+int __init fpga_irq_of_init(struct device_node *node,
+                           struct device_node *parent)
+{
+       struct fpga_irq_data *f;
+       void __iomem *base;
+       u32 clear_mask;
+       u32 valid_mask;
+
+       if (WARN_ON(!node))
+               return -ENODEV;
+
+       base = of_iomap(node, 0);
+       WARN(!base, "unable to map fpga irq registers\n");
+
+       if (of_property_read_u32(node, "clear-mask", &clear_mask))
+               clear_mask = 0;
+
+       if (of_property_read_u32(node, "valid-mask", &valid_mask))
+               valid_mask = 0;
+
+       fpga_irq_init(base, node->name, 0, -1, valid_mask, node);
+
+       writel(clear_mask, base + IRQ_ENABLE_CLEAR);
+       writel(clear_mask, base + FIQ_ENABLE_CLEAR);
+
+       return 0;
+}
+#endif
diff --git a/include/linux/irqchip/versatile-fpga.h b/include/linux/irqchip/versatile-fpga.h
new file mode 100644 (file)
index 0000000..1fac965
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef PLAT_FPGA_IRQ_H
+#define PLAT_FPGA_IRQ_H
+
+struct device_node;
+struct pt_regs;
+
+void fpga_handle_irq(struct pt_regs *regs);
+void fpga_irq_init(void __iomem *, const char *, int, int, u32,
+               struct device_node *node);
+int fpga_irq_of_init(struct device_node *node,
+                    struct device_node *parent);
+
+#endif