Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * FILE NAME ite_gpio.c | |
3 | * | |
4 | * BRIEF MODULE DESCRIPTION | |
5 | * API for ITE GPIO device. | |
6 | * Driver for ITE GPIO device. | |
7 | * | |
8 | * Author: MontaVista Software, Inc. <source@mvista.com> | |
9 | * Hai-Pao Fan <haipao@mvista.com> | |
10 | * | |
11 | * Copyright 2001 MontaVista Software Inc. | |
12 | * | |
13 | * This program is free software; you can redistribute it and/or modify it | |
14 | * under the terms of the GNU General Public License as published by the | |
15 | * Free Software Foundation; either version 2 of the License, or (at your | |
16 | * option) any later version. | |
17 | * | |
18 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
19 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
20 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | |
21 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
24 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
25 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 | * | |
29 | * You should have received a copy of the GNU General Public License along | |
30 | * with this program; if not, write to the Free Software Foundation, Inc., | |
31 | * 675 Mass Ave, Cambridge, MA 02139, USA. | |
32 | */ | |
33 | #include <linux/module.h> | |
34 | #include <linux/types.h> | |
35 | #include <linux/kernel.h> | |
36 | #include <linux/miscdevice.h> | |
37 | #include <linux/init.h> | |
38 | #include <linux/ioport.h> | |
39 | #include <asm/uaccess.h> | |
40 | #include <asm/addrspace.h> | |
41 | #include <asm/it8172/it8172_int.h> | |
42 | #include <linux/sched.h> | |
43 | #include <linux/ite_gpio.h> | |
44 | ||
45 | #define ite_gpio_base 0x14013800 | |
46 | ||
47 | #define ITE_GPADR (*(volatile __u8 *)(0x14013800 + KSEG1)) | |
48 | #define ITE_GPBDR (*(volatile __u8 *)(0x14013808 + KSEG1)) | |
49 | #define ITE_GPCDR (*(volatile __u8 *)(0x14013810 + KSEG1)) | |
50 | #define ITE_GPACR (*(volatile __u16 *)(0x14013802 + KSEG1)) | |
51 | #define ITE_GPBCR (*(volatile __u16 *)(0x1401380a + KSEG1)) | |
52 | #define ITE_GPCCR (*(volatile __u16 *)(0x14013812 + KSEG1)) | |
53 | #define ITE_GPAICR (*(volatile __u16 *)(0x14013804 + KSEG1)) | |
54 | #define ITE_GPBICR (*(volatile __u16 *)(0x1401380c + KSEG1)) | |
55 | #define ITE_GPCICR (*(volatile __u16 *)(0x14013814 + KSEG1)) | |
56 | #define ITE_GPAISR (*(volatile __u8 *)(0x14013806 + KSEG1)) | |
57 | #define ITE_GPBISR (*(volatile __u8 *)(0x1401380e + KSEG1)) | |
58 | #define ITE_GPCISR (*(volatile __u8 *)(0x14013816 + KSEG1)) | |
59 | #define ITE_GCR (*(volatile __u8 *)(0x14013818 + KSEG1)) | |
60 | ||
61 | #define MAX_GPIO_LINE 21 | |
62 | static int ite_gpio_irq=IT8172_GPIO_IRQ; | |
63 | ||
64 | static long ite_irq_counter[MAX_GPIO_LINE]; | |
65 | wait_queue_head_t ite_gpio_wait[MAX_GPIO_LINE]; | |
66 | static int ite_gpio_irq_pending[MAX_GPIO_LINE]; | |
67 | ||
68 | static int ite_gpio_debug=0; | |
69 | #define DEB(x) if (ite_gpio_debug>=1) x | |
70 | ||
71 | int ite_gpio_in(__u32 device, __u32 mask, volatile __u32 *data) | |
72 | { | |
73 | DEB(printk("ite_gpio_in mask=0x%x\n",mask)); | |
74 | ||
75 | switch (device) { | |
76 | case ITE_GPIO_PORTA: | |
77 | ITE_GPACR = (__u16)mask; /* 0xffff */ | |
78 | *data = ITE_GPADR; | |
79 | break; | |
80 | case ITE_GPIO_PORTB: | |
81 | ITE_GPBCR = (__u16)mask; /* 0xffff */ | |
82 | *data = ITE_GPBDR; | |
83 | break; | |
84 | case ITE_GPIO_PORTC: | |
85 | ITE_GPCCR = (__u16)mask; /* 0x03ff */ | |
86 | *data = ITE_GPCDR; | |
87 | break; | |
88 | default: | |
89 | return -EFAULT; | |
90 | } | |
91 | ||
92 | return 0; | |
93 | } | |
94 | ||
95 | ||
96 | int ite_gpio_out(__u32 device, __u32 mask, __u32 data) | |
97 | { | |
98 | switch (device) { | |
99 | case ITE_GPIO_PORTA: | |
100 | ITE_GPACR = (__u16)mask; /* 0x5555 */ | |
101 | ITE_GPADR = (__u8)data; | |
102 | break; | |
103 | case ITE_GPIO_PORTB: | |
104 | ITE_GPBCR = (__u16)mask; /* 0x5555 */ | |
105 | ITE_GPBDR = (__u8)data; | |
106 | break; | |
107 | case ITE_GPIO_PORTC: | |
108 | ITE_GPCCR = (__u16)mask; /* 0x0155 */ | |
109 | ITE_GPCDR = (__u8)data; | |
110 | break; | |
111 | default: | |
112 | return -EFAULT; | |
113 | } | |
114 | ||
115 | return 0; | |
116 | } | |
117 | ||
118 | int ite_gpio_int_ctrl(__u32 device, __u32 mask, __u32 data) | |
119 | { | |
120 | switch (device) { | |
121 | case ITE_GPIO_PORTA: | |
122 | ITE_GPAICR = (ITE_GPAICR & ~mask) | (data & mask); | |
123 | break; | |
124 | case ITE_GPIO_PORTB: | |
125 | ITE_GPBICR = (ITE_GPBICR & ~mask) | (data & mask); | |
126 | break; | |
127 | case ITE_GPIO_PORTC: | |
128 | ITE_GPCICR = (ITE_GPCICR & ~mask) | (data & mask); | |
129 | break; | |
130 | default: | |
131 | return -EFAULT; | |
132 | } | |
133 | ||
134 | return 0; | |
135 | } | |
136 | ||
137 | int ite_gpio_in_status(__u32 device, __u32 mask, volatile __u32 *data) | |
138 | { | |
139 | int ret=-1; | |
140 | ||
141 | if ((MAX_GPIO_LINE > *data) && (*data >= 0)) | |
142 | ret=ite_gpio_irq_pending[*data]; | |
143 | ||
144 | DEB(printk("ite_gpio_in_status %d ret=%d\n",*data, ret)); | |
145 | ||
146 | switch (device) { | |
147 | case ITE_GPIO_PORTA: | |
148 | *data = ITE_GPAISR & mask; | |
149 | break; | |
150 | case ITE_GPIO_PORTB: | |
151 | *data = ITE_GPBISR & mask; | |
152 | break; | |
153 | case ITE_GPIO_PORTC: | |
154 | *data = ITE_GPCISR & mask; | |
155 | break; | |
156 | default: | |
157 | return -EFAULT; | |
158 | } | |
159 | ||
160 | return ret; | |
161 | } | |
162 | ||
163 | int ite_gpio_out_status(__u32 device, __u32 mask, __u32 data) | |
164 | { | |
165 | switch (device) { | |
166 | case ITE_GPIO_PORTA: | |
167 | ITE_GPAISR = (ITE_GPAISR & ~mask) | (data & mask); | |
168 | break; | |
169 | case ITE_GPIO_PORTB: | |
170 | ITE_GPBISR = (ITE_GPBISR & ~mask) | (data & mask); | |
171 | break; | |
172 | case ITE_GPIO_PORTC: | |
173 | ITE_GPCISR = (ITE_GPCISR & ~mask) | (data & mask); | |
174 | break; | |
175 | default: | |
176 | return -EFAULT; | |
177 | } | |
178 | ||
179 | return 0; | |
180 | } | |
181 | ||
182 | int ite_gpio_gen_ctrl(__u32 device, __u32 mask, __u32 data) | |
183 | { | |
184 | ITE_GCR = (ITE_GCR & ~mask) | (data & mask); | |
185 | ||
186 | return 0; | |
187 | } | |
188 | ||
189 | int ite_gpio_int_wait (__u32 device, __u32 mask, __u32 data) | |
190 | { | |
191 | int i,line=0, ret=0; | |
192 | unsigned long flags; | |
193 | ||
194 | switch (device) { | |
195 | case ITE_GPIO_PORTA: | |
196 | line = data & mask; | |
197 | break; | |
198 | case ITE_GPIO_PORTB: | |
199 | line = (data & mask) <<8; | |
200 | break; | |
201 | case ITE_GPIO_PORTC: | |
202 | line = (data & mask) <<16; | |
203 | break; | |
204 | } | |
205 | for (i=MAX_GPIO_LINE-1; i >= 0; i--) { | |
206 | if ( (line) & (1 << i)) | |
207 | break; | |
208 | } | |
209 | ||
210 | DEB(printk("wait device=0x%d mask=0x%x data=0x%x index %d\n", | |
211 | device, mask, data, i)); | |
212 | ||
213 | if (line & ~(1<<i)) | |
214 | return -EFAULT; | |
215 | ||
216 | if (ite_gpio_irq_pending[i]==1) | |
217 | return -EFAULT; | |
218 | ||
219 | save_flags (flags); | |
220 | cli(); | |
221 | ite_gpio_irq_pending[i] = 1; | |
222 | ret = interruptible_sleep_on_timeout(&ite_gpio_wait[i], 3*HZ); | |
223 | restore_flags (flags); | |
224 | ite_gpio_irq_pending[i] = 0; | |
225 | ||
226 | return ret; | |
227 | } | |
228 | ||
229 | EXPORT_SYMBOL(ite_gpio_in); | |
230 | EXPORT_SYMBOL(ite_gpio_out); | |
231 | EXPORT_SYMBOL(ite_gpio_int_ctrl); | |
232 | EXPORT_SYMBOL(ite_gpio_in_status); | |
233 | EXPORT_SYMBOL(ite_gpio_out_status); | |
234 | EXPORT_SYMBOL(ite_gpio_gen_ctrl); | |
235 | EXPORT_SYMBOL(ite_gpio_int_wait); | |
236 | ||
237 | static int ite_gpio_open(struct inode *inode, struct file *file) | |
238 | { | |
239 | return 0; | |
240 | } | |
241 | ||
242 | ||
243 | static int ite_gpio_release(struct inode *inode, struct file *file) | |
244 | { | |
245 | return 0; | |
246 | } | |
247 | ||
248 | ||
249 | static int ite_gpio_ioctl(struct inode *inode, struct file *file, | |
250 | unsigned int cmd, unsigned long arg) | |
251 | { | |
252 | static struct ite_gpio_ioctl_data ioctl_data; | |
253 | ||
254 | if (copy_from_user(&ioctl_data, (struct ite_gpio_ioctl_data *)arg, | |
255 | sizeof(ioctl_data))) | |
256 | return -EFAULT; | |
257 | if ((ioctl_data.device < ITE_GPIO_PORTA) || | |
258 | (ioctl_data.device > ITE_GPIO_PORTC) ) | |
259 | return -EFAULT; | |
260 | ||
261 | switch(cmd) { | |
262 | case ITE_GPIO_IN: | |
263 | if (ite_gpio_in(ioctl_data.device, ioctl_data.mask, | |
264 | &ioctl_data.data)) | |
265 | return -EFAULT; | |
266 | ||
267 | if (copy_to_user((struct ite_gpio_ioctl_data *)arg, | |
268 | &ioctl_data, sizeof(ioctl_data))) | |
269 | return -EFAULT; | |
270 | break; | |
271 | ||
272 | case ITE_GPIO_OUT: | |
273 | return ite_gpio_out(ioctl_data.device, | |
274 | ioctl_data.mask, ioctl_data.data); | |
275 | break; | |
276 | ||
277 | case ITE_GPIO_INT_CTRL: | |
278 | return ite_gpio_int_ctrl(ioctl_data.device, | |
279 | ioctl_data.mask, ioctl_data.data); | |
280 | break; | |
281 | ||
282 | case ITE_GPIO_IN_STATUS: | |
283 | if (ite_gpio_in_status(ioctl_data.device, ioctl_data.mask, | |
284 | &ioctl_data.data)) | |
285 | return -EFAULT; | |
286 | if (copy_to_user((struct ite_gpio_ioctl_data *)arg, | |
287 | &ioctl_data, sizeof(ioctl_data))) | |
288 | return -EFAULT; | |
289 | break; | |
290 | ||
291 | case ITE_GPIO_OUT_STATUS: | |
292 | return ite_gpio_out_status(ioctl_data.device, | |
293 | ioctl_data.mask, ioctl_data.data); | |
294 | break; | |
295 | ||
296 | case ITE_GPIO_GEN_CTRL: | |
297 | return ite_gpio_gen_ctrl(ioctl_data.device, | |
298 | ioctl_data.mask, ioctl_data.data); | |
299 | break; | |
300 | ||
301 | case ITE_GPIO_INT_WAIT: | |
302 | return ite_gpio_int_wait(ioctl_data.device, | |
303 | ioctl_data.mask, ioctl_data.data); | |
304 | break; | |
305 | ||
306 | default: | |
307 | return -ENOIOCTLCMD; | |
308 | ||
309 | } | |
310 | ||
311 | return 0; | |
312 | } | |
313 | ||
314 | static void ite_gpio_irq_handler(int this_irq, void *dev_id, | |
315 | struct pt_regs *regs) | |
316 | { | |
317 | int i,line; | |
318 | ||
319 | line = ITE_GPCISR & 0x1f; | |
320 | for (i=4; i >=0; i--) { | |
321 | if ( line & (1 << i)) { | |
322 | ++ite_irq_counter[i+16]; | |
323 | ite_gpio_irq_pending[i+16] = 2; | |
324 | wake_up_interruptible(&ite_gpio_wait[i+16]); | |
325 | ||
326 | DEB(printk("interrupt 0x%x %d\n", &ite_gpio_wait[i+16], i+16)); | |
327 | ||
328 | ITE_GPCISR = ITE_GPCISR & (1<<i); | |
329 | return; | |
330 | } | |
331 | } | |
332 | line = ITE_GPBISR; | |
333 | for (i=7; i >= 0; i--) { | |
334 | if ( line & (1 << i)) { | |
335 | ++ite_irq_counter[i+8]; | |
336 | ite_gpio_irq_pending[i+8] = 2; | |
337 | wake_up_interruptible(&ite_gpio_wait[i+8]); | |
338 | ||
339 | DEB(printk("interrupt 0x%x %d\n",ITE_GPBISR, i+8)); | |
340 | ||
341 | ITE_GPBISR = ITE_GPBISR & (1<<i); | |
342 | return; | |
343 | } | |
344 | } | |
345 | line = ITE_GPAISR; | |
346 | for (i=7; i >= 0; i--) { | |
347 | if ( line & (1 << i)) { | |
348 | ++ite_irq_counter[i]; | |
349 | ite_gpio_irq_pending[i] = 2; | |
350 | wake_up_interruptible(&ite_gpio_wait[i]); | |
351 | ||
352 | DEB(printk("interrupt 0x%x %d\n",ITE_GPAISR, i)); | |
353 | ||
354 | ITE_GPAISR = ITE_GPAISR & (1<<i); | |
355 | return; | |
356 | } | |
357 | } | |
358 | } | |
359 | ||
360 | static struct file_operations ite_gpio_fops = { | |
361 | .owner = THIS_MODULE, | |
362 | .ioctl = ite_gpio_ioctl, | |
363 | .open = ite_gpio_open, | |
364 | .release = ite_gpio_release, | |
365 | }; | |
366 | ||
367 | static struct miscdevice ite_gpio_miscdev = { | |
368 | MISC_DYNAMIC_MINOR, | |
369 | "ite_gpio", | |
370 | &ite_gpio_fops | |
371 | }; | |
372 | ||
373 | int __init ite_gpio_init(void) | |
374 | { | |
375 | int i; | |
376 | ||
377 | if (misc_register(&ite_gpio_miscdev)) | |
378 | return -ENODEV; | |
379 | ||
380 | if (!request_region(ite_gpio_base, 0x1c, "ITE GPIO")) | |
381 | { | |
382 | misc_deregister(&ite_gpio_miscdev); | |
383 | return -EIO; | |
384 | } | |
385 | ||
386 | /* initialize registers */ | |
387 | ITE_GPACR = 0xffff; | |
388 | ITE_GPBCR = 0xffff; | |
389 | ITE_GPCCR = 0xffff; | |
390 | ITE_GPAICR = 0x00ff; | |
391 | ITE_GPBICR = 0x00ff; | |
392 | ITE_GPCICR = 0x00ff; | |
393 | ITE_GCR = 0; | |
394 | ||
395 | for (i = 0; i < MAX_GPIO_LINE; i++) { | |
396 | ite_gpio_irq_pending[i]=0; | |
397 | init_waitqueue_head(&ite_gpio_wait[i]); | |
398 | } | |
399 | ||
400 | if (request_irq(ite_gpio_irq, ite_gpio_irq_handler, SA_SHIRQ, "gpio", 0) < 0) { | |
401 | misc_deregister(&ite_gpio_miscdev); | |
402 | release_region(ite_gpio_base, 0x1c); | |
403 | return 0; | |
404 | } | |
405 | ||
406 | printk("GPIO at 0x%x (irq = %d)\n", ite_gpio_base, ite_gpio_irq); | |
407 | ||
408 | return 0; | |
409 | } | |
410 | ||
411 | static void __exit ite_gpio_exit(void) | |
412 | { | |
413 | misc_deregister(&ite_gpio_miscdev); | |
414 | } | |
415 | ||
416 | module_init(ite_gpio_init); | |
417 | module_exit(ite_gpio_exit); | |
418 | ||
419 | MODULE_LICENSE("GPL"); |