f9767655c72b1fac096e6b8ce61bac4738245278
[openwrt/staging/yousong.git] / target / linux / lantiq / patches-3.8 / 0019-MIPS-lantiq-rework-external-irq-code.patch
1 From d8f6bf3fb606ee8fdd5b7aff4aedb54e30792b84 Mon Sep 17 00:00:00 2001
2 From: John Crispin <blogic@openwrt.org>
3 Date: Sat, 19 Jan 2013 08:54:27 +0000
4 Subject: [PATCH 19/40] MIPS: lantiq: rework external irq code
5
6 This code makes the irqs used by the EIU loadable from the DT. Additionally we
7 add a helper that allows the pinctrl layer to map external irqs to real irq
8 numbers.
9
10 Signed-off-by: John Crispin <blogic@openwrt.org>
11 Patchwork: http://patchwork.linux-mips.org/patch/4818/
12 ---
13 arch/mips/include/asm/mach-lantiq/lantiq.h | 1 +
14 arch/mips/lantiq/irq.c | 105 +++++++++++++++++++---------
15 2 files changed, 74 insertions(+), 32 deletions(-)
16
17 diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h
18 index 76be7a0..f196cce 100644
19 --- a/arch/mips/include/asm/mach-lantiq/lantiq.h
20 +++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
21 @@ -34,6 +34,7 @@ extern spinlock_t ebu_lock;
22 extern void ltq_disable_irq(struct irq_data *data);
23 extern void ltq_mask_and_ack_irq(struct irq_data *data);
24 extern void ltq_enable_irq(struct irq_data *data);
25 +extern int ltq_eiu_get_irq(int exin);
26
27 /* clock handling */
28 extern int clk_activate(struct clk *clk);
29 diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
30 index a7935bf..5119487 100644
31 --- a/arch/mips/lantiq/irq.c
32 +++ b/arch/mips/lantiq/irq.c
33 @@ -33,17 +33,10 @@
34 /* register definitions - external irqs */
35 #define LTQ_EIU_EXIN_C 0x0000
36 #define LTQ_EIU_EXIN_INIC 0x0004
37 +#define LTQ_EIU_EXIN_INC 0x0008
38 #define LTQ_EIU_EXIN_INEN 0x000C
39
40 -/* irq numbers used by the external interrupt unit (EIU) */
41 -#define LTQ_EIU_IR0 (INT_NUM_IM4_IRL0 + 30)
42 -#define LTQ_EIU_IR1 (INT_NUM_IM3_IRL0 + 31)
43 -#define LTQ_EIU_IR2 (INT_NUM_IM1_IRL0 + 26)
44 -#define LTQ_EIU_IR3 INT_NUM_IM1_IRL0
45 -#define LTQ_EIU_IR4 (INT_NUM_IM1_IRL0 + 1)
46 -#define LTQ_EIU_IR5 (INT_NUM_IM1_IRL0 + 2)
47 -#define LTQ_EIU_IR6 (INT_NUM_IM2_IRL0 + 30)
48 -#define XWAY_EXIN_COUNT 3
49 +/* number of external interrupts */
50 #define MAX_EIU 6
51
52 /* the performance counter */
53 @@ -72,20 +65,19 @@
54 int gic_present;
55 #endif
56
57 -static unsigned short ltq_eiu_irq[MAX_EIU] = {
58 - LTQ_EIU_IR0,
59 - LTQ_EIU_IR1,
60 - LTQ_EIU_IR2,
61 - LTQ_EIU_IR3,
62 - LTQ_EIU_IR4,
63 - LTQ_EIU_IR5,
64 -};
65 -
66 static int exin_avail;
67 +static struct resource ltq_eiu_irq[MAX_EIU];
68 static void __iomem *ltq_icu_membase[MAX_IM];
69 static void __iomem *ltq_eiu_membase;
70 static struct irq_domain *ltq_domain;
71
72 +int ltq_eiu_get_irq(int exin)
73 +{
74 + if (exin < exin_avail)
75 + return ltq_eiu_irq[exin].start;
76 + return -1;
77 +}
78 +
79 void ltq_disable_irq(struct irq_data *d)
80 {
81 u32 ier = LTQ_ICU_IM0_IER;
82 @@ -128,19 +120,65 @@ void ltq_enable_irq(struct irq_data *d)
83 ltq_icu_w32(im, ltq_icu_r32(im, ier) | BIT(offset), ier);
84 }
85
86 +static int ltq_eiu_settype(struct irq_data *d, unsigned int type)
87 +{
88 + int i;
89 +
90 + for (i = 0; i < MAX_EIU; i++) {
91 + if (d->hwirq == ltq_eiu_irq[i].start) {
92 + int val = 0;
93 + int edge = 0;
94 +
95 + switch (type) {
96 + case IRQF_TRIGGER_NONE:
97 + break;
98 + case IRQF_TRIGGER_RISING:
99 + val = 1;
100 + edge = 1;
101 + break;
102 + case IRQF_TRIGGER_FALLING:
103 + val = 2;
104 + edge = 1;
105 + break;
106 + case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING:
107 + val = 3;
108 + edge = 1;
109 + break;
110 + case IRQF_TRIGGER_HIGH:
111 + val = 5;
112 + break;
113 + case IRQF_TRIGGER_LOW:
114 + val = 6;
115 + break;
116 + default:
117 + pr_err("invalid type %d for irq %ld\n",
118 + type, d->hwirq);
119 + return -EINVAL;
120 + }
121 +
122 + if (edge)
123 + irq_set_handler(d->hwirq, handle_edge_irq);
124 +
125 + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
126 + (val << (i * 4)), LTQ_EIU_EXIN_C);
127 + }
128 + }
129 +
130 + return 0;
131 +}
132 +
133 static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
134 {
135 int i;
136
137 ltq_enable_irq(d);
138 for (i = 0; i < MAX_EIU; i++) {
139 - if (d->hwirq == ltq_eiu_irq[i]) {
140 - /* low level - we should really handle set_type */
141 - ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
142 - (0x6 << (i * 4)), LTQ_EIU_EXIN_C);
143 + if (d->hwirq == ltq_eiu_irq[i].start) {
144 + /* by default we are low level triggered */
145 + ltq_eiu_settype(d, IRQF_TRIGGER_LOW);
146 /* clear all pending */
147 - ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~BIT(i),
148 - LTQ_EIU_EXIN_INIC);
149 + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INC) & ~BIT(i),
150 + LTQ_EIU_EXIN_INC);
151 /* enable */
152 ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | BIT(i),
153 LTQ_EIU_EXIN_INEN);
154 @@ -157,7 +195,7 @@ static void ltq_shutdown_eiu_irq(struct irq_data *d)
155
156 ltq_disable_irq(d);
157 for (i = 0; i < MAX_EIU; i++) {
158 - if (d->hwirq == ltq_eiu_irq[i]) {
159 + if (d->hwirq == ltq_eiu_irq[i].start) {
160 /* disable */
161 ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i),
162 LTQ_EIU_EXIN_INEN);
163 @@ -186,6 +224,7 @@ static struct irq_chip ltq_eiu_type = {
164 .irq_ack = ltq_ack_irq,
165 .irq_mask = ltq_disable_irq,
166 .irq_mask_ack = ltq_mask_and_ack_irq,
167 + .irq_set_type = ltq_eiu_settype,
168 };
169
170 static void ltq_hw_irqdispatch(int module)
171 @@ -301,7 +340,7 @@ static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
172 return 0;
173
174 for (i = 0; i < exin_avail; i++)
175 - if (hw == ltq_eiu_irq[i])
176 + if (hw == ltq_eiu_irq[i].start)
177 chip = &ltq_eiu_type;
178
179 irq_set_chip_and_handler(hw, chip, handle_level_irq);
180 @@ -323,7 +362,7 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
181 {
182 struct device_node *eiu_node;
183 struct resource res;
184 - int i;
185 + int i, ret;
186
187 for (i = 0; i < MAX_IM; i++) {
188 if (of_address_to_resource(node, i, &res))
189 @@ -340,17 +379,19 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
190 }
191
192 /* the external interrupts are optional and xway only */
193 - eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu");
194 + eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway");
195 if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) {
196 /* find out how many external irq sources we have */
197 - const __be32 *count = of_get_property(node,
198 - "lantiq,count", NULL);
199 + exin_avail = of_irq_count(eiu_node);
200
201 - if (count)
202 - exin_avail = *count;
203 if (exin_avail > MAX_EIU)
204 exin_avail = MAX_EIU;
205
206 + ret = of_irq_to_resource_table(eiu_node,
207 + ltq_eiu_irq, exin_avail);
208 + if (ret != exin_avail)
209 + panic("failed to load external irq resources\n");
210 +
211 if (request_mem_region(res.start, resource_size(&res),
212 res.name) < 0)
213 pr_err("Failed to request eiu memory");
214 --
215 1.7.10.4
216