workaround for timer glitch on some boards
[openwrt.git] / target / linux / brcm-2.4 / files / arch / mips / bcm947xx / gpio.c
1 /*
2 * GPIO char driver
3 *
4 * Copyright 2005, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 *
12 * $Id$
13 */
14
15 #include <linux/module.h>
16 #include <linux/init.h>
17 #include <linux/fs.h>
18 #include <linux/miscdevice.h>
19 #include <asm/uaccess.h>
20
21 #include <typedefs.h>
22 #include <osl.h>
23 #include <bcmutils.h>
24 #include <sbutils.h>
25 #include <bcmdevs.h>
26
27 static sb_t *gpio_sbh;
28 static int gpio_major;
29 static devfs_handle_t gpio_dir;
30 static struct {
31 char *name;
32 devfs_handle_t handle;
33 } gpio_file[] = {
34 { "in", NULL },
35 { "out", NULL },
36 { "outen", NULL },
37 { "control", NULL }
38 };
39
40 static int
41 gpio_open(struct inode *inode, struct file * file)
42 {
43 if (MINOR(inode->i_rdev) > ARRAYSIZE(gpio_file))
44 return -ENODEV;
45
46 MOD_INC_USE_COUNT;
47 return 0;
48 }
49
50 static int
51 gpio_release(struct inode *inode, struct file * file)
52 {
53 MOD_DEC_USE_COUNT;
54 return 0;
55 }
56
57 static ssize_t
58 gpio_read(struct file *file, char *buf, size_t count, loff_t *ppos)
59 {
60 u32 val;
61
62 switch (MINOR(file->f_dentry->d_inode->i_rdev)) {
63 case 0:
64 val = sb_gpioin(gpio_sbh);
65 break;
66 case 1:
67 val = sb_gpioout(gpio_sbh, 0, 0, GPIO_DRV_PRIORITY);
68 break;
69 case 2:
70 val = sb_gpioouten(gpio_sbh, 0, 0, GPIO_DRV_PRIORITY);
71 break;
72 case 3:
73 val = sb_gpiocontrol(gpio_sbh, 0, 0, GPIO_DRV_PRIORITY);
74 break;
75 default:
76 return -ENODEV;
77 }
78
79 if (put_user(val, (u32 *) buf))
80 return -EFAULT;
81
82 return sizeof(val);
83 }
84
85 static ssize_t
86 gpio_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
87 {
88 u32 val;
89
90 if (get_user(val, (u32 *) buf))
91 return -EFAULT;
92
93 switch (MINOR(file->f_dentry->d_inode->i_rdev)) {
94 case 0:
95 return -EACCES;
96 case 1:
97 sb_gpioout(gpio_sbh, ~0, val, GPIO_DRV_PRIORITY);
98 break;
99 case 2:
100 sb_gpioouten(gpio_sbh, ~0, val, GPIO_DRV_PRIORITY);
101 break;
102 case 3:
103 sb_gpiocontrol(gpio_sbh, ~0, val, GPIO_DRV_PRIORITY);
104 break;
105 default:
106 return -ENODEV;
107 }
108
109 return sizeof(val);
110 }
111
112 static struct file_operations gpio_fops = {
113 owner: THIS_MODULE,
114 open: gpio_open,
115 release: gpio_release,
116 read: gpio_read,
117 write: gpio_write,
118 };
119
120 static int __init
121 gpio_init(void)
122 {
123 int i;
124
125 if (!(gpio_sbh = sb_kattach()))
126 return -ENODEV;
127
128 sb_gpiosetcore(gpio_sbh);
129
130 if ((gpio_major = devfs_register_chrdev(0, "gpio", &gpio_fops)) < 0)
131 return gpio_major;
132
133 gpio_dir = devfs_mk_dir(NULL, "gpio", NULL);
134
135 for (i = 0; i < ARRAYSIZE(gpio_file); i++) {
136 gpio_file[i].handle = devfs_register(gpio_dir,
137 gpio_file[i].name,
138 DEVFS_FL_DEFAULT, gpio_major, i,
139 S_IFCHR | S_IRUGO | S_IWUGO,
140 &gpio_fops, NULL);
141 }
142
143 return 0;
144 }
145
146 static void __exit
147 gpio_exit(void)
148 {
149 int i;
150
151 for (i = 0; i < ARRAYSIZE(gpio_file); i++)
152 devfs_unregister(gpio_file[i].handle);
153 devfs_unregister(gpio_dir);
154 devfs_unregister_chrdev(gpio_major, "gpio");
155 sb_detach(gpio_sbh);
156 }
157
158 module_init(gpio_init);
159 module_exit(gpio_exit);
This page took 0.058654 seconds and 5 git commands to generate.