Root/target/linux/lantiq/patches-3.7/0105-MIPS-lantiq-rework-external-irq-code.patch

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

Archive Download this file



interactive