2 * giu.c, General-purpose I/O Unit Interrupt routines for NEC VR4100 series.
4 * Copyright (C) 2002 MontaVista Software Inc.
5 * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
6 * Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
25 * - New creation, NEC VR4111, VR4121, VR4122 and VR4131 are supported.
27 * Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
28 * - Added support for NEC VR4133.
29 * - Removed board_irq_init.
31 #include <linux/errno.h>
32 #include <linux/init.h>
33 #include <linux/irq.h>
34 #include <linux/kernel.h>
35 #include <linux/smp.h>
36 #include <linux/types.h>
40 #include <asm/vr41xx/vr41xx.h>
42 #define GIUIOSELL_TYPE1 KSEG1ADDR(0x0b000100)
43 #define GIUIOSELL_TYPE2 KSEG1ADDR(0x0f000140)
45 #define GIUIOSELL 0x00
46 #define GIUIOSELH 0x02
47 #define GIUINTSTATL 0x08
48 #define GIUINTSTATH 0x0a
49 #define GIUINTENL 0x0c
50 #define GIUINTENH 0x0e
51 #define GIUINTTYPL 0x10
52 #define GIUINTTYPH 0x12
53 #define GIUINTALSELL 0x14
54 #define GIUINTALSELH 0x16
55 #define GIUINTHTSELL 0x18
56 #define GIUINTHTSELH 0x1a
57 #define GIUFEDGEINHL 0x20
58 #define GIUFEDGEINHH 0x22
59 #define GIUREDGEINHL 0x24
60 #define GIUREDGEINHH 0x26
62 static uint32_t giu_base;
64 #define read_giuint(offset) readw(giu_base + (offset))
65 #define write_giuint(val, offset) writew((val), giu_base + (offset))
67 static inline uint16_t set_giuint(uint8_t offset, uint16_t set)
71 res = read_giuint(offset);
73 write_giuint(res, offset);
78 static inline uint16_t clear_giuint(uint8_t offset, uint16_t clear)
82 res = read_giuint(offset);
84 write_giuint(res, offset);
89 void vr41xx_enable_giuint(int pin)
92 set_giuint(GIUINTENL, (uint16_t)1 << pin);
94 set_giuint(GIUINTENH, (uint16_t)1 << (pin - 16));
97 void vr41xx_disable_giuint(int pin)
100 clear_giuint(GIUINTENL, (uint16_t)1 << pin);
102 clear_giuint(GIUINTENH, (uint16_t)1 << (pin - 16));
105 void vr41xx_clear_giuint(int pin)
108 write_giuint((uint16_t)1 << pin, GIUINTSTATL);
110 write_giuint((uint16_t)1 << (pin - 16), GIUINTSTATH);
113 void vr41xx_set_irq_trigger(int pin, int trigger, int hold)
118 mask = (uint16_t)1 << pin;
119 if (trigger != TRIGGER_LEVEL) {
120 set_giuint(GIUINTTYPL, mask);
121 if (hold == SIGNAL_HOLD)
122 set_giuint(GIUINTHTSELL, mask);
124 clear_giuint(GIUINTHTSELL, mask);
125 if (current_cpu_data.cputype == CPU_VR4133) {
127 case TRIGGER_EDGE_FALLING:
128 set_giuint(GIUFEDGEINHL, mask);
129 clear_giuint(GIUREDGEINHL, mask);
131 case TRIGGER_EDGE_RISING:
132 clear_giuint(GIUFEDGEINHL, mask);
133 set_giuint(GIUREDGEINHL, mask);
136 set_giuint(GIUFEDGEINHL, mask);
137 set_giuint(GIUREDGEINHL, mask);
142 clear_giuint(GIUINTTYPL, mask);
143 clear_giuint(GIUINTHTSELL, mask);
146 mask = (uint16_t)1 << (pin - 16);
147 if (trigger != TRIGGER_LEVEL) {
148 set_giuint(GIUINTTYPH, mask);
149 if (hold == SIGNAL_HOLD)
150 set_giuint(GIUINTHTSELH, mask);
152 clear_giuint(GIUINTHTSELH, mask);
153 if (current_cpu_data.cputype == CPU_VR4133) {
155 case TRIGGER_EDGE_FALLING:
156 set_giuint(GIUFEDGEINHH, mask);
157 clear_giuint(GIUREDGEINHH, mask);
159 case TRIGGER_EDGE_RISING:
160 clear_giuint(GIUFEDGEINHH, mask);
161 set_giuint(GIUREDGEINHH, mask);
164 set_giuint(GIUFEDGEINHH, mask);
165 set_giuint(GIUREDGEINHH, mask);
170 clear_giuint(GIUINTTYPH, mask);
171 clear_giuint(GIUINTHTSELH, mask);
175 vr41xx_clear_giuint(pin);
178 void vr41xx_set_irq_level(int pin, int level)
183 mask = (uint16_t)1 << pin;
184 if (level == LEVEL_HIGH)
185 set_giuint(GIUINTALSELL, mask);
187 clear_giuint(GIUINTALSELL, mask);
189 mask = (uint16_t)1 << (pin - 16);
190 if (level == LEVEL_HIGH)
191 set_giuint(GIUINTALSELH, mask);
193 clear_giuint(GIUINTALSELH, mask);
196 vr41xx_clear_giuint(pin);
199 #define GIUINT_NR_IRQS 32
206 struct vr41xx_giuint_cascade {
208 int (*get_irq_number)(int irq);
211 static struct vr41xx_giuint_cascade giuint_cascade[GIUINT_NR_IRQS];
212 static struct irqaction giu_cascade = {no_action, 0, 0, "cascade", NULL, NULL};
214 static int no_irq_number(int irq)
219 int vr41xx_cascade_irq(unsigned int irq, int (*get_irq_number)(int irq))
224 if (irq < GIU_IRQ(0) || irq > GIU_IRQ(31))
230 pin = GIU_IRQ_TO_PIN(irq);
231 giuint_cascade[pin].flag = GIUINT_CASCADE;
232 giuint_cascade[pin].get_irq_number = get_irq_number;
234 retval = setup_irq(irq, &giu_cascade);
236 giuint_cascade[pin].flag = GIUINT_NO_CASCADE;
237 giuint_cascade[pin].get_irq_number = no_irq_number;
243 unsigned int giuint_do_IRQ(int pin, struct pt_regs *regs)
245 struct vr41xx_giuint_cascade *cascade;
246 unsigned int retval = 0;
247 int giuint_irq, cascade_irq;
249 disable_irq(GIUINT_CASCADE_IRQ);
250 cascade = &giuint_cascade[pin];
251 giuint_irq = GIU_IRQ(pin);
252 if (cascade->flag == GIUINT_CASCADE) {
253 cascade_irq = cascade->get_irq_number(giuint_irq);
254 disable_irq(giuint_irq);
256 retval = do_IRQ(cascade_irq, regs);
257 enable_irq(giuint_irq);
259 retval = do_IRQ(giuint_irq, regs);
260 enable_irq(GIUINT_CASCADE_IRQ);
265 void __init vr41xx_giuint_init(void)
269 switch (current_cpu_data.cputype) {
272 giu_base = GIUIOSELL_TYPE1;
277 giu_base = GIUIOSELL_TYPE2;
280 panic("GIU: Unexpected CPU of NEC VR4100 series");
284 for (i = 0; i < GIUINT_NR_IRQS; i++) {
285 vr41xx_disable_giuint(i);
286 giuint_cascade[i].flag = GIUINT_NO_CASCADE;
287 giuint_cascade[i].get_irq_number = no_irq_number;
290 if (setup_irq(GIUINT_CASCADE_IRQ, &giu_cascade))
291 printk("GIUINT: Can not cascade IRQ %d.\n", GIUINT_CASCADE_IRQ);