diff options
-rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt | 18 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/irqchip/irq-zevio.c | 127 |
3 files changed, 146 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt new file mode 100644 index 000000000000..aee38e7c13e7 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/lsi,zevio-intc.txt | |||
@@ -0,0 +1,18 @@ | |||
1 | TI-NSPIRE interrupt controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: Compatible property value should be "lsi,zevio-intc". | ||
5 | |||
6 | - reg: Physical base address of the controller and length of memory mapped | ||
7 | region. | ||
8 | |||
9 | - interrupt-controller : Identifies the node as an interrupt controller | ||
10 | |||
11 | Example: | ||
12 | |||
13 | interrupt-controller { | ||
14 | compatible = "lsi,zevio-intc"; | ||
15 | interrupt-controller; | ||
16 | reg = <0xDC000000 0x1000>; | ||
17 | #interrupt-cells = <1>; | ||
18 | }; | ||
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index c60b9010b152..292b10645fd8 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
@@ -20,5 +20,6 @@ obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o | |||
20 | obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o | 20 | obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o |
21 | obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o | 21 | obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o |
22 | obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o | 22 | obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o |
23 | obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o | ||
23 | obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o | 24 | obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o |
24 | obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o | 25 | obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o |
diff --git a/drivers/irqchip/irq-zevio.c b/drivers/irqchip/irq-zevio.c new file mode 100644 index 000000000000..8ed04c4a43ee --- /dev/null +++ b/drivers/irqchip/irq-zevio.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * linux/drivers/irqchip/irq-zevio.c | ||
3 | * | ||
4 | * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2, as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/io.h> | ||
13 | #include <linux/irq.h> | ||
14 | #include <linux/of.h> | ||
15 | #include <linux/of_address.h> | ||
16 | #include <linux/of_irq.h> | ||
17 | |||
18 | #include <asm/mach/irq.h> | ||
19 | #include <asm/exception.h> | ||
20 | |||
21 | #include "irqchip.h" | ||
22 | |||
23 | #define IO_STATUS 0x000 | ||
24 | #define IO_RAW_STATUS 0x004 | ||
25 | #define IO_ENABLE 0x008 | ||
26 | #define IO_DISABLE 0x00C | ||
27 | #define IO_CURRENT 0x020 | ||
28 | #define IO_RESET 0x028 | ||
29 | #define IO_MAX_PRIOTY 0x02C | ||
30 | |||
31 | #define IO_IRQ_BASE 0x000 | ||
32 | #define IO_FIQ_BASE 0x100 | ||
33 | |||
34 | #define IO_INVERT_SEL 0x200 | ||
35 | #define IO_STICKY_SEL 0x204 | ||
36 | #define IO_PRIORITY_SEL 0x300 | ||
37 | |||
38 | #define MAX_INTRS 32 | ||
39 | #define FIQ_START MAX_INTRS | ||
40 | |||
41 | static struct irq_domain *zevio_irq_domain; | ||
42 | static void __iomem *zevio_irq_io; | ||
43 | |||
44 | static void zevio_irq_ack(struct irq_data *irqd) | ||
45 | { | ||
46 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(irqd); | ||
47 | struct irq_chip_regs *regs = | ||
48 | &container_of(irqd->chip, struct irq_chip_type, chip)->regs; | ||
49 | |||
50 | readl(gc->reg_base + regs->ack); | ||
51 | } | ||
52 | |||
53 | static asmlinkage void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs) | ||
54 | { | ||
55 | int irqnr; | ||
56 | |||
57 | while (readl(zevio_irq_io + IO_STATUS)) { | ||
58 | irqnr = readl(zevio_irq_io + IO_CURRENT); | ||
59 | irqnr = irq_find_mapping(zevio_irq_domain, irqnr); | ||
60 | handle_IRQ(irqnr, regs); | ||
61 | }; | ||
62 | } | ||
63 | |||
64 | static void __init zevio_init_irq_base(void __iomem *base) | ||
65 | { | ||
66 | /* Disable all interrupts */ | ||
67 | writel(~0, base + IO_DISABLE); | ||
68 | |||
69 | /* Accept interrupts of all priorities */ | ||
70 | writel(0xF, base + IO_MAX_PRIOTY); | ||
71 | |||
72 | /* Reset existing interrupts */ | ||
73 | readl(base + IO_RESET); | ||
74 | } | ||
75 | |||
76 | static int __init zevio_of_init(struct device_node *node, | ||
77 | struct device_node *parent) | ||
78 | { | ||
79 | unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; | ||
80 | struct irq_chip_generic *gc; | ||
81 | int ret; | ||
82 | |||
83 | if (WARN_ON(zevio_irq_io || zevio_irq_domain)) | ||
84 | return -EBUSY; | ||
85 | |||
86 | zevio_irq_io = of_iomap(node, 0); | ||
87 | BUG_ON(!zevio_irq_io); | ||
88 | |||
89 | /* Do not invert interrupt status bits */ | ||
90 | writel(~0, zevio_irq_io + IO_INVERT_SEL); | ||
91 | |||
92 | /* Disable sticky interrupts */ | ||
93 | writel(0, zevio_irq_io + IO_STICKY_SEL); | ||
94 | |||
95 | /* We don't use IRQ priorities. Set each IRQ to highest priority. */ | ||
96 | memset_io(zevio_irq_io + IO_PRIORITY_SEL, 0, MAX_INTRS * sizeof(u32)); | ||
97 | |||
98 | /* Init IRQ and FIQ */ | ||
99 | zevio_init_irq_base(zevio_irq_io + IO_IRQ_BASE); | ||
100 | zevio_init_irq_base(zevio_irq_io + IO_FIQ_BASE); | ||
101 | |||
102 | zevio_irq_domain = irq_domain_add_linear(node, MAX_INTRS, | ||
103 | &irq_generic_chip_ops, NULL); | ||
104 | BUG_ON(!zevio_irq_domain); | ||
105 | |||
106 | ret = irq_alloc_domain_generic_chips(zevio_irq_domain, MAX_INTRS, 1, | ||
107 | "zevio_intc", handle_level_irq, | ||
108 | clr, 0, IRQ_GC_INIT_MASK_CACHE); | ||
109 | BUG_ON(ret); | ||
110 | |||
111 | gc = irq_get_domain_generic_chip(zevio_irq_domain, 0); | ||
112 | gc->reg_base = zevio_irq_io; | ||
113 | gc->chip_types[0].chip.irq_ack = zevio_irq_ack; | ||
114 | gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; | ||
115 | gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; | ||
116 | gc->chip_types[0].regs.mask = IO_IRQ_BASE + IO_ENABLE; | ||
117 | gc->chip_types[0].regs.enable = IO_IRQ_BASE + IO_ENABLE; | ||
118 | gc->chip_types[0].regs.disable = IO_IRQ_BASE + IO_DISABLE; | ||
119 | gc->chip_types[0].regs.ack = IO_IRQ_BASE + IO_RESET; | ||
120 | |||
121 | set_handle_irq(zevio_handle_irq); | ||
122 | |||
123 | pr_info("TI-NSPIRE classic IRQ controller\n"); | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | IRQCHIP_DECLARE(zevio_irq, "lsi,zevio-intc", zevio_of_init); | ||