blob: 0cea8d4907dfb965d509e356f51c18ca23118756 [file] [log] [blame]
Yoichi Yuasae400bae2005-06-21 17:15:56 -07001/*
2 * Driver for NEC VR4100 series General-purpose I/O Unit.
3 *
4 * Copyright (C) 2002 MontaVista Software Inc.
5 * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +09006 * Copyright (C) 2003-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
Yoichi Yuasae400bae2005-06-21 17:15:56 -07007 *
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.
12 *
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.
17 *
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
21 */
Russell Kingd052d1b2005-10-29 19:07:23 +010022#include <linux/platform_device.h>
Yoichi Yuasae400bae2005-06-21 17:15:56 -070023#include <linux/errno.h>
24#include <linux/fs.h>
25#include <linux/init.h>
26#include <linux/irq.h>
27#include <linux/interrupt.h>
28#include <linux/kernel.h>
29#include <linux/module.h>
30#include <linux/spinlock.h>
31#include <linux/types.h>
32
33#include <asm/cpu.h>
34#include <asm/io.h>
35#include <asm/vr41xx/giu.h>
Yoichi Yuasa66151bb2006-07-13 17:33:03 +090036#include <asm/vr41xx/irq.h>
Yoichi Yuasae400bae2005-06-21 17:15:56 -070037#include <asm/vr41xx/vr41xx.h>
38
Ralf Baechle29ce2c72005-12-12 20:11:50 +000039MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
Yoichi Yuasae400bae2005-06-21 17:15:56 -070040MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver");
41MODULE_LICENSE("GPL");
42
43static int major; /* default is dynamic major device number */
44module_param(major, int, 0);
45MODULE_PARM_DESC(major, "Major device number");
46
47#define GIU_TYPE1_START 0x0b000100UL
48#define GIU_TYPE1_SIZE 0x20UL
49
50#define GIU_TYPE2_START 0x0f000140UL
51#define GIU_TYPE2_SIZE 0x20UL
52
53#define GIU_TYPE3_START 0x0f000140UL
54#define GIU_TYPE3_SIZE 0x28UL
55
56#define GIU_PULLUPDOWN_START 0x0b0002e0UL
57#define GIU_PULLUPDOWN_SIZE 0x04UL
58
59#define GIUIOSELL 0x00
60#define GIUIOSELH 0x02
61#define GIUPIODL 0x04
62#define GIUPIODH 0x06
63#define GIUINTSTATL 0x08
64#define GIUINTSTATH 0x0a
65#define GIUINTENL 0x0c
66#define GIUINTENH 0x0e
67#define GIUINTTYPL 0x10
68#define GIUINTTYPH 0x12
69#define GIUINTALSELL 0x14
70#define GIUINTALSELH 0x16
71#define GIUINTHTSELL 0x18
72#define GIUINTHTSELH 0x1a
73#define GIUPODATL 0x1c
74#define GIUPODATEN 0x1c
75#define GIUPODATH 0x1e
76 #define PIOEN0 0x0100
77 #define PIOEN1 0x0200
78#define GIUPODAT 0x1e
79#define GIUFEDGEINHL 0x20
80#define GIUFEDGEINHH 0x22
81#define GIUREDGEINHL 0x24
82#define GIUREDGEINHH 0x26
83
84#define GIUUSEUPDN 0x1e0
85#define GIUTERMUPDN 0x1e2
86
87#define GPIO_HAS_PULLUPDOWN_IO 0x0001
88#define GPIO_HAS_OUTPUT_ENABLE 0x0002
89#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100
90
91static spinlock_t giu_lock;
92static struct resource *giu_resource1;
93static struct resource *giu_resource2;
94static unsigned long giu_flags;
95static unsigned int giu_nr_pins;
96
97static void __iomem *giu_base;
98
99#define giu_read(offset) readw(giu_base + (offset))
100#define giu_write(offset, value) writew((value), giu_base + (offset))
101
102#define GPIO_PIN_OF_IRQ(irq) ((irq) - GIU_IRQ_BASE)
103#define GIUINT_HIGH_OFFSET 16
104#define GIUINT_HIGH_MAX 32
105
106static inline uint16_t giu_set(uint16_t offset, uint16_t set)
107{
108 uint16_t data;
109
110 data = giu_read(offset);
111 data |= set;
112 giu_write(offset, data);
113
114 return data;
115}
116
117static inline uint16_t giu_clear(uint16_t offset, uint16_t clear)
118{
119 uint16_t data;
120
121 data = giu_read(offset);
122 data &= ~clear;
123 giu_write(offset, data);
124
125 return data;
126}
127
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900128static void ack_giuint_low(unsigned int irq)
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700129{
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900130 giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq));
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700131}
132
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900133static void mask_giuint_low(unsigned int irq)
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700134{
135 giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
136}
137
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900138static void mask_ack_giuint_low(unsigned int irq)
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700139{
140 unsigned int pin;
141
142 pin = GPIO_PIN_OF_IRQ(irq);
143 giu_clear(GIUINTENL, 1 << pin);
144 giu_write(GIUINTSTATL, 1 << pin);
145}
146
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900147static void unmask_giuint_low(unsigned int irq)
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700148{
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900149 giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700150}
151
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900152static struct irq_chip giuint_low_irq_chip = {
153 .name = "GIUINTL",
154 .ack = ack_giuint_low,
155 .mask = mask_giuint_low,
156 .mask_ack = mask_ack_giuint_low,
157 .unmask = unmask_giuint_low,
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700158};
159
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900160static void ack_giuint_high(unsigned int irq)
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700161{
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900162 giu_write(GIUINTSTATH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700163}
164
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900165static void mask_giuint_high(unsigned int irq)
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700166{
167 giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
168}
169
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900170static void mask_ack_giuint_high(unsigned int irq)
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700171{
172 unsigned int pin;
173
174 pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET;
175 giu_clear(GIUINTENH, 1 << pin);
176 giu_write(GIUINTSTATH, 1 << pin);
177}
178
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900179static void unmask_giuint_high(unsigned int irq)
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700180{
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900181 giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700182}
183
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900184static struct irq_chip giuint_high_irq_chip = {
185 .name = "GIUINTH",
186 .ack = ack_giuint_high,
187 .mask = mask_giuint_high,
188 .mask_ack = mask_ack_giuint_high,
189 .unmask = unmask_giuint_high,
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700190};
191
David Howells7d12e782006-10-05 14:55:46 +0100192static int giu_get_irq(unsigned int irq)
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700193{
194 uint16_t pendl, pendh, maskl, maskh;
195 int i;
196
197 pendl = giu_read(GIUINTSTATL);
198 pendh = giu_read(GIUINTSTATH);
199 maskl = giu_read(GIUINTENL);
200 maskh = giu_read(GIUINTENH);
201
202 maskl &= pendl;
203 maskh &= pendh;
204
205 if (maskl) {
206 for (i = 0; i < 16; i++) {
207 if (maskl & (1 << i))
208 return GIU_IRQ(i);
209 }
210 } else if (maskh) {
211 for (i = 0; i < 16; i++) {
212 if (maskh & (1 << i))
213 return GIU_IRQ(i + GIUINT_HIGH_OFFSET);
214 }
215 }
216
217 printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
218 maskl, pendl, maskh, pendh);
219
220 atomic_inc(&irq_err_count);
221
222 return -EINVAL;
223}
224
225void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal)
226{
227 uint16_t mask;
228
229 if (pin < GIUINT_HIGH_OFFSET) {
230 mask = 1 << pin;
231 if (trigger != IRQ_TRIGGER_LEVEL) {
232 giu_set(GIUINTTYPL, mask);
233 if (signal == IRQ_SIGNAL_HOLD)
234 giu_set(GIUINTHTSELL, mask);
235 else
236 giu_clear(GIUINTHTSELL, mask);
237 if (current_cpu_data.cputype == CPU_VR4133) {
238 switch (trigger) {
239 case IRQ_TRIGGER_EDGE_FALLING:
240 giu_set(GIUFEDGEINHL, mask);
241 giu_clear(GIUREDGEINHL, mask);
242 break;
243 case IRQ_TRIGGER_EDGE_RISING:
244 giu_clear(GIUFEDGEINHL, mask);
245 giu_set(GIUREDGEINHL, mask);
246 break;
247 default:
248 giu_set(GIUFEDGEINHL, mask);
249 giu_set(GIUREDGEINHL, mask);
250 break;
251 }
252 }
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900253 set_irq_chip_and_handler(GIU_IRQ(pin),
254 &giuint_low_irq_chip,
255 handle_edge_irq);
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700256 } else {
257 giu_clear(GIUINTTYPL, mask);
258 giu_clear(GIUINTHTSELL, mask);
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900259 set_irq_chip_and_handler(GIU_IRQ(pin),
260 &giuint_low_irq_chip,
261 handle_level_irq);
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700262 }
263 giu_write(GIUINTSTATL, mask);
264 } else if (pin < GIUINT_HIGH_MAX) {
265 mask = 1 << (pin - GIUINT_HIGH_OFFSET);
266 if (trigger != IRQ_TRIGGER_LEVEL) {
267 giu_set(GIUINTTYPH, mask);
268 if (signal == IRQ_SIGNAL_HOLD)
269 giu_set(GIUINTHTSELH, mask);
270 else
271 giu_clear(GIUINTHTSELH, mask);
272 if (current_cpu_data.cputype == CPU_VR4133) {
273 switch (trigger) {
274 case IRQ_TRIGGER_EDGE_FALLING:
275 giu_set(GIUFEDGEINHH, mask);
276 giu_clear(GIUREDGEINHH, mask);
277 break;
278 case IRQ_TRIGGER_EDGE_RISING:
279 giu_clear(GIUFEDGEINHH, mask);
280 giu_set(GIUREDGEINHH, mask);
281 break;
282 default:
283 giu_set(GIUFEDGEINHH, mask);
284 giu_set(GIUREDGEINHH, mask);
285 break;
286 }
287 }
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900288 set_irq_chip_and_handler(GIU_IRQ(pin),
289 &giuint_high_irq_chip,
290 handle_edge_irq);
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700291 } else {
292 giu_clear(GIUINTTYPH, mask);
293 giu_clear(GIUINTHTSELH, mask);
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900294 set_irq_chip_and_handler(GIU_IRQ(pin),
295 &giuint_high_irq_chip,
296 handle_level_irq);
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700297 }
298 giu_write(GIUINTSTATH, mask);
299 }
300}
301
302EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
303
304void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
305{
306 uint16_t mask;
307
308 if (pin < GIUINT_HIGH_OFFSET) {
309 mask = 1 << pin;
310 if (level == IRQ_LEVEL_HIGH)
311 giu_set(GIUINTALSELL, mask);
312 else
313 giu_clear(GIUINTALSELL, mask);
314 giu_write(GIUINTSTATL, mask);
315 } else if (pin < GIUINT_HIGH_MAX) {
316 mask = 1 << (pin - GIUINT_HIGH_OFFSET);
317 if (level == IRQ_LEVEL_HIGH)
318 giu_set(GIUINTALSELH, mask);
319 else
320 giu_clear(GIUINTALSELH, mask);
321 giu_write(GIUINTSTATH, mask);
322 }
323}
324
325EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
326
327gpio_data_t vr41xx_gpio_get_pin(unsigned int pin)
328{
329 uint16_t reg, mask;
330
331 if (pin >= giu_nr_pins)
332 return GPIO_DATA_INVAL;
333
334 if (pin < 16) {
335 reg = giu_read(GIUPIODL);
336 mask = (uint16_t)1 << pin;
337 } else if (pin < 32) {
338 reg = giu_read(GIUPIODH);
339 mask = (uint16_t)1 << (pin - 16);
340 } else if (pin < 48) {
341 reg = giu_read(GIUPODATL);
342 mask = (uint16_t)1 << (pin - 32);
343 } else {
344 reg = giu_read(GIUPODATH);
345 mask = (uint16_t)1 << (pin - 48);
346 }
347
348 if (reg & mask)
349 return GPIO_DATA_HIGH;
350
351 return GPIO_DATA_LOW;
352}
353
354EXPORT_SYMBOL_GPL(vr41xx_gpio_get_pin);
355
356int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data)
357{
358 uint16_t offset, mask, reg;
359 unsigned long flags;
360
361 if (pin >= giu_nr_pins)
362 return -EINVAL;
363
364 if (pin < 16) {
365 offset = GIUPIODL;
366 mask = (uint16_t)1 << pin;
367 } else if (pin < 32) {
368 offset = GIUPIODH;
369 mask = (uint16_t)1 << (pin - 16);
370 } else if (pin < 48) {
371 offset = GIUPODATL;
372 mask = (uint16_t)1 << (pin - 32);
373 } else {
374 offset = GIUPODATH;
375 mask = (uint16_t)1 << (pin - 48);
376 }
377
378 spin_lock_irqsave(&giu_lock, flags);
379
380 reg = giu_read(offset);
381 if (data == GPIO_DATA_HIGH)
382 reg |= mask;
383 else
384 reg &= ~mask;
385 giu_write(offset, reg);
386
387 spin_unlock_irqrestore(&giu_lock, flags);
388
389 return 0;
390}
391
392EXPORT_SYMBOL_GPL(vr41xx_gpio_set_pin);
393
394int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir)
395{
396 uint16_t offset, mask, reg;
397 unsigned long flags;
398
399 if (pin >= giu_nr_pins)
400 return -EINVAL;
401
402 if (pin < 16) {
403 offset = GIUIOSELL;
404 mask = (uint16_t)1 << pin;
405 } else if (pin < 32) {
406 offset = GIUIOSELH;
407 mask = (uint16_t)1 << (pin - 16);
408 } else {
409 if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {
410 offset = GIUPODATEN;
411 mask = (uint16_t)1 << (pin - 32);
412 } else {
413 switch (pin) {
414 case 48:
415 offset = GIUPODATH;
416 mask = PIOEN0;
417 break;
418 case 49:
419 offset = GIUPODATH;
420 mask = PIOEN1;
421 break;
422 default:
423 return -EINVAL;
424 }
425 }
426 }
427
428 spin_lock_irqsave(&giu_lock, flags);
429
430 reg = giu_read(offset);
431 if (dir == GPIO_OUTPUT)
432 reg |= mask;
433 else
434 reg &= ~mask;
435 giu_write(offset, reg);
436
437 spin_unlock_irqrestore(&giu_lock, flags);
438
439 return 0;
440}
441
442EXPORT_SYMBOL_GPL(vr41xx_gpio_set_direction);
443
444int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
445{
446 uint16_t reg, mask;
447 unsigned long flags;
448
449 if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)
450 return -EPERM;
451
452 if (pin >= 15)
453 return -EINVAL;
454
455 mask = (uint16_t)1 << pin;
456
457 spin_lock_irqsave(&giu_lock, flags);
458
459 if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {
460 reg = giu_read(GIUTERMUPDN);
461 if (pull == GPIO_PULL_UP)
462 reg |= mask;
463 else
464 reg &= ~mask;
465 giu_write(GIUTERMUPDN, reg);
466
467 reg = giu_read(GIUUSEUPDN);
468 reg |= mask;
469 giu_write(GIUUSEUPDN, reg);
470 } else {
471 reg = giu_read(GIUUSEUPDN);
472 reg &= ~mask;
473 giu_write(GIUUSEUPDN, reg);
474 }
475
476 spin_unlock_irqrestore(&giu_lock, flags);
477
478 return 0;
479}
480
481EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
482
483static ssize_t gpio_read(struct file *file, char __user *buf, size_t len,
484 loff_t *ppos)
485{
486 unsigned int pin;
487 char value = '0';
488
Josef Sipeka7113a92006-12-08 02:36:55 -0800489 pin = iminor(file->f_path.dentry->d_inode);
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700490 if (pin >= giu_nr_pins)
491 return -EBADF;
492
493 if (vr41xx_gpio_get_pin(pin) == GPIO_DATA_HIGH)
494 value = '1';
495
496 if (len <= 0)
497 return -EFAULT;
498
499 if (put_user(value, buf))
500 return -EFAULT;
501
502 return 1;
503}
504
505static ssize_t gpio_write(struct file *file, const char __user *data,
506 size_t len, loff_t *ppos)
507{
508 unsigned int pin;
509 size_t i;
510 char c;
511 int retval = 0;
512
Josef Sipeka7113a92006-12-08 02:36:55 -0800513 pin = iminor(file->f_path.dentry->d_inode);
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700514 if (pin >= giu_nr_pins)
515 return -EBADF;
516
517 for (i = 0; i < len; i++) {
518 if (get_user(c, data + i))
519 return -EFAULT;
520
521 switch (c) {
522 case '0':
523 retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_LOW);
524 break;
525 case '1':
526 retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_HIGH);
527 break;
528 case 'D':
529 printk(KERN_INFO "GPIO%d: pull down\n", pin);
530 retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DOWN);
531 break;
532 case 'd':
533 printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin);
534 retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE);
535 break;
536 case 'I':
537 printk(KERN_INFO "GPIO%d: input\n", pin);
538 retval = vr41xx_gpio_set_direction(pin, GPIO_INPUT);
539 break;
540 case 'O':
541 printk(KERN_INFO "GPIO%d: output\n", pin);
542 retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT);
543 break;
544 case 'o':
545 printk(KERN_INFO "GPIO%d: output disable\n", pin);
546 retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT_DISABLE);
547 break;
548 case 'P':
549 printk(KERN_INFO "GPIO%d: pull up\n", pin);
550 retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_UP);
551 break;
552 case 'p':
553 printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin);
554 retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE);
555 break;
556 default:
557 break;
558 }
559
560 if (retval < 0)
561 break;
562 }
563
564 return i;
565}
566
567static int gpio_open(struct inode *inode, struct file *file)
568{
569 unsigned int pin;
570
571 pin = iminor(inode);
572 if (pin >= giu_nr_pins)
573 return -EBADF;
574
575 return nonseekable_open(inode, file);
576}
577
578static int gpio_release(struct inode *inode, struct file *file)
579{
580 unsigned int pin;
581
582 pin = iminor(inode);
583 if (pin >= giu_nr_pins)
584 return -EBADF;
585
586 return 0;
587}
588
Arjan van de Ven62322d22006-07-03 00:24:21 -0700589static const struct file_operations gpio_fops = {
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700590 .owner = THIS_MODULE,
591 .read = gpio_read,
592 .write = gpio_write,
593 .open = gpio_open,
594 .release = gpio_release,
595};
596
Dmitry Torokhovd39b6cf2006-03-22 00:07:53 -0800597static int __devinit giu_probe(struct platform_device *dev)
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700598{
599 unsigned long start, size, flags = 0;
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900600 unsigned int nr_pins = 0, trigger, i, pin;
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700601 struct resource *res1, *res2 = NULL;
602 void *base;
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900603 struct irq_chip *chip;
604 int retval;
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700605
606 switch (current_cpu_data.cputype) {
607 case CPU_VR4111:
608 case CPU_VR4121:
609 start = GIU_TYPE1_START;
610 size = GIU_TYPE1_SIZE;
611 flags = GPIO_HAS_PULLUPDOWN_IO;
612 nr_pins = 50;
613 break;
614 case CPU_VR4122:
615 case CPU_VR4131:
616 start = GIU_TYPE2_START;
617 size = GIU_TYPE2_SIZE;
618 nr_pins = 36;
619 break;
620 case CPU_VR4133:
621 start = GIU_TYPE3_START;
622 size = GIU_TYPE3_SIZE;
623 flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
624 nr_pins = 48;
625 break;
626 default:
627 return -ENODEV;
628 }
629
630 res1 = request_mem_region(start, size, "GIU");
631 if (res1 == NULL)
632 return -EBUSY;
633
634 base = ioremap(start, size);
635 if (base == NULL) {
636 release_resource(res1);
637 return -ENOMEM;
638 }
639
640 if (flags & GPIO_HAS_PULLUPDOWN_IO) {
641 res2 = request_mem_region(GIU_PULLUPDOWN_START, GIU_PULLUPDOWN_SIZE, "GIU");
642 if (res2 == NULL) {
643 iounmap(base);
644 release_resource(res1);
645 return -EBUSY;
646 }
647 }
648
649 retval = register_chrdev(major, "GIU", &gpio_fops);
650 if (retval < 0) {
651 iounmap(base);
652 release_resource(res1);
653 release_resource(res2);
654 return retval;
655 }
656
657 if (major == 0) {
658 major = retval;
659 printk(KERN_INFO "GIU: major number %d\n", major);
660 }
661
662 spin_lock_init(&giu_lock);
663 giu_base = base;
664 giu_resource1 = res1;
665 giu_resource2 = res2;
666 giu_flags = flags;
667 giu_nr_pins = nr_pins;
668
669 giu_write(GIUINTENL, 0);
670 giu_write(GIUINTENH, 0);
671
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900672 trigger = giu_read(GIUINTTYPH) << 16;
673 trigger |= giu_read(GIUINTTYPL);
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700674 for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900675 pin = GPIO_PIN_OF_IRQ(i);
676 if (pin < GIUINT_HIGH_OFFSET)
677 chip = &giuint_low_irq_chip;
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700678 else
Yoichi Yuasa364ca8a2007-01-22 23:01:06 +0900679 chip = &giuint_high_irq_chip;
680
681 if (trigger & (1 << pin))
682 set_irq_chip_and_handler(i, chip, handle_edge_irq);
683 else
684 set_irq_chip_and_handler(i, chip, handle_level_irq);
685
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700686 }
687
688 return cascade_irq(GIUINT_IRQ, giu_get_irq);
689}
690
Dmitry Torokhovd39b6cf2006-03-22 00:07:53 -0800691static int __devexit giu_remove(struct platform_device *dev)
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700692{
693 iounmap(giu_base);
694
695 release_resource(giu_resource1);
696 if (giu_flags & GPIO_HAS_PULLUPDOWN_IO)
697 release_resource(giu_resource2);
698
699 return 0;
700}
701
702static struct platform_device *giu_platform_device;
703
Russell King3ae5eae2005-11-09 22:32:44 +0000704static struct platform_driver giu_device_driver = {
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700705 .probe = giu_probe,
Dmitry Torokhovd39b6cf2006-03-22 00:07:53 -0800706 .remove = __devexit_p(giu_remove),
Russell King3ae5eae2005-11-09 22:32:44 +0000707 .driver = {
708 .name = "GIU",
Dmitry Torokhovd39b6cf2006-03-22 00:07:53 -0800709 .owner = THIS_MODULE,
Russell King3ae5eae2005-11-09 22:32:44 +0000710 },
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700711};
712
Jean Delvaree701e852006-01-08 01:05:18 -0800713static int __init vr41xx_giu_init(void)
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700714{
715 int retval;
716
Dmitry Torokhovd39b6cf2006-03-22 00:07:53 -0800717 giu_platform_device = platform_device_alloc("GIU", -1);
718 if (!giu_platform_device)
719 return -ENOMEM;
720
721 retval = platform_device_add(giu_platform_device);
722 if (retval < 0) {
723 platform_device_put(giu_platform_device);
724 return retval;
725 }
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700726
Russell King3ae5eae2005-11-09 22:32:44 +0000727 retval = platform_driver_register(&giu_device_driver);
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700728 if (retval < 0)
729 platform_device_unregister(giu_platform_device);
730
731 return retval;
732}
733
Jean Delvaree701e852006-01-08 01:05:18 -0800734static void __exit vr41xx_giu_exit(void)
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700735{
Russell King3ae5eae2005-11-09 22:32:44 +0000736 platform_driver_unregister(&giu_device_driver);
Yoichi Yuasae400bae2005-06-21 17:15:56 -0700737
738 platform_device_unregister(giu_platform_device);
739}
740
741module_init(vr41xx_giu_init);
742module_exit(vr41xx_giu_exit);