2 * $Id: gpio.c,v 1.4 2003/05/19 22:24:18 lethal Exp $
3 * by Greg Banks <gbanks@pocketpenguins.com>
4 * (c) 2000 PocketPenguins Inc
6 * GPIO pin support for HD64465 companion chip.
9 #include <linux/kernel.h>
10 #include <linux/init.h>
11 #include <linux/module.h>
12 #include <linux/sched.h>
13 #include <linux/ioport.h>
15 #include <asm/hd64465/gpio.h>
17 #define _PORTOF(portpin) (((portpin)>>3)&0x7)
18 #define _PINOF(portpin) ((portpin)&0x7)
20 /* Register addresses parametrised on port */
21 #define GPIO_CR(port) (HD64465_REG_GPACR+((port)<<1))
22 #define GPIO_DR(port) (HD64465_REG_GPADR+((port)<<1))
23 #define GPIO_ICR(port) (HD64465_REG_GPAICR+((port)<<1))
24 #define GPIO_ISR(port) (HD64465_REG_GPAISR+((port)<<1))
28 #define MODNAME "hd64465_gpio"
30 EXPORT_SYMBOL(hd64465_gpio_configure
);
31 EXPORT_SYMBOL(hd64465_gpio_get_pin
);
32 EXPORT_SYMBOL(hd64465_gpio_get_port
);
33 EXPORT_SYMBOL(hd64465_gpio_register_irq
);
34 EXPORT_SYMBOL(hd64465_gpio_set_pin
);
35 EXPORT_SYMBOL(hd64465_gpio_set_port
);
36 EXPORT_SYMBOL(hd64465_gpio_unregister_irq
);
38 /* TODO: each port should be protected with a spinlock */
41 void hd64465_gpio_configure(int portpin
, int direction
)
44 unsigned int shift
= (_PINOF(portpin
)<<1);
46 cr
= inw(GPIO_CR(_PORTOF(portpin
)));
48 cr
|= direction
<<shift
;
49 outw(cr
, GPIO_CR(_PORTOF(portpin
)));
52 void hd64465_gpio_set_pin(int portpin
, unsigned int value
)
55 unsigned short mask
= 1<<(_PINOF(portpin
));
57 d
= inw(GPIO_DR(_PORTOF(portpin
)));
62 outw(d
, GPIO_DR(_PORTOF(portpin
)));
65 unsigned int hd64465_gpio_get_pin(int portpin
)
67 return inw(GPIO_DR(_PORTOF(portpin
))) & (1<<(_PINOF(portpin
)));
70 /* TODO: for cleaner atomicity semantics, add a mask to this routine */
72 void hd64465_gpio_set_port(int port
, unsigned int value
)
74 outw(value
, GPIO_DR(port
));
77 unsigned int hd64465_gpio_get_port(int port
)
79 return inw(GPIO_DR(port
));
84 void (*func
)(int portpin
, void *dev
);
86 } handlers
[GPIO_NPORTS
* 8];
88 static irqreturn_t
hd64465_gpio_interrupt(int irq
, void *dev
, struct pt_regs
*regs
)
90 unsigned short port
, pin
, isr
, mask
, portpin
;
92 for (port
=0 ; port
<GPIO_NPORTS
; port
++) {
93 isr
= inw(GPIO_ISR(port
));
95 for (pin
=0 ; pin
<8 ; pin
++) {
98 portpin
= (port
<<3)|pin
;
99 if (handlers
[portpin
].func
!= 0)
100 handlers
[portpin
].func(portpin
, handlers
[portpin
].dev
);
102 printk(KERN_NOTICE
"unexpected GPIO interrupt, pin %c%d\n",
107 /* Write 1s back to ISR to clear it? That's what the manual says.. */
108 outw(isr
, GPIO_ISR(port
));
114 void hd64465_gpio_register_irq(int portpin
, int mode
,
115 void (*handler
)(int portpin
, void *dev
), void *dev
)
118 unsigned short icr
, mask
;
123 local_irq_save(flags
);
125 handlers
[portpin
].func
= handler
;
126 handlers
[portpin
].dev
= dev
;
129 * Configure Interrupt Control Register
131 icr
= inw(GPIO_ICR(_PORTOF(portpin
)));
132 mask
= (1<<_PINOF(portpin
));
134 /* unmask interrupt */
140 if (mode
== HD64465_GPIO_RISING
)
143 outw(icr
, GPIO_ICR(_PORTOF(portpin
)));
145 local_irq_restore(flags
);
148 void hd64465_gpio_unregister_irq(int portpin
)
153 local_irq_save(flags
);
156 * Configure Interrupt Control Register
158 icr
= inw(GPIO_ICR(_PORTOF(portpin
)));
159 icr
|= (1<<_PINOF(portpin
)); /* mask interrupt */
160 outw(icr
, GPIO_ICR(_PORTOF(portpin
)));
162 handlers
[portpin
].func
= 0;
163 handlers
[portpin
].dev
= 0;
165 local_irq_restore(flags
);
168 static int __init
hd64465_gpio_init(void)
170 if (!request_region(HD64465_REG_GPACR
, 0x1000, MODNAME
))
172 if (request_irq(HD64465_IRQ_GPIO
, hd64465_gpio_interrupt
,
173 SA_INTERRUPT
, MODNAME
, 0))
176 printk("HD64465 GPIO layer on irq %d\n", HD64465_IRQ_GPIO
);
181 release_region(HD64465_REG_GPACR
, 0x1000);
186 static void __exit
hd64465_gpio_exit(void)
188 release_region(HD64465_REG_GPACR
, 0x1000);
189 free_irq(HD64465_IRQ_GPIO
, 0);
192 module_init(hd64465_gpio_init
);
193 module_exit(hd64465_gpio_exit
);
195 MODULE_LICENSE("GPL");