aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/lantiq
diff options
context:
space:
mode:
authorJohn Crispin <blogic@openwrt.org>2013-01-19 03:54:27 -0500
committerJohn Crispin <blogic@openwrt.org>2013-02-16 18:15:18 -0500
commit26365625947fb7d6501065272a1fd59460c0f4ed (patch)
tree5966c84966c51d1c45a6f0896ceb04e2980fed53 /arch/mips/lantiq
parentbae696a267d81ea268f4de1e396b8c82154f22ed (diff)
MIPS: lantiq: rework external irq code
This code makes the irqs used by the EIU loadable from the DT. Additionally we add a helper that allows the pinctrl layer to map external irqs to real irq numbers. Signed-off-by: John Crispin <blogic@openwrt.org> Patchwork: http://patchwork.linux-mips.org/patch/4818/
Diffstat (limited to 'arch/mips/lantiq')
-rw-r--r--arch/mips/lantiq/irq.c105
1 files changed, 73 insertions, 32 deletions
diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
index a7935bf0fecb..51194875f158 100644
--- a/arch/mips/lantiq/irq.c
+++ b/arch/mips/lantiq/irq.c
@@ -33,17 +33,10 @@
33/* register definitions - external irqs */ 33/* register definitions - external irqs */
34#define LTQ_EIU_EXIN_C 0x0000 34#define LTQ_EIU_EXIN_C 0x0000
35#define LTQ_EIU_EXIN_INIC 0x0004 35#define LTQ_EIU_EXIN_INIC 0x0004
36#define LTQ_EIU_EXIN_INC 0x0008
36#define LTQ_EIU_EXIN_INEN 0x000C 37#define LTQ_EIU_EXIN_INEN 0x000C
37 38
38/* irq numbers used by the external interrupt unit (EIU) */ 39/* number of external interrupts */
39#define LTQ_EIU_IR0 (INT_NUM_IM4_IRL0 + 30)
40#define LTQ_EIU_IR1 (INT_NUM_IM3_IRL0 + 31)
41#define LTQ_EIU_IR2 (INT_NUM_IM1_IRL0 + 26)
42#define LTQ_EIU_IR3 INT_NUM_IM1_IRL0
43#define LTQ_EIU_IR4 (INT_NUM_IM1_IRL0 + 1)
44#define LTQ_EIU_IR5 (INT_NUM_IM1_IRL0 + 2)
45#define LTQ_EIU_IR6 (INT_NUM_IM2_IRL0 + 30)
46#define XWAY_EXIN_COUNT 3
47#define MAX_EIU 6 40#define MAX_EIU 6
48 41
49/* the performance counter */ 42/* the performance counter */
@@ -72,20 +65,19 @@
72int gic_present; 65int gic_present;
73#endif 66#endif
74 67
75static unsigned short ltq_eiu_irq[MAX_EIU] = {
76 LTQ_EIU_IR0,
77 LTQ_EIU_IR1,
78 LTQ_EIU_IR2,
79 LTQ_EIU_IR3,
80 LTQ_EIU_IR4,
81 LTQ_EIU_IR5,
82};
83
84static int exin_avail; 68static int exin_avail;
69static struct resource ltq_eiu_irq[MAX_EIU];
85static void __iomem *ltq_icu_membase[MAX_IM]; 70static void __iomem *ltq_icu_membase[MAX_IM];
86static void __iomem *ltq_eiu_membase; 71static void __iomem *ltq_eiu_membase;
87static struct irq_domain *ltq_domain; 72static struct irq_domain *ltq_domain;
88 73
74int ltq_eiu_get_irq(int exin)
75{
76 if (exin < exin_avail)
77 return ltq_eiu_irq[exin].start;
78 return -1;
79}
80
89void ltq_disable_irq(struct irq_data *d) 81void ltq_disable_irq(struct irq_data *d)
90{ 82{
91 u32 ier = LTQ_ICU_IM0_IER; 83 u32 ier = LTQ_ICU_IM0_IER;
@@ -128,19 +120,65 @@ void ltq_enable_irq(struct irq_data *d)
128 ltq_icu_w32(im, ltq_icu_r32(im, ier) | BIT(offset), ier); 120 ltq_icu_w32(im, ltq_icu_r32(im, ier) | BIT(offset), ier);
129} 121}
130 122
123static int ltq_eiu_settype(struct irq_data *d, unsigned int type)
124{
125 int i;
126
127 for (i = 0; i < MAX_EIU; i++) {
128 if (d->hwirq == ltq_eiu_irq[i].start) {
129 int val = 0;
130 int edge = 0;
131
132 switch (type) {
133 case IRQF_TRIGGER_NONE:
134 break;
135 case IRQF_TRIGGER_RISING:
136 val = 1;
137 edge = 1;
138 break;
139 case IRQF_TRIGGER_FALLING:
140 val = 2;
141 edge = 1;
142 break;
143 case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING:
144 val = 3;
145 edge = 1;
146 break;
147 case IRQF_TRIGGER_HIGH:
148 val = 5;
149 break;
150 case IRQF_TRIGGER_LOW:
151 val = 6;
152 break;
153 default:
154 pr_err("invalid type %d for irq %ld\n",
155 type, d->hwirq);
156 return -EINVAL;
157 }
158
159 if (edge)
160 irq_set_handler(d->hwirq, handle_edge_irq);
161
162 ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
163 (val << (i * 4)), LTQ_EIU_EXIN_C);
164 }
165 }
166
167 return 0;
168}
169
131static unsigned int ltq_startup_eiu_irq(struct irq_data *d) 170static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
132{ 171{
133 int i; 172 int i;
134 173
135 ltq_enable_irq(d); 174 ltq_enable_irq(d);
136 for (i = 0; i < MAX_EIU; i++) { 175 for (i = 0; i < MAX_EIU; i++) {
137 if (d->hwirq == ltq_eiu_irq[i]) { 176 if (d->hwirq == ltq_eiu_irq[i].start) {
138 /* low level - we should really handle set_type */ 177 /* by default we are low level triggered */
139 ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) | 178 ltq_eiu_settype(d, IRQF_TRIGGER_LOW);
140 (0x6 << (i * 4)), LTQ_EIU_EXIN_C);
141 /* clear all pending */ 179 /* clear all pending */
142 ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~BIT(i), 180 ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INC) & ~BIT(i),
143 LTQ_EIU_EXIN_INIC); 181 LTQ_EIU_EXIN_INC);
144 /* enable */ 182 /* enable */
145 ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | BIT(i), 183 ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | BIT(i),
146 LTQ_EIU_EXIN_INEN); 184 LTQ_EIU_EXIN_INEN);
@@ -157,7 +195,7 @@ static void ltq_shutdown_eiu_irq(struct irq_data *d)
157 195
158 ltq_disable_irq(d); 196 ltq_disable_irq(d);
159 for (i = 0; i < MAX_EIU; i++) { 197 for (i = 0; i < MAX_EIU; i++) {
160 if (d->hwirq == ltq_eiu_irq[i]) { 198 if (d->hwirq == ltq_eiu_irq[i].start) {
161 /* disable */ 199 /* disable */
162 ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i), 200 ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i),
163 LTQ_EIU_EXIN_INEN); 201 LTQ_EIU_EXIN_INEN);
@@ -186,6 +224,7 @@ static struct irq_chip ltq_eiu_type = {
186 .irq_ack = ltq_ack_irq, 224 .irq_ack = ltq_ack_irq,
187 .irq_mask = ltq_disable_irq, 225 .irq_mask = ltq_disable_irq,
188 .irq_mask_ack = ltq_mask_and_ack_irq, 226 .irq_mask_ack = ltq_mask_and_ack_irq,
227 .irq_set_type = ltq_eiu_settype,
189}; 228};
190 229
191static void ltq_hw_irqdispatch(int module) 230static void ltq_hw_irqdispatch(int module)
@@ -301,7 +340,7 @@ static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
301 return 0; 340 return 0;
302 341
303 for (i = 0; i < exin_avail; i++) 342 for (i = 0; i < exin_avail; i++)
304 if (hw == ltq_eiu_irq[i]) 343 if (hw == ltq_eiu_irq[i].start)
305 chip = &ltq_eiu_type; 344 chip = &ltq_eiu_type;
306 345
307 irq_set_chip_and_handler(hw, chip, handle_level_irq); 346 irq_set_chip_and_handler(hw, chip, handle_level_irq);
@@ -323,7 +362,7 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
323{ 362{
324 struct device_node *eiu_node; 363 struct device_node *eiu_node;
325 struct resource res; 364 struct resource res;
326 int i; 365 int i, ret;
327 366
328 for (i = 0; i < MAX_IM; i++) { 367 for (i = 0; i < MAX_IM; i++) {
329 if (of_address_to_resource(node, i, &res)) 368 if (of_address_to_resource(node, i, &res))
@@ -340,17 +379,19 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
340 } 379 }
341 380
342 /* the external interrupts are optional and xway only */ 381 /* the external interrupts are optional and xway only */
343 eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu"); 382 eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway");
344 if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) { 383 if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) {
345 /* find out how many external irq sources we have */ 384 /* find out how many external irq sources we have */
346 const __be32 *count = of_get_property(node, 385 exin_avail = of_irq_count(eiu_node);
347 "lantiq,count", NULL);
348 386
349 if (count)
350 exin_avail = *count;
351 if (exin_avail > MAX_EIU) 387 if (exin_avail > MAX_EIU)
352 exin_avail = MAX_EIU; 388 exin_avail = MAX_EIU;
353 389
390 ret = of_irq_to_resource_table(eiu_node,
391 ltq_eiu_irq, exin_avail);
392 if (ret != exin_avail)
393 panic("failed to load external irq resources\n");
394
354 if (request_mem_region(res.start, resource_size(&res), 395 if (request_mem_region(res.start, resource_size(&res),
355 res.name) < 0) 396 res.name) < 0)
356 pr_err("Failed to request eiu memory"); 397 pr_err("Failed to request eiu memory");