diff options
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/Kconfig | 4 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/irqchip/exynos-combiner.c | 15 | ||||
-rw-r--r-- | drivers/irqchip/irq-dw-apb-ictl.c | 150 | ||||
-rw-r--r-- | drivers/irqchip/irq-renesas-irqc.c | 21 | ||||
-rw-r--r-- | drivers/irqchip/irq-sirfsoc.c | 3 | ||||
-rw-r--r-- | drivers/irqchip/irq-versatile-fpga.c | 15 |
7 files changed, 181 insertions, 28 deletions
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 07bc79c34012..61ffdca96e25 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig | |||
@@ -30,6 +30,10 @@ config ARM_VIC_NR | |||
30 | The maximum number of VICs available in the system, for | 30 | The maximum number of VICs available in the system, for |
31 | power management. | 31 | power management. |
32 | 32 | ||
33 | config DW_APB_ICTL | ||
34 | bool | ||
35 | select IRQ_DOMAIN | ||
36 | |||
33 | config IMGPDC_IRQ | 37 | config IMGPDC_IRQ |
34 | bool | 38 | bool |
35 | select GENERIC_IRQ_CHIP | 39 | select GENERIC_IRQ_CHIP |
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 66913f9587b3..86b484cb3ec2 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
@@ -6,6 +6,7 @@ obj-$(CONFIG_ARCH_MMP) += irq-mmp.o | |||
6 | obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o | 6 | obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o |
7 | obj-$(CONFIG_ARCH_MXS) += irq-mxs.o | 7 | obj-$(CONFIG_ARCH_MXS) += irq-mxs.o |
8 | obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o | 8 | obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o |
9 | obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o | ||
9 | obj-$(CONFIG_METAG) += irq-metag-ext.o | 10 | obj-$(CONFIG_METAG) += irq-metag-ext.o |
10 | obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o | 11 | obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o |
11 | obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o | 12 | obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o |
diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 868ed40cb6bf..40e6440348ff 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c | |||
@@ -171,8 +171,7 @@ static struct irq_domain_ops combiner_irq_domain_ops = { | |||
171 | 171 | ||
172 | static void __init combiner_init(void __iomem *combiner_base, | 172 | static void __init combiner_init(void __iomem *combiner_base, |
173 | struct device_node *np, | 173 | struct device_node *np, |
174 | unsigned int max_nr, | 174 | unsigned int max_nr) |
175 | int irq_base) | ||
176 | { | 175 | { |
177 | int i, irq; | 176 | int i, irq; |
178 | unsigned int nr_irq; | 177 | unsigned int nr_irq; |
@@ -186,7 +185,7 @@ static void __init combiner_init(void __iomem *combiner_base, | |||
186 | return; | 185 | return; |
187 | } | 186 | } |
188 | 187 | ||
189 | combiner_irq_domain = irq_domain_add_simple(np, nr_irq, irq_base, | 188 | combiner_irq_domain = irq_domain_add_linear(np, nr_irq, |
190 | &combiner_irq_domain_ops, combiner_data); | 189 | &combiner_irq_domain_ops, combiner_data); |
191 | if (WARN_ON(!combiner_irq_domain)) { | 190 | if (WARN_ON(!combiner_irq_domain)) { |
192 | pr_warning("%s: irq domain init failed\n", __func__); | 191 | pr_warning("%s: irq domain init failed\n", __func__); |
@@ -207,7 +206,6 @@ static int __init combiner_of_init(struct device_node *np, | |||
207 | { | 206 | { |
208 | void __iomem *combiner_base; | 207 | void __iomem *combiner_base; |
209 | unsigned int max_nr = 20; | 208 | unsigned int max_nr = 20; |
210 | int irq_base = -1; | ||
211 | 209 | ||
212 | combiner_base = of_iomap(np, 0); | 210 | combiner_base = of_iomap(np, 0); |
213 | if (!combiner_base) { | 211 | if (!combiner_base) { |
@@ -221,14 +219,7 @@ static int __init combiner_of_init(struct device_node *np, | |||
221 | __func__, max_nr); | 219 | __func__, max_nr); |
222 | } | 220 | } |
223 | 221 | ||
224 | /* | 222 | combiner_init(combiner_base, np, max_nr); |
225 | * FIXME: This is a hardwired COMBINER_IRQ(0,0). Once all devices | ||
226 | * get their IRQ from DT, remove this in order to get dynamic | ||
227 | * allocation. | ||
228 | */ | ||
229 | irq_base = 160; | ||
230 | |||
231 | combiner_init(combiner_base, np, max_nr, irq_base); | ||
232 | 223 | ||
233 | return 0; | 224 | return 0; |
234 | } | 225 | } |
diff --git a/drivers/irqchip/irq-dw-apb-ictl.c b/drivers/irqchip/irq-dw-apb-ictl.c new file mode 100644 index 000000000000..31e231e1f566 --- /dev/null +++ b/drivers/irqchip/irq-dw-apb-ictl.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * Synopsys DW APB ICTL irqchip driver. | ||
3 | * | ||
4 | * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | ||
5 | * | ||
6 | * based on GPL'ed 2.6 kernel sources | ||
7 | * (c) Marvell International Ltd. | ||
8 | * | ||
9 | * This file is licensed under the terms of the GNU General Public | ||
10 | * License version 2. This program is licensed "as is" without any | ||
11 | * warranty of any kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | #include <linux/io.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <linux/irqchip/chained_irq.h> | ||
17 | #include <linux/of_address.h> | ||
18 | #include <linux/of_irq.h> | ||
19 | |||
20 | #include "irqchip.h" | ||
21 | |||
22 | #define APB_INT_ENABLE_L 0x00 | ||
23 | #define APB_INT_ENABLE_H 0x04 | ||
24 | #define APB_INT_MASK_L 0x08 | ||
25 | #define APB_INT_MASK_H 0x0c | ||
26 | #define APB_INT_FINALSTATUS_L 0x30 | ||
27 | #define APB_INT_FINALSTATUS_H 0x34 | ||
28 | |||
29 | static void dw_apb_ictl_handler(unsigned int irq, struct irq_desc *desc) | ||
30 | { | ||
31 | struct irq_chip *chip = irq_get_chip(irq); | ||
32 | struct irq_chip_generic *gc = irq_get_handler_data(irq); | ||
33 | struct irq_domain *d = gc->private; | ||
34 | u32 stat; | ||
35 | int n; | ||
36 | |||
37 | chained_irq_enter(chip, desc); | ||
38 | |||
39 | for (n = 0; n < gc->num_ct; n++) { | ||
40 | stat = readl_relaxed(gc->reg_base + | ||
41 | APB_INT_FINALSTATUS_L + 4 * n); | ||
42 | while (stat) { | ||
43 | u32 hwirq = ffs(stat) - 1; | ||
44 | generic_handle_irq(irq_find_mapping(d, | ||
45 | gc->irq_base + hwirq + 32 * n)); | ||
46 | stat &= ~(1 << hwirq); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | chained_irq_exit(chip, desc); | ||
51 | } | ||
52 | |||
53 | static int __init dw_apb_ictl_init(struct device_node *np, | ||
54 | struct device_node *parent) | ||
55 | { | ||
56 | unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; | ||
57 | struct resource r; | ||
58 | struct irq_domain *domain; | ||
59 | struct irq_chip_generic *gc; | ||
60 | void __iomem *iobase; | ||
61 | int ret, nrirqs, irq; | ||
62 | u32 reg; | ||
63 | |||
64 | /* Map the parent interrupt for the chained handler */ | ||
65 | irq = irq_of_parse_and_map(np, 0); | ||
66 | if (irq <= 0) { | ||
67 | pr_err("%s: unable to parse irq\n", np->full_name); | ||
68 | return -EINVAL; | ||
69 | } | ||
70 | |||
71 | ret = of_address_to_resource(np, 0, &r); | ||
72 | if (ret) { | ||
73 | pr_err("%s: unable to get resource\n", np->full_name); | ||
74 | return ret; | ||
75 | } | ||
76 | |||
77 | if (!request_mem_region(r.start, resource_size(&r), np->full_name)) { | ||
78 | pr_err("%s: unable to request mem region\n", np->full_name); | ||
79 | return -ENOMEM; | ||
80 | } | ||
81 | |||
82 | iobase = ioremap(r.start, resource_size(&r)); | ||
83 | if (!iobase) { | ||
84 | pr_err("%s: unable to map resource\n", np->full_name); | ||
85 | ret = -ENOMEM; | ||
86 | goto err_release; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * DW IP can be configured to allow 2-64 irqs. We can determine | ||
91 | * the number of irqs supported by writing into enable register | ||
92 | * and look for bits not set, as corresponding flip-flops will | ||
93 | * have been removed by sythesis tool. | ||
94 | */ | ||
95 | |||
96 | /* mask and enable all interrupts */ | ||
97 | writel(~0, iobase + APB_INT_MASK_L); | ||
98 | writel(~0, iobase + APB_INT_MASK_H); | ||
99 | writel(~0, iobase + APB_INT_ENABLE_L); | ||
100 | writel(~0, iobase + APB_INT_ENABLE_H); | ||
101 | |||
102 | reg = readl(iobase + APB_INT_ENABLE_H); | ||
103 | if (reg) | ||
104 | nrirqs = 32 + fls(reg); | ||
105 | else | ||
106 | nrirqs = fls(readl(iobase + APB_INT_ENABLE_L)); | ||
107 | |||
108 | domain = irq_domain_add_linear(np, nrirqs, | ||
109 | &irq_generic_chip_ops, NULL); | ||
110 | if (!domain) { | ||
111 | pr_err("%s: unable to add irq domain\n", np->full_name); | ||
112 | ret = -ENOMEM; | ||
113 | goto err_unmap; | ||
114 | } | ||
115 | |||
116 | ret = irq_alloc_domain_generic_chips(domain, 32, (nrirqs > 32) ? 2 : 1, | ||
117 | np->name, handle_level_irq, clr, 0, | ||
118 | IRQ_GC_INIT_MASK_CACHE); | ||
119 | if (ret) { | ||
120 | pr_err("%s: unable to alloc irq domain gc\n", np->full_name); | ||
121 | goto err_unmap; | ||
122 | } | ||
123 | |||
124 | gc = irq_get_domain_generic_chip(domain, 0); | ||
125 | gc->private = domain; | ||
126 | gc->reg_base = iobase; | ||
127 | |||
128 | gc->chip_types[0].regs.mask = APB_INT_MASK_L; | ||
129 | gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; | ||
130 | gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit; | ||
131 | |||
132 | if (nrirqs > 32) { | ||
133 | gc->chip_types[1].regs.mask = APB_INT_MASK_H; | ||
134 | gc->chip_types[1].chip.irq_mask = irq_gc_mask_set_bit; | ||
135 | gc->chip_types[1].chip.irq_unmask = irq_gc_mask_clr_bit; | ||
136 | } | ||
137 | |||
138 | irq_set_handler_data(irq, gc); | ||
139 | irq_set_chained_handler(irq, dw_apb_ictl_handler); | ||
140 | |||
141 | return 0; | ||
142 | |||
143 | err_unmap: | ||
144 | iounmap(iobase); | ||
145 | err_release: | ||
146 | release_mem_region(r.start, resource_size(&r)); | ||
147 | return ret; | ||
148 | } | ||
149 | IRQCHIP_DECLARE(dw_apb_ictl, | ||
150 | "snps,dw-apb-ictl", dw_apb_ictl_init); | ||
diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 2f404ba61c6c..8777065012a5 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c | |||
@@ -81,15 +81,12 @@ static void irqc_irq_disable(struct irq_data *d) | |||
81 | iowrite32(BIT(hw_irq), p->cpu_int_base + IRQC_EN_STS); | 81 | iowrite32(BIT(hw_irq), p->cpu_int_base + IRQC_EN_STS); |
82 | } | 82 | } |
83 | 83 | ||
84 | #define INTC_IRQ_SENSE_VALID 0x10 | ||
85 | #define INTC_IRQ_SENSE(x) (x + INTC_IRQ_SENSE_VALID) | ||
86 | |||
87 | static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = { | 84 | static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = { |
88 | [IRQ_TYPE_LEVEL_LOW] = INTC_IRQ_SENSE(0x01), | 85 | [IRQ_TYPE_LEVEL_LOW] = 0x01, |
89 | [IRQ_TYPE_LEVEL_HIGH] = INTC_IRQ_SENSE(0x02), | 86 | [IRQ_TYPE_LEVEL_HIGH] = 0x02, |
90 | [IRQ_TYPE_EDGE_FALLING] = INTC_IRQ_SENSE(0x04), /* Synchronous */ | 87 | [IRQ_TYPE_EDGE_FALLING] = 0x04, /* Synchronous */ |
91 | [IRQ_TYPE_EDGE_RISING] = INTC_IRQ_SENSE(0x08), /* Synchronous */ | 88 | [IRQ_TYPE_EDGE_RISING] = 0x08, /* Synchronous */ |
92 | [IRQ_TYPE_EDGE_BOTH] = INTC_IRQ_SENSE(0x0c), /* Synchronous */ | 89 | [IRQ_TYPE_EDGE_BOTH] = 0x0c, /* Synchronous */ |
93 | }; | 90 | }; |
94 | 91 | ||
95 | static int irqc_irq_set_type(struct irq_data *d, unsigned int type) | 92 | static int irqc_irq_set_type(struct irq_data *d, unsigned int type) |
@@ -101,12 +98,12 @@ static int irqc_irq_set_type(struct irq_data *d, unsigned int type) | |||
101 | 98 | ||
102 | irqc_dbg(&p->irq[hw_irq], "sense"); | 99 | irqc_dbg(&p->irq[hw_irq], "sense"); |
103 | 100 | ||
104 | if (!(value & INTC_IRQ_SENSE_VALID)) | 101 | if (!value) |
105 | return -EINVAL; | 102 | return -EINVAL; |
106 | 103 | ||
107 | tmp = ioread32(p->iomem + IRQC_CONFIG(hw_irq)); | 104 | tmp = ioread32(p->iomem + IRQC_CONFIG(hw_irq)); |
108 | tmp &= ~0x3f; | 105 | tmp &= ~0x3f; |
109 | tmp |= value ^ INTC_IRQ_SENSE_VALID; | 106 | tmp |= value; |
110 | iowrite32(tmp, p->iomem + IRQC_CONFIG(hw_irq)); | 107 | iowrite32(tmp, p->iomem + IRQC_CONFIG(hw_irq)); |
111 | return 0; | 108 | return 0; |
112 | } | 109 | } |
@@ -212,10 +209,8 @@ static int irqc_probe(struct platform_device *pdev) | |||
212 | irq_chip->name = name; | 209 | irq_chip->name = name; |
213 | irq_chip->irq_mask = irqc_irq_disable; | 210 | irq_chip->irq_mask = irqc_irq_disable; |
214 | irq_chip->irq_unmask = irqc_irq_enable; | 211 | irq_chip->irq_unmask = irqc_irq_enable; |
215 | irq_chip->irq_enable = irqc_irq_enable; | ||
216 | irq_chip->irq_disable = irqc_irq_disable; | ||
217 | irq_chip->irq_set_type = irqc_irq_set_type; | 212 | irq_chip->irq_set_type = irqc_irq_set_type; |
218 | irq_chip->flags = IRQCHIP_SKIP_SET_WAKE; | 213 | irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; |
219 | 214 | ||
220 | p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, | 215 | p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, |
221 | p->number_of_irqs, | 216 | p->number_of_irqs, |
diff --git a/drivers/irqchip/irq-sirfsoc.c b/drivers/irqchip/irq-sirfsoc.c index 4851afae38dc..3a070c587ed9 100644 --- a/drivers/irqchip/irq-sirfsoc.c +++ b/drivers/irqchip/irq-sirfsoc.c | |||
@@ -34,9 +34,10 @@ sirfsoc_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num) | |||
34 | struct irq_chip_type *ct; | 34 | struct irq_chip_type *ct; |
35 | int ret; | 35 | int ret; |
36 | unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; | 36 | unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; |
37 | unsigned int set = IRQ_LEVEL; | ||
37 | 38 | ||
38 | ret = irq_alloc_domain_generic_chips(sirfsoc_irqdomain, num, 1, "irq_sirfsoc", | 39 | ret = irq_alloc_domain_generic_chips(sirfsoc_irqdomain, num, 1, "irq_sirfsoc", |
39 | handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); | 40 | handle_level_irq, clr, set, IRQ_GC_INIT_MASK_CACHE); |
40 | 41 | ||
41 | gc = irq_get_domain_generic_chip(sirfsoc_irqdomain, irq_start); | 42 | gc = irq_get_domain_generic_chip(sirfsoc_irqdomain, irq_start); |
42 | gc->reg_base = base; | 43 | gc->reg_base = base; |
diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index 47a52ab580d8..3ae2bb8d9cf2 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/of.h> | 10 | #include <linux/of.h> |
11 | #include <linux/of_address.h> | 11 | #include <linux/of_address.h> |
12 | #include <linux/of_irq.h> | ||
12 | 13 | ||
13 | #include <asm/exception.h> | 14 | #include <asm/exception.h> |
14 | #include <asm/mach/irq.h> | 15 | #include <asm/mach/irq.h> |
@@ -167,8 +168,12 @@ void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start, | |||
167 | f->used_irqs++; | 168 | f->used_irqs++; |
168 | } | 169 | } |
169 | 170 | ||
170 | pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n", | 171 | pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs", |
171 | fpga_irq_id, name, base, f->used_irqs); | 172 | fpga_irq_id, name, base, f->used_irqs); |
173 | if (parent_irq != -1) | ||
174 | pr_cont(", parent IRQ: %d\n", parent_irq); | ||
175 | else | ||
176 | pr_cont("\n"); | ||
172 | 177 | ||
173 | fpga_irq_id++; | 178 | fpga_irq_id++; |
174 | } | 179 | } |
@@ -180,6 +185,7 @@ int __init fpga_irq_of_init(struct device_node *node, | |||
180 | void __iomem *base; | 185 | void __iomem *base; |
181 | u32 clear_mask; | 186 | u32 clear_mask; |
182 | u32 valid_mask; | 187 | u32 valid_mask; |
188 | int parent_irq; | ||
183 | 189 | ||
184 | if (WARN_ON(!node)) | 190 | if (WARN_ON(!node)) |
185 | return -ENODEV; | 191 | return -ENODEV; |
@@ -193,7 +199,12 @@ int __init fpga_irq_of_init(struct device_node *node, | |||
193 | if (of_property_read_u32(node, "valid-mask", &valid_mask)) | 199 | if (of_property_read_u32(node, "valid-mask", &valid_mask)) |
194 | valid_mask = 0; | 200 | valid_mask = 0; |
195 | 201 | ||
196 | fpga_irq_init(base, node->name, 0, -1, valid_mask, node); | 202 | /* Some chips are cascaded from a parent IRQ */ |
203 | parent_irq = irq_of_parse_and_map(node, 0); | ||
204 | if (!parent_irq) | ||
205 | parent_irq = -1; | ||
206 | |||
207 | fpga_irq_init(base, node->name, 0, parent_irq, valid_mask, node); | ||
197 | 208 | ||
198 | writel(clear_mask, base + IRQ_ENABLE_CLEAR); | 209 | writel(clear_mask, base + IRQ_ENABLE_CLEAR); |
199 | writel(clear_mask, base + FIQ_ENABLE_CLEAR); | 210 | writel(clear_mask, base + FIQ_ENABLE_CLEAR); |