get rid of $Id$ - it has never helped us and it has broken too many patches ;)
[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  */
13
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/fs.h>
17 #include <linux/miscdevice.h>
18 #include <asm/uaccess.h>
19
20 #include <typedefs.h>
21 #include <osl.h>
22 #include <sbutils.h>
23 #include <bcmdevs.h>
24
25 static sb_t *gpio_sbh;
26 static int gpio_major;
27 static devfs_handle_t gpio_dir;
28 static struct {
29         char *name;
30         devfs_handle_t handle;
31 } gpio_file[] = {
32         { "in", NULL },
33         { "out", NULL },
34         { "outen", NULL },
35         { "control", NULL }
36 };
37
38 static int
39 gpio_open(struct inode *inode, struct file * file)
40 {
41         if (MINOR(inode->i_rdev) > ARRAYSIZE(gpio_file))
42                 return -ENODEV;
43
44         MOD_INC_USE_COUNT;
45         return 0;
46 }
47
48 static int
49 gpio_release(struct inode *inode, struct file * file)
50 {
51         MOD_DEC_USE_COUNT;
52         return 0;
53 }
54
55 static ssize_t
56 gpio_read(struct file *file, char *buf, size_t count, loff_t *ppos)
57 {
58         u32 val;
59
60         switch (MINOR(file->f_dentry->d_inode->i_rdev)) {
61         case 0:
62                 val = sb_gpioin(gpio_sbh);
63                 break;
64         case 1:
65                 val = sb_gpioout(gpio_sbh, 0, 0, GPIO_DRV_PRIORITY);
66                 break;
67         case 2:
68                 val = sb_gpioouten(gpio_sbh, 0, 0, GPIO_DRV_PRIORITY);
69                 break;
70         case 3:
71                 val = sb_gpiocontrol(gpio_sbh, 0, 0, GPIO_DRV_PRIORITY);
72                 break;
73         default:
74                 return -ENODEV;
75         }
76
77         if (put_user(val, (u32 *) buf))
78                 return -EFAULT;
79
80         return sizeof(val);
81 }
82
83 static ssize_t
84 gpio_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
85 {
86         u32 val;
87
88         if (get_user(val, (u32 *) buf))
89                 return -EFAULT;
90
91         switch (MINOR(file->f_dentry->d_inode->i_rdev)) {
92         case 0:
93                 return -EACCES;
94         case 1:
95                 sb_gpioout(gpio_sbh, ~0, val, GPIO_DRV_PRIORITY);
96                 break;
97         case 2:
98                 sb_gpioouten(gpio_sbh, ~0, val, GPIO_DRV_PRIORITY);
99                 break;
100         case 3:
101                 sb_gpiocontrol(gpio_sbh, ~0, val, GPIO_DRV_PRIORITY);
102                 break;
103         default:
104                 return -ENODEV;
105         }
106
107         return sizeof(val);
108 }
109
110 static struct file_operations gpio_fops = {
111         owner:          THIS_MODULE,
112         open:           gpio_open,
113         release:        gpio_release,
114         read:           gpio_read,
115         write:          gpio_write,
116 };
117
118 static int __init
119 gpio_init(void)
120 {
121         int i;
122
123         if (!(gpio_sbh = sb_kattach(SB_OSH)))
124                 return -ENODEV;
125
126         sb_gpiosetcore(gpio_sbh);
127
128         if ((gpio_major = devfs_register_chrdev(0, "gpio", &gpio_fops)) < 0)
129                 return gpio_major;
130
131         gpio_dir = devfs_mk_dir(NULL, "gpio", NULL);
132
133         for (i = 0; i < ARRAYSIZE(gpio_file); i++) {
134                 gpio_file[i].handle = devfs_register(gpio_dir,
135                                                      gpio_file[i].name,
136                                                      DEVFS_FL_DEFAULT, gpio_major, i,
137                                                      S_IFCHR | S_IRUGO | S_IWUGO,
138                                                      &gpio_fops, NULL);
139         }
140
141         return 0;
142 }
143
144 static void __exit
145 gpio_exit(void)
146 {
147         int i;
148
149         for (i = 0; i < ARRAYSIZE(gpio_file); i++)
150                 devfs_unregister(gpio_file[i].handle);
151         devfs_unregister(gpio_dir);
152         devfs_unregister_chrdev(gpio_major, "gpio");
153         sb_detach(gpio_sbh);
154 }
155
156 module_init(gpio_init);
157 module_exit(gpio_exit);