aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2006-03-20 16:02:37 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-03-21 17:06:21 -0500
commitbd20ff5793b4ece4fa3e9e0fcf8e6bbd93526215 (patch)
tree3241a5ab8b8ff5e00107f80417d5dc75e57e8acb /arch/arm
parent36c64af4e013ddf44c44298f50ff138ef1e2e7b7 (diff)
[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>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-ep93xx/core.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 7d3e79990fad..865427bfad7e 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -150,6 +150,26 @@ struct sys_timer ep93xx_timer = {
150/************************************************************************* 150/*************************************************************************
151 * GPIO handling for EP93xx 151 * GPIO handling for EP93xx
152 *************************************************************************/ 152 *************************************************************************/
153static unsigned char gpio_int_enable[2];
154static unsigned char gpio_int_type1[2];
155static unsigned char gpio_int_type2[2];
156
157static 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
153static unsigned char data_register_offset[8] = { 173static unsigned char data_register_offset[8] = {
154 0x00, 0x04, 0x08, 0x0c, 0x20, 0x30, 0x38, 0x40, 174 0x00, 0x04, 0x08, 0x0c, 0x20, 0x30, 0x38, 0x40,
155}; 175};
@@ -169,6 +189,11 @@ void gpio_line_config(int line, int direction)
169 189
170 local_irq_save(flags); 190 local_irq_save(flags);
171 if (direction == GPIO_OUT) { 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 v = __raw_readb(data_direction_register); 197 v = __raw_readb(data_direction_register);
173 v |= 1 << (line & 7); 198 v |= 1 << (line & 7);
174 __raw_writeb(v, data_direction_register); 199 __raw_writeb(v, data_direction_register);
@@ -217,10 +242,118 @@ EXPORT_SYMBOL(gpio_line_set);
217/************************************************************************* 242/*************************************************************************
218 * EP93xx IRQ handling 243 * EP93xx IRQ handling
219 *************************************************************************/ 244 *************************************************************************/
245static 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
268static 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
283static 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
292static 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 */
307static 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
336static 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
220void __init ep93xx_init_irq(void) 344void __init ep93xx_init_irq(void)
221{ 345{
346 int irq;
347
222 vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK); 348 vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK);
223 vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK); 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