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