[POWERPC] 85xx: Add support for Wind River SBC8560 in arch/powerpc
[linux-2.6] / arch / arm / mach-ks8695 / irq.c
1 /*
2  * arch/arm/mach-ks8695/irq.c
3  *
4  * Copyright (C) 2006 Ben Dooks <ben@simtec.co.uk>
5  * Copyright (C) 2006 Simtec Electronics
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <linux/init.h>
23 #include <linux/module.h>
24 #include <linux/interrupt.h>
25 #include <linux/ioport.h>
26 #include <linux/sysdev.h>
27
28 #include <asm/hardware.h>
29 #include <asm/irq.h>
30 #include <asm/io.h>
31
32 #include <asm/mach/irq.h>
33
34 #include <asm/arch/regs-irq.h>
35 #include <asm/arch/regs-gpio.h>
36
37 static void ks8695_irq_mask(unsigned int irqno)
38 {
39         unsigned long inten;
40
41         inten = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN);
42         inten &= ~(1 << irqno);
43
44         __raw_writel(inten, KS8695_IRQ_VA + KS8695_INTEN);
45 }
46
47 static void ks8695_irq_unmask(unsigned int irqno)
48 {
49         unsigned long inten;
50
51         inten = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN);
52         inten |= (1 << irqno);
53
54         __raw_writel(inten, KS8695_IRQ_VA + KS8695_INTEN);
55 }
56
57 static void ks8695_irq_ack(unsigned int irqno)
58 {
59         __raw_writel((1 << irqno), KS8695_IRQ_VA + KS8695_INTST);
60 }
61
62
63 static struct irq_chip ks8695_irq_level_chip;
64 static struct irq_chip ks8695_irq_edge_chip;
65
66
67 static int ks8695_irq_set_type(unsigned int irqno, unsigned int type)
68 {
69         unsigned long ctrl, mode;
70         unsigned short level_triggered = 0;
71
72         ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
73
74         switch (type) {
75                 case IRQT_HIGH:
76                         mode = IOPC_TM_HIGH;
77                         level_triggered = 1;
78                         break;
79                 case IRQT_LOW:
80                         mode = IOPC_TM_LOW;
81                         level_triggered = 1;
82                         break;
83                 case IRQT_RISING:
84                         mode = IOPC_TM_RISING;
85                         break;
86                 case IRQT_FALLING:
87                         mode = IOPC_TM_FALLING;
88                         break;
89                 case IRQT_BOTHEDGE:
90                         mode = IOPC_TM_EDGE;
91                         break;
92                 default:
93                         return -EINVAL;
94         }
95
96         switch (irqno) {
97                 case KS8695_IRQ_EXTERN0:
98                         ctrl &= ~IOPC_IOEINT0TM;
99                         ctrl |= IOPC_IOEINT0_MODE(mode);
100                         break;
101                 case KS8695_IRQ_EXTERN1:
102                         ctrl &= ~IOPC_IOEINT1TM;
103                         ctrl |= IOPC_IOEINT1_MODE(mode);
104                         break;
105                 case KS8695_IRQ_EXTERN2:
106                         ctrl &= ~IOPC_IOEINT2TM;
107                         ctrl |= IOPC_IOEINT2_MODE(mode);
108                         break;
109                 case KS8695_IRQ_EXTERN3:
110                         ctrl &= ~IOPC_IOEINT3TM;
111                         ctrl |= IOPC_IOEINT3_MODE(mode);
112                         break;
113                 default:
114                         return -EINVAL;
115         }
116
117         if (level_triggered) {
118                 set_irq_chip(irqno, &ks8695_irq_level_chip);
119                 set_irq_handler(irqno, handle_level_irq);
120         }
121         else {
122                 set_irq_chip(irqno, &ks8695_irq_edge_chip);
123                 set_irq_handler(irqno, handle_edge_irq);
124         }
125
126         __raw_writel(ctrl, KS8695_GPIO_VA + KS8695_IOPC);
127         return 0;
128 }
129
130 static struct irq_chip ks8695_irq_level_chip = {
131         .ack            = ks8695_irq_mask,
132         .mask           = ks8695_irq_mask,
133         .unmask         = ks8695_irq_unmask,
134         .set_type       = ks8695_irq_set_type,
135 };
136
137 static struct irq_chip ks8695_irq_edge_chip = {
138         .ack            = ks8695_irq_ack,
139         .mask           = ks8695_irq_mask,
140         .unmask         = ks8695_irq_unmask,
141         .set_type       = ks8695_irq_set_type,
142 };
143
144 void __init ks8695_init_irq(void)
145 {
146         unsigned int irq;
147
148         /* Disable all interrupts initially */
149         __raw_writel(0, KS8695_IRQ_VA + KS8695_INTMC);
150         __raw_writel(0, KS8695_IRQ_VA + KS8695_INTEN);
151
152         for (irq = 0; irq < NR_IRQS; irq++) {
153                 switch (irq) {
154                         /* Level-triggered interrupts */
155                         case KS8695_IRQ_BUS_ERROR:
156                         case KS8695_IRQ_UART_MODEM_STATUS:
157                         case KS8695_IRQ_UART_LINE_STATUS:
158                         case KS8695_IRQ_UART_RX:
159                         case KS8695_IRQ_COMM_TX:
160                         case KS8695_IRQ_COMM_RX:
161                                 set_irq_chip(irq, &ks8695_irq_level_chip);
162                                 set_irq_handler(irq, handle_level_irq);
163                                 break;
164
165                         /* Edge-triggered interrupts */
166                         default:
167                                 ks8695_irq_ack(irq);    /* clear pending bit */
168                                 set_irq_chip(irq, &ks8695_irq_edge_chip);
169                                 set_irq_handler(irq, handle_edge_irq);
170                 }
171
172                 set_irq_flags(irq, IRQF_VALID);
173         }
174 }