Commit bd20ff5793b4ece4fa3e9e0fcf8e6bbd93526215
Committed by
Russell King
1 parent
36c64af4e0
[ARM] 3374/1: ep93xx: gpio interrupt support
Patch from Lennert Buytenhek Add GPIO interrupt support for the first 16 GPIO lines (port A and B.) Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Showing 3 changed files with 146 additions and 1 deletions Side-by-side Diff
arch/arm/mach-ep93xx/core.c
... | ... | @@ -150,6 +150,26 @@ |
150 | 150 | /************************************************************************* |
151 | 151 | * GPIO handling for EP93xx |
152 | 152 | *************************************************************************/ |
153 | +static unsigned char gpio_int_enable[2]; | |
154 | +static unsigned char gpio_int_type1[2]; | |
155 | +static unsigned char gpio_int_type2[2]; | |
156 | + | |
157 | +static void update_gpio_ab_int_params(int port) | |
158 | +{ | |
159 | + if (port == 0) { | |
160 | + __raw_writeb(0, EP93XX_GPIO_A_INT_ENABLE); | |
161 | + __raw_writeb(gpio_int_type2[0], EP93XX_GPIO_A_INT_TYPE2); | |
162 | + __raw_writeb(gpio_int_type1[0], EP93XX_GPIO_A_INT_TYPE1); | |
163 | + __raw_writeb(gpio_int_enable[0], EP93XX_GPIO_A_INT_ENABLE); | |
164 | + } else if (port == 1) { | |
165 | + __raw_writeb(0, EP93XX_GPIO_B_INT_ENABLE); | |
166 | + __raw_writeb(gpio_int_type2[1], EP93XX_GPIO_B_INT_TYPE2); | |
167 | + __raw_writeb(gpio_int_type1[1], EP93XX_GPIO_B_INT_TYPE1); | |
168 | + __raw_writeb(gpio_int_enable[1], EP93XX_GPIO_B_INT_ENABLE); | |
169 | + } | |
170 | +} | |
171 | + | |
172 | + | |
153 | 173 | static unsigned char data_register_offset[8] = { |
154 | 174 | 0x00, 0x04, 0x08, 0x0c, 0x20, 0x30, 0x38, 0x40, |
155 | 175 | }; |
... | ... | @@ -169,6 +189,11 @@ |
169 | 189 | |
170 | 190 | local_irq_save(flags); |
171 | 191 | if (direction == GPIO_OUT) { |
192 | + if (line >= 0 && line < 16) { | |
193 | + gpio_int_enable[line >> 3] &= ~(1 << (line & 7)); | |
194 | + update_gpio_ab_int_params(line >> 3); | |
195 | + } | |
196 | + | |
172 | 197 | v = __raw_readb(data_direction_register); |
173 | 198 | v |= 1 << (line & 7); |
174 | 199 | __raw_writeb(v, data_direction_register); |
175 | 200 | |
176 | 201 | |
... | ... | @@ -217,10 +242,118 @@ |
217 | 242 | /************************************************************************* |
218 | 243 | * EP93xx IRQ handling |
219 | 244 | *************************************************************************/ |
245 | +static void ep93xx_gpio_ab_irq_handler(unsigned int irq, | |
246 | + struct irqdesc *desc, struct pt_regs *regs) | |
247 | +{ | |
248 | + unsigned char status; | |
249 | + int i; | |
250 | + | |
251 | + status = __raw_readb(EP93XX_GPIO_A_INT_STATUS); | |
252 | + for (i = 0; i < 8; i++) { | |
253 | + if (status & (1 << i)) { | |
254 | + desc = irq_desc + IRQ_EP93XX_GPIO(0) + i; | |
255 | + desc_handle_irq(IRQ_EP93XX_GPIO(0) + i, desc, regs); | |
256 | + } | |
257 | + } | |
258 | + | |
259 | + status = __raw_readb(EP93XX_GPIO_B_INT_STATUS); | |
260 | + for (i = 0; i < 8; i++) { | |
261 | + if (status & (1 << i)) { | |
262 | + desc = irq_desc + IRQ_EP93XX_GPIO(8) + i; | |
263 | + desc_handle_irq(IRQ_EP93XX_GPIO(8) + i, desc, regs); | |
264 | + } | |
265 | + } | |
266 | +} | |
267 | + | |
268 | +static void ep93xx_gpio_ab_irq_mask_ack(unsigned int irq) | |
269 | +{ | |
270 | + int line = irq - IRQ_EP93XX_GPIO(0); | |
271 | + int port = line >> 3; | |
272 | + | |
273 | + gpio_int_enable[port] &= ~(1 << (line & 7)); | |
274 | + update_gpio_ab_int_params(port); | |
275 | + | |
276 | + if (line >> 3) { | |
277 | + __raw_writel(1 << (line & 7), EP93XX_GPIO_B_INT_ACK); | |
278 | + } else { | |
279 | + __raw_writel(1 << (line & 7), EP93XX_GPIO_A_INT_ACK); | |
280 | + } | |
281 | +} | |
282 | + | |
283 | +static void ep93xx_gpio_ab_irq_mask(unsigned int irq) | |
284 | +{ | |
285 | + int line = irq - IRQ_EP93XX_GPIO(0); | |
286 | + int port = line >> 3; | |
287 | + | |
288 | + gpio_int_enable[port] &= ~(1 << (line & 7)); | |
289 | + update_gpio_ab_int_params(port); | |
290 | +} | |
291 | + | |
292 | +static void ep93xx_gpio_ab_irq_unmask(unsigned int irq) | |
293 | +{ | |
294 | + int line = irq - IRQ_EP93XX_GPIO(0); | |
295 | + int port = line >> 3; | |
296 | + | |
297 | + gpio_int_enable[port] |= 1 << (line & 7); | |
298 | + update_gpio_ab_int_params(port); | |
299 | +} | |
300 | + | |
301 | + | |
302 | +/* | |
303 | + * gpio_int_type1 controls whether the interrupt is level (0) or | |
304 | + * edge (1) triggered, while gpio_int_type2 controls whether it | |
305 | + * triggers on low/falling (0) or high/rising (1). | |
306 | + */ | |
307 | +static int ep93xx_gpio_ab_irq_type(unsigned int irq, unsigned int type) | |
308 | +{ | |
309 | + int port; | |
310 | + int line; | |
311 | + | |
312 | + line = irq - IRQ_EP93XX_GPIO(0); | |
313 | + gpio_line_config(line, GPIO_IN); | |
314 | + | |
315 | + port = line >> 3; | |
316 | + line &= 7; | |
317 | + | |
318 | + if (type & IRQT_RISING) { | |
319 | + gpio_int_type1[port] |= 1 << line; | |
320 | + gpio_int_type2[port] |= 1 << line; | |
321 | + } else if (type & IRQT_FALLING) { | |
322 | + gpio_int_type1[port] |= 1 << line; | |
323 | + gpio_int_type2[port] &= ~(1 << line); | |
324 | + } else if (type & IRQT_HIGH) { | |
325 | + gpio_int_type1[port] &= ~(1 << line); | |
326 | + gpio_int_type2[port] |= 1 << line; | |
327 | + } else if (type & IRQT_LOW) { | |
328 | + gpio_int_type1[port] &= ~(1 << line); | |
329 | + gpio_int_type2[port] &= ~(1 << line); | |
330 | + } | |
331 | + update_gpio_ab_int_params(port); | |
332 | + | |
333 | + return 0; | |
334 | +} | |
335 | + | |
336 | +static struct irqchip ep93xx_gpio_ab_irq_chip = { | |
337 | + .ack = ep93xx_gpio_ab_irq_mask_ack, | |
338 | + .mask = ep93xx_gpio_ab_irq_mask, | |
339 | + .unmask = ep93xx_gpio_ab_irq_unmask, | |
340 | + .set_type = ep93xx_gpio_ab_irq_type, | |
341 | +}; | |
342 | + | |
343 | + | |
220 | 344 | void __init ep93xx_init_irq(void) |
221 | 345 | { |
346 | + int irq; | |
347 | + | |
222 | 348 | vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK); |
223 | 349 | vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK); |
350 | + | |
351 | + for (irq = IRQ_EP93XX_GPIO(0) ; irq <= IRQ_EP93XX_GPIO(15); irq++) { | |
352 | + set_irq_chip(irq, &ep93xx_gpio_ab_irq_chip); | |
353 | + set_irq_handler(irq, do_level_IRQ); | |
354 | + set_irq_flags(irq, IRQF_VALID); | |
355 | + } | |
356 | + set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler); | |
224 | 357 | } |
225 | 358 | |
226 | 359 |
include/asm-arm/arch-ep93xx/ep93xx-regs.h
... | ... | @@ -72,6 +72,16 @@ |
72 | 72 | |
73 | 73 | #define EP93XX_GPIO_BASE (EP93XX_APB_VIRT_BASE + 0x00040000) |
74 | 74 | #define EP93XX_GPIO_REG(x) (EP93XX_GPIO_BASE + (x)) |
75 | +#define EP93XX_GPIO_A_INT_TYPE1 EP93XX_GPIO_REG(0x90) | |
76 | +#define EP93XX_GPIO_A_INT_TYPE2 EP93XX_GPIO_REG(0x94) | |
77 | +#define EP93XX_GPIO_A_INT_ACK EP93XX_GPIO_REG(0x98) | |
78 | +#define EP93XX_GPIO_A_INT_ENABLE EP93XX_GPIO_REG(0x9c) | |
79 | +#define EP93XX_GPIO_A_INT_STATUS EP93XX_GPIO_REG(0xa0) | |
80 | +#define EP93XX_GPIO_B_INT_TYPE1 EP93XX_GPIO_REG(0xac) | |
81 | +#define EP93XX_GPIO_B_INT_TYPE2 EP93XX_GPIO_REG(0xb0) | |
82 | +#define EP93XX_GPIO_B_INT_ACK EP93XX_GPIO_REG(0xb4) | |
83 | +#define EP93XX_GPIO_B_INT_ENABLE EP93XX_GPIO_REG(0xb8) | |
84 | +#define EP93XX_GPIO_B_INT_STATUS EP93XX_GPIO_REG(0xbc) | |
75 | 85 | |
76 | 86 | #define EP93XX_AAC_BASE (EP93XX_APB_VIRT_BASE + 0x00080000) |
77 | 87 |
include/asm-arm/arch-ep93xx/irqs.h
... | ... | @@ -67,7 +67,9 @@ |
67 | 67 | #define IRQ_EP93XX_SAI 60 |
68 | 68 | #define EP93XX_VIC2_VALID_IRQ_MASK 0x1fffffff |
69 | 69 | |
70 | -#define NR_EP93XX_IRQS 64 | |
70 | +#define IRQ_EP93XX_GPIO(x) (64 + (x)) | |
71 | + | |
72 | +#define NR_EP93XX_IRQS IRQ_EP93XX_GPIO(16) | |
71 | 73 | |
72 | 74 | #define EP93XX_BOARD_IRQ(x) (NR_EP93XX_IRQS + (x)) |
73 | 75 | #define EP93XX_BOARD_IRQS 32 |