Contents of /alx-src/tags/kernel26-2.6.12-alx-r9/drivers/char/ite_gpio.c
Parent Directory
|
Revision Log
Revision 630 -
(show annotations)
(download)
Wed Mar 4 11:03:09 2009 UTC (15 years, 3 months ago) by niro
File MIME type: text/plain
File size: 10055 byte(s)
Wed Mar 4 11:03:09 2009 UTC (15 years, 3 months ago) by niro
File MIME type: text/plain
File size: 10055 byte(s)
Tag kernel26-2.6.12-alx-r9
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"); |