File: /usr/src/linux/arch/cris/drivers/gpio.c
1 /* $Id: gpio.c,v 1.9 2001/05/04 14:16:07 matsfg Exp $
2 *
3 * Etrax general port I/O device
4 *
5 * Copyright (c) 1999, 2000, 2001 Axis Communications AB
6 *
7 * Authors: Bjorn Wesen (initial version)
8 * Ola Knutsson (LED handling)
9 * Johan Adolfsson (read/set directions)
10 *
11 * $Log: gpio.c,v $
12 * Revision 1.9 2001/05/04 14:16:07 matsfg
13 * Corrected spelling error
14 *
15 * Revision 1.8 2001/04/27 13:55:26 matsfg
16 * Moved initioremap.
17 * Turns off all LEDS on init.
18 * Added support for shutdown and powerbutton.
19 *
20 * Revision 1.7 2001/04/04 13:30:08 matsfg
21 * Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping
22 *
23 * Revision 1.6 2001/03/26 16:03:06 bjornw
24 * Needs linux/config.h
25 *
26 * Revision 1.5 2001/03/26 14:22:03 bjornw
27 * Namechange of some config options
28 *
29 * Revision 1.4 2001/02/27 13:52:48 bjornw
30 * malloc.h -> slab.h
31 *
32 * Revision 1.3 2001/01/24 15:06:48 bjornw
33 * gpio_wq correct type
34 *
35 * Revision 1.2 2001/01/18 16:07:30 bjornw
36 * 2.4 port
37 *
38 * Revision 1.1 2001/01/18 15:55:16 bjornw
39 * Verbatim copy of etraxgpio.c from elinux 2.0 added
40 *
41 *
42 */
43
44 #include <linux/config.h>
45
46 #include <linux/module.h>
47 #include <linux/sched.h>
48 #include <linux/slab.h>
49 #include <linux/ioport.h>
50 #include <linux/errno.h>
51 #include <linux/kernel.h>
52 #include <linux/fs.h>
53 #include <linux/string.h>
54 #include <linux/poll.h>
55 #include <linux/init.h>
56
57 #include <asm/etraxgpio.h>
58 #include <asm/svinto.h>
59 #include <asm/io.h>
60 #include <asm/system.h>
61
62 #define GPIO_MAJOR 120 /* experimental MAJOR number */
63
64 #define D(x)
65
66 static char gpio_name[] = "etrax gpio";
67
68 static wait_queue_head_t *gpio_wq;
69
70 static int gpio_ioctl(struct inode *inode, struct file *file,
71 unsigned int cmd, unsigned long arg);
72 static int gpio_open(struct inode *inode, struct file *filp);
73 static int gpio_release(struct inode *inode, struct file *filp);
74 static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait);
75
76 /* private data per open() of this driver */
77
78 struct gpio_private {
79 struct gpio_private *next;
80 volatile unsigned char *port, *shadow;
81 volatile unsigned char *dir, *dir_shadow;
82 unsigned char changeable_dir;
83 unsigned char changeable_bits;
84 unsigned char highalarm, lowalarm;
85 wait_queue_head_t alarm_wq;
86 int minor;
87 };
88
89 /* linked list of alarms to check for */
90
91 static struct gpio_private *alarmlist = 0;
92
93 #define NUM_PORTS 2
94 static volatile unsigned char *ports[2] = { R_PORT_PA_DATA, R_PORT_PB_DATA };
95 static volatile unsigned char *shads[2] = {
96 &port_pa_data_shadow, &port_pb_data_shadow };
97
98 /* What direction bits that are user changeable 1=changeable*/
99 #ifndef CONFIG_ETRAX_PA_CHANGEABLE_DIR
100 #define CONFIG_ETRAX_PA_CHANGEABLE_DIR 0x00
101 #endif
102 #ifndef CONFIG_ETRAX_PB_CHANGEABLE_DIR
103 #define CONFIG_ETRAX_PB_CHANGEABLE_DIR 0x00
104 #endif
105
106 #ifndef CONFIG_ETRAX_PA_CHANGEABLE_BITS
107 #define CONFIG_ETRAX_PA_CHANGEABLE_BITS 0xFF
108 #endif
109 #ifndef CONFIG_ETRAX_PB_CHANGEABLE_BITS
110 #define CONFIG_ETRAX_PB_CHANGEABLE_BITS 0xFF
111 #endif
112
113
114 static unsigned char changeable_dir[2] = { CONFIG_ETRAX_PA_CHANGEABLE_DIR,
115 CONFIG_ETRAX_PB_CHANGEABLE_DIR };
116 static unsigned char changeable_bits[2] = { CONFIG_ETRAX_PA_CHANGEABLE_BITS,
117 CONFIG_ETRAX_PB_CHANGEABLE_BITS };
118
119 static volatile unsigned char *dir[2] = { R_PORT_PA_DIR, R_PORT_PB_DIR };
120
121 static volatile unsigned char *dir_shadow[2] = {
122 &port_pa_dir_shadow, &port_pb_dir_shadow };
123
124 #define LEDS 2
125
126 static unsigned int
127 gpio_poll(struct file *filp,
128 struct poll_table_struct *wait)
129 {
130 /* TODO poll on alarms! */
131 #if 0
132 if(!ANYTHING_WANTED) {
133 D(printk("gpio_select sleeping task\n"));
134 select_wait(&gpio_wq, table);
135 return 0;
136 }
137 D(printk("gpio_select ready\n"));
138 #endif
139 return 1;
140 }
141
142 static int
143 gpio_open(struct inode *inode, struct file *filp)
144 {
145 struct gpio_private *priv;
146 int p = MINOR(inode->i_rdev);
147
148 if(p >= NUM_PORTS && p != LEDS)
149 return -EINVAL;
150
151 priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private),
152 GFP_KERNEL);
153
154 if(!priv)
155 return -ENOMEM;
156
157 priv->minor = p;
158
159 /* initialize the io/alarm struct and link it into our alarmlist */
160
161 priv->next = alarmlist;
162 alarmlist = priv;
163 priv->port = ports[p];
164 priv->shadow = shads[p];
165
166 priv->changeable_dir = changeable_dir[p];
167 priv->changeable_bits = changeable_bits[p];
168 priv->dir = dir[p];
169 priv->dir_shadow = dir_shadow[p];
170
171 priv->highalarm = 0;
172 priv->lowalarm = 0;
173 init_waitqueue_head(&priv->alarm_wq);
174
175 filp->private_data = (void *)priv;
176
177 return 0;
178 }
179
180 static int
181 gpio_release(struct inode *inode, struct file *filp)
182 {
183 struct gpio_private *p = alarmlist;
184 struct gpio_private *todel = (struct gpio_private *)filp->private_data;
185
186 /* unlink from alarmlist and free the private structure */
187
188 if(p == todel) {
189 alarmlist = todel->next;
190 } else {
191 while(p->next != todel)
192 p = p->next;
193 p->next = todel->next;
194 }
195
196 kfree(todel);
197
198 return 0;
199 }
200
201 /* Main device API. ioctl's to read/set/clear bits, as well as to
202 * set alarms to wait for using a subsequent select().
203 */
204
205 static int
206 gpio_leds_ioctl(unsigned int cmd, unsigned long arg);
207
208 static int
209 gpio_ioctl(struct inode *inode, struct file *file,
210 unsigned int cmd, unsigned long arg)
211 {
212 struct gpio_private *priv = (struct gpio_private *)file->private_data;
213
214 if(_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
215 return -EINVAL;
216 }
217
218 switch (_IOC_NR(cmd)) {
219 case IO_READBITS:
220 // read the port
221 return *priv->port;
222 case IO_SETBITS:
223 // set changeable bits with a 1 in arg
224 *priv->port = *priv->shadow |=
225 ((unsigned char)arg & priv->changeable_bits);
226 break;
227 case IO_CLRBITS:
228 // clear changeable bits with a 1 in arg
229 *priv->port = *priv->shadow &=
230 ~((unsigned char)arg & priv->changeable_bits);
231 break;
232 case IO_HIGHALARM:
233 // set alarm when bits with 1 in arg go high
234 priv->highalarm |= (unsigned char)arg;
235 break;
236 case IO_LOWALARM:
237 // set alarm when bits with 1 in arg go low
238 priv->lowalarm |= (unsigned char)arg;
239 break;
240 case IO_CLRALARM:
241 // clear alarm for bits with 1 in arg
242 priv->highalarm &= ~(unsigned char)arg;
243 priv->lowalarm &= ~(unsigned char)arg;
244 break;
245 case IO_READDIR:
246 /* Read direction 0=input 1=output */
247 return *priv->dir_shadow;
248 case IO_SETINPUT:
249 /* Set direction 0=unchanged 1=input */
250 *priv->dir = *priv->dir_shadow &=
251 ~((unsigned char)arg & priv->changeable_dir);
252 return *priv->dir_shadow;
253 case IO_SETOUTPUT:
254 /* Set direction 0=unchanged 1=output */
255 *priv->dir = *priv->dir_shadow |=
256 ((unsigned char)arg & priv->changeable_dir);
257 return *priv->dir_shadow;
258 case IO_SHUTDOWN:
259 SOFT_SHUTDOWN();
260 break;
261 case IO_GET_PWR_BT:
262 #if defined (CONFIG_ETRAX_SOFT_SHUTDOWN)
263 return (*R_PORT_G_DATA &
264 ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT));
265 #else
266 return 0;
267 #endif
268 default:
269 if(priv->minor == LEDS)
270 return gpio_leds_ioctl(cmd, arg);
271 else
272 return -EINVAL;
273 }
274
275 return 0;
276 }
277
278 static int
279 gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
280 {
281 unsigned char green;
282 unsigned char red;
283 switch (_IOC_NR(cmd)) {
284 case IO_LEDACTIVE_SET:
285 green = ((unsigned char) arg) & 1;
286 red = (((unsigned char) arg) >> 1) & 1;
287 LED_ACTIVE_SET_G(green);
288 LED_ACTIVE_SET_R(red);
289 break;
290 case IO_LED_SETBIT:
291 LED_BIT_SET(arg);
292 break;
293 case IO_LED_CLRBIT:
294 LED_BIT_CLR(arg);
295 default:
296 return -EINVAL;
297 }
298 }
299
300 struct file_operations gpio_fops = {
301 owner: THIS_MODULE,
302 poll: gpio_poll,
303 ioctl: gpio_ioctl,
304 open: gpio_open,
305 release: gpio_release,
306 };
307
308 /* main driver initialization routine, called from mem.c */
309
310 static __init int
311 gpio_init(void)
312 {
313 int res,i;
314
315 /* do the formalities */
316
317 res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);
318 if(res < 0) {
319 printk(KERN_ERR "gpio: couldn't get a major number.\n");
320 return res;
321 }
322
323 /* Clear all leds */
324 #if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS)
325
326 init_ioremap();
327 LED_NETWORK_SET(0);
328 LED_ACTIVE_SET(0);
329 LED_DISK_READ(0);
330 LED_DISK_WRITE(0);
331
332 #if defined (CONFIG_ETRAX_CSP0_LEDS)
333 for( i = 0; i < 32; i ++)
334 {
335 LED_BIT_SET(i);
336 }
337 #endif
338
339 #endif
340
341 printk("ETRAX 100LX GPIO driver v2.1, (c) 2001 Axis Communications AB\n");
342
343 return res;
344 }
345
346 /* this makes sure that gpio_init is called during kernel boot */
347
348 module_init(gpio_init);
349