get rid of $Id$ - it has never helped us and it has broken too many patches ;)
[openwrt/staging/florian.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);