Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen...
[linux-2.6] / arch / mips / txx9 / rbtx4939 / irq.c
1 /*
2  * Toshiba RBTX4939 interrupt routines
3  * Based on linux/arch/mips/txx9/rbtx4938/irq.c,
4  *          and RBTX49xx patch from CELF patch archive.
5  *
6  * Copyright (C) 2000-2001,2005-2006 Toshiba Corporation
7  * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
8  * terms of the GNU General Public License version 2. This program is
9  * licensed "as is" without any warranty of any kind, whether express
10  * or implied.
11  */
12 #include <linux/init.h>
13 #include <linux/interrupt.h>
14 #include <asm/mipsregs.h>
15 #include <asm/txx9/rbtx4939.h>
16
17 /*
18  * RBTX4939 IOC controller definition
19  */
20
21 static void rbtx4939_ioc_irq_unmask(unsigned int irq)
22 {
23         int ioc_nr = irq - RBTX4939_IRQ_IOC;
24
25         writeb(readb(rbtx4939_ien_addr) | (1 << ioc_nr), rbtx4939_ien_addr);
26 }
27
28 static void rbtx4939_ioc_irq_mask(unsigned int irq)
29 {
30         int ioc_nr = irq - RBTX4939_IRQ_IOC;
31
32         writeb(readb(rbtx4939_ien_addr) & ~(1 << ioc_nr), rbtx4939_ien_addr);
33         mmiowb();
34 }
35
36 static struct irq_chip rbtx4939_ioc_irq_chip = {
37         .name           = "IOC",
38         .ack            = rbtx4939_ioc_irq_mask,
39         .mask           = rbtx4939_ioc_irq_mask,
40         .mask_ack       = rbtx4939_ioc_irq_mask,
41         .unmask         = rbtx4939_ioc_irq_unmask,
42 };
43
44
45 static inline int rbtx4939_ioc_irqroute(void)
46 {
47         unsigned char istat = readb(rbtx4939_ifac2_addr);
48
49         if (unlikely(istat == 0))
50                 return -1;
51         return RBTX4939_IRQ_IOC + __fls8(istat);
52 }
53
54 static int rbtx4939_irq_dispatch(int pending)
55 {
56         int irq;
57
58         if (pending & CAUSEF_IP7)
59                 return MIPS_CPU_IRQ_BASE + 7;
60         irq = tx4939_irq();
61         if (likely(irq >= 0)) {
62                 /* redirect IOC interrupts */
63                 switch (irq) {
64                 case RBTX4939_IRQ_IOCINT:
65                         irq = rbtx4939_ioc_irqroute();
66                         break;
67                 }
68         } else if (pending & CAUSEF_IP0)
69                 irq = MIPS_CPU_IRQ_BASE + 0;
70         else if (pending & CAUSEF_IP1)
71                 irq = MIPS_CPU_IRQ_BASE + 1;
72         else
73                 irq = -1;
74         return irq;
75 }
76
77 void __init rbtx4939_irq_setup(void)
78 {
79         int i;
80
81         /* mask all IOC interrupts */
82         writeb(0, rbtx4939_ien_addr);
83
84         /* clear SoftInt interrupts */
85         writeb(0, rbtx4939_softint_addr);
86
87         txx9_irq_dispatch = rbtx4939_irq_dispatch;
88
89         tx4939_irq_init();
90         for (i = RBTX4939_IRQ_IOC;
91              i < RBTX4939_IRQ_IOC + RBTX4939_NR_IRQ_IOC; i++)
92                 set_irq_chip_and_handler(i, &rbtx4939_ioc_irq_chip,
93                                          handle_level_irq);
94
95         set_irq_chained_handler(RBTX4939_IRQ_IOCINT, handle_simple_irq);
96 }