[lantiq] add linux-v3.7
[openwrt.git] / target / linux / lantiq / patches-3.7 / 0105-MIPS-lantiq-rework-external-irq-code.patch
1 From edd237c93d564e698e169a89d1b1b35248c5ef4a Mon Sep 17 00:00:00 2001
2 From: John Crispin <blogic@openwrt.org>
3 Date: Mon, 3 Dec 2012 21:44:30 +0100
4 Subject: [PATCH 105/123] 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 ---
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
16 diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h
17 index 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);
28 diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
29 index 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 -- 
213 1.7.10.4
214