• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/src/linux/linux-2.6/arch/cris/arch-v32/drivers/
1/* $Id: gpio.c,v 1.1.1.1 2007-08-03 18:51:41 $
2 *
3 * ETRAX CRISv32 general port I/O device
4 *
5 * Copyright (c) 1999, 2000, 2001, 2002, 2003 Axis Communications AB
6 *
7 * Authors:    Bjorn Wesen      (initial version)
8 *             Ola Knutsson     (LED handling)
9 *             Johan Adolfsson  (read/set directions, write, port G,
10 *                               port to ETRAX FS.
11 *
12 * $Log: not supported by cvs2svn $
13 * Revision 1.16  2005/06/19 17:06:49  starvik
14 * Merge of Linux 2.6.12.
15 *
16 * Revision 1.15  2005/05/25 08:22:20  starvik
17 * Changed GPIO port order to fit packages/devices/axis-2.4.
18 *
19 * Revision 1.14  2005/04/24 18:35:08  starvik
20 * Updated with final register headers.
21 *
22 * Revision 1.13  2005/03/15 15:43:00  starvik
23 * dev_id needs to be supplied for shared IRQs.
24 *
25 * Revision 1.12  2005/03/10 17:12:00  starvik
26 * Protect alarm list with spinlock.
27 *
28 * Revision 1.11  2005/01/05 06:08:59  starvik
29 * No need to do local_irq_disable after local_irq_save.
30 *
31 * Revision 1.10  2004/11/19 08:38:31  starvik
32 * Removed old crap.
33 *
34 * Revision 1.9  2004/05/14 07:58:02  starvik
35 * Merge of changes from 2.4
36 *
37 * Revision 1.8  2003/09/11 07:29:50  starvik
38 * Merge of Linux 2.6.0-test5
39 *
40 * Revision 1.7  2003/07/10 13:25:46  starvik
41 * Compiles for 2.5.74
42 * Lindented ethernet.c
43 *
44 * Revision 1.6  2003/07/04 08:27:46  starvik
45 * Merge of Linux 2.5.74
46 *
47 * Revision 1.5  2003/06/10 08:26:37  johana
48 * Etrax -> ETRAX CRISv32
49 *
50 * Revision 1.4  2003/06/05 14:22:48  johana
51 * Initialise some_alarms.
52 *
53 * Revision 1.3  2003/06/05 10:15:46  johana
54 * New INTR_VECT macros.
55 * Enable interrupts in global config.
56 *
57 * Revision 1.2  2003/06/03 15:52:50  johana
58 * Initial CRIS v32 version.
59 *
60 * Revision 1.1  2003/06/03 08:53:15  johana
61 * Copy of os/lx25/arch/cris/arch-v10/drivers/gpio.c version 1.7.
62 *
63 */
64
65
66#include <linux/module.h>
67#include <linux/sched.h>
68#include <linux/slab.h>
69#include <linux/ioport.h>
70#include <linux/errno.h>
71#include <linux/kernel.h>
72#include <linux/fs.h>
73#include <linux/string.h>
74#include <linux/poll.h>
75#include <linux/init.h>
76#include <linux/interrupt.h>
77#include <linux/spinlock.h>
78
79#include <asm/etraxgpio.h>
80#include <asm/arch/hwregs/reg_map.h>
81#include <asm/arch/hwregs/reg_rdwr.h>
82#include <asm/arch/hwregs/gio_defs.h>
83#include <asm/arch/hwregs/intr_vect_defs.h>
84#include <asm/io.h>
85#include <asm/system.h>
86#include <asm/irq.h>
87
88/* The following gio ports on ETRAX FS is available:
89 * pa  8 bits, supports interrupts off, hi, low, set, posedge, negedge anyedge
90 * pb 18 bits
91 * pc 18 bits
92 * pd 18 bits
93 * pe 18 bits
94 * each port has a rw_px_dout, r_px_din and rw_px_oe register.
95 */
96
97#define GPIO_MAJOR 120  /* experimental MAJOR number */
98
99#define D(x)
100
101#define DP(x)
102
103static char gpio_name[] = "etrax gpio";
104
105
106static int gpio_ioctl(struct inode *inode, struct file *file,
107		      unsigned int cmd, unsigned long arg);
108static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
109                          loff_t *off);
110static int gpio_open(struct inode *inode, struct file *filp);
111static int gpio_release(struct inode *inode, struct file *filp);
112static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait);
113
114/* private data per open() of this driver */
115
116struct gpio_private {
117	struct gpio_private *next;
118	/* The IO_CFG_WRITE_MODE_VALUE only support 8 bits: */
119	unsigned char clk_mask;
120	unsigned char data_mask;
121	unsigned char write_msb;
122	unsigned char pad1;
123	/* These fields are generic */
124	unsigned long highalarm, lowalarm;
125	wait_queue_head_t alarm_wq;
126	int minor;
127};
128
129/* linked list of alarms to check for */
130
131static struct gpio_private *alarmlist = 0;
132
133static int gpio_some_alarms = 0; /* Set if someone uses alarm */
134static unsigned long gpio_pa_high_alarms = 0;
135static unsigned long gpio_pa_low_alarms = 0;
136
137static DEFINE_SPINLOCK(alarm_lock);
138
139#define NUM_PORTS (GPIO_MINOR_LAST+1)
140#define GIO_REG_RD_ADDR(reg) (volatile unsigned long*) (regi_gio + REG_RD_ADDR_gio_##reg )
141#define GIO_REG_WR_ADDR(reg) (volatile unsigned long*) (regi_gio + REG_RD_ADDR_gio_##reg )
142unsigned long led_dummy;
143
144static volatile unsigned long *data_out[NUM_PORTS] = {
145	GIO_REG_WR_ADDR(rw_pa_dout),
146	GIO_REG_WR_ADDR(rw_pb_dout),
147	&led_dummy,
148	GIO_REG_WR_ADDR(rw_pc_dout),
149	GIO_REG_WR_ADDR(rw_pd_dout),
150	GIO_REG_WR_ADDR(rw_pe_dout),
151};
152
153static volatile unsigned long *data_in[NUM_PORTS] = {
154	GIO_REG_RD_ADDR(r_pa_din),
155	GIO_REG_RD_ADDR(r_pb_din),
156	&led_dummy,
157	GIO_REG_RD_ADDR(r_pc_din),
158	GIO_REG_RD_ADDR(r_pd_din),
159	GIO_REG_RD_ADDR(r_pe_din),
160};
161
162static unsigned long changeable_dir[NUM_PORTS] = {
163	CONFIG_ETRAX_PA_CHANGEABLE_DIR,
164	CONFIG_ETRAX_PB_CHANGEABLE_DIR,
165	0,
166	CONFIG_ETRAX_PC_CHANGEABLE_DIR,
167	CONFIG_ETRAX_PD_CHANGEABLE_DIR,
168	CONFIG_ETRAX_PE_CHANGEABLE_DIR,
169};
170
171static unsigned long changeable_bits[NUM_PORTS] = {
172	CONFIG_ETRAX_PA_CHANGEABLE_BITS,
173	CONFIG_ETRAX_PB_CHANGEABLE_BITS,
174	0,
175	CONFIG_ETRAX_PC_CHANGEABLE_BITS,
176	CONFIG_ETRAX_PD_CHANGEABLE_BITS,
177	CONFIG_ETRAX_PE_CHANGEABLE_BITS,
178};
179
180static volatile unsigned long *dir_oe[NUM_PORTS] = {
181	GIO_REG_WR_ADDR(rw_pa_oe),
182	GIO_REG_WR_ADDR(rw_pb_oe),
183	&led_dummy,
184	GIO_REG_WR_ADDR(rw_pc_oe),
185	GIO_REG_WR_ADDR(rw_pd_oe),
186	GIO_REG_WR_ADDR(rw_pe_oe),
187};
188
189
190
191static unsigned int
192gpio_poll(struct file *file,
193	  poll_table *wait)
194{
195	unsigned int mask = 0;
196	struct gpio_private *priv = (struct gpio_private *)file->private_data;
197	unsigned long data;
198	poll_wait(file, &priv->alarm_wq, wait);
199	if (priv->minor == GPIO_MINOR_A) {
200		reg_gio_rw_intr_cfg intr_cfg;
201		unsigned long tmp;
202		unsigned long flags;
203
204		local_irq_save(flags);
205		data = REG_TYPE_CONV(unsigned long, reg_gio_r_pa_din, REG_RD(gio, regi_gio, r_pa_din));
206		/* PA has support for interrupt
207		 * lets activate high for those low and with highalarm set
208		 */
209		intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg);
210
211		tmp = ~data & priv->highalarm & 0xFF;
212                if (tmp & (1 << 0)) {
213			intr_cfg.pa0 = regk_gio_hi;
214		}
215                if (tmp & (1 << 1)) {
216			intr_cfg.pa1 = regk_gio_hi;
217		}
218                if (tmp & (1 << 2)) {
219			intr_cfg.pa2 = regk_gio_hi;
220		}
221                if (tmp & (1 << 3)) {
222			intr_cfg.pa3 = regk_gio_hi;
223		}
224                if (tmp & (1 << 4)) {
225			intr_cfg.pa4 = regk_gio_hi;
226		}
227                if (tmp & (1 << 5)) {
228			intr_cfg.pa5 = regk_gio_hi;
229		}
230                if (tmp & (1 << 6)) {
231			intr_cfg.pa6 = regk_gio_hi;
232		}
233                if (tmp & (1 << 7)) {
234			intr_cfg.pa7 = regk_gio_hi;
235		}
236		/*
237		 * lets activate low for those high and with lowalarm set
238		 */
239		tmp = data & priv->lowalarm & 0xFF;
240                if (tmp & (1 << 0)) {
241			intr_cfg.pa0 = regk_gio_lo;
242		}
243                if (tmp & (1 << 1)) {
244			intr_cfg.pa1 = regk_gio_lo;
245		}
246                if (tmp & (1 << 2)) {
247			intr_cfg.pa2 = regk_gio_lo;
248		}
249                if (tmp & (1 << 3)) {
250			intr_cfg.pa3 = regk_gio_lo;
251		}
252                if (tmp & (1 << 4)) {
253			intr_cfg.pa4 = regk_gio_lo;
254		}
255                if (tmp & (1 << 5)) {
256			intr_cfg.pa5 = regk_gio_lo;
257		}
258                if (tmp & (1 << 6)) {
259			intr_cfg.pa6 = regk_gio_lo;
260		}
261                if (tmp & (1 << 7)) {
262			intr_cfg.pa7 = regk_gio_lo;
263		}
264
265		REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg);
266		local_irq_restore(flags);
267	} else if (priv->minor <= GPIO_MINOR_E)
268		data = *data_in[priv->minor];
269	else
270		return 0;
271
272	if ((data & priv->highalarm) ||
273	    (~data & priv->lowalarm)) {
274		mask = POLLIN|POLLRDNORM;
275	}
276
277	DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
278	return mask;
279}
280
281int etrax_gpio_wake_up_check(void)
282{
283	struct gpio_private *priv = alarmlist;
284	unsigned long data = 0;
285        int ret = 0;
286	while (priv) {
287		data = *data_in[priv->minor];
288		if ((data & priv->highalarm) ||
289		    (~data & priv->lowalarm)) {
290			DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor));
291			wake_up_interruptible(&priv->alarm_wq);
292                        ret = 1;
293		}
294		priv = priv->next;
295	}
296        return ret;
297}
298
299static irqreturn_t
300gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
301{
302	if (gpio_some_alarms) {
303		return IRQ_RETVAL(etrax_gpio_wake_up_check());
304	}
305        return IRQ_NONE;
306}
307
308static irqreturn_t
309gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
310{
311	reg_gio_rw_intr_mask intr_mask;
312	reg_gio_r_masked_intr masked_intr;
313	reg_gio_rw_ack_intr ack_intr;
314	unsigned long tmp;
315	unsigned long tmp2;
316
317	/* Find what PA interrupts are active */
318	masked_intr = REG_RD(gio, regi_gio, r_masked_intr);
319	tmp = REG_TYPE_CONV(unsigned long, reg_gio_r_masked_intr, masked_intr);
320
321	/* Find those that we have enabled */
322	spin_lock(&alarm_lock);
323	tmp &= (gpio_pa_high_alarms | gpio_pa_low_alarms);
324	spin_unlock(&alarm_lock);
325
326	/* Ack them */
327	ack_intr = REG_TYPE_CONV(reg_gio_rw_ack_intr, unsigned long, tmp);
328	REG_WR(gio, regi_gio, rw_ack_intr, ack_intr);
329
330	/* Disable those interrupts.. */
331	intr_mask = REG_RD(gio, regi_gio, rw_intr_mask);
332	tmp2 = REG_TYPE_CONV(unsigned long, reg_gio_rw_intr_mask, intr_mask);
333	tmp2 &= ~tmp;
334	intr_mask = REG_TYPE_CONV(reg_gio_rw_intr_mask, unsigned long, tmp2);
335	REG_WR(gio, regi_gio, rw_intr_mask, intr_mask);
336
337	if (gpio_some_alarms) {
338		return IRQ_RETVAL(etrax_gpio_wake_up_check());
339	}
340        return IRQ_NONE;
341}
342
343
344static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
345                          loff_t *off)
346{
347	struct gpio_private *priv = (struct gpio_private *)file->private_data;
348	unsigned char data, clk_mask, data_mask, write_msb;
349	unsigned long flags;
350	unsigned long shadow;
351	volatile unsigned long *port;
352	ssize_t retval = count;
353	/* Only bits 0-7 may be used for write operations but allow all
354	   devices except leds... */
355	if (priv->minor == GPIO_MINOR_LEDS) {
356		return -EFAULT;
357	}
358
359	if (!access_ok(VERIFY_READ, buf, count)) {
360		return -EFAULT;
361	}
362	clk_mask = priv->clk_mask;
363	data_mask = priv->data_mask;
364	/* It must have been configured using the IO_CFG_WRITE_MODE */
365	/* Perhaps a better error code? */
366	if (clk_mask == 0 || data_mask == 0) {
367		return -EPERM;
368	}
369	write_msb = priv->write_msb;
370	D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %i\n",count, data_mask, clk_mask, write_msb));
371	port = data_out[priv->minor];
372
373	while (count--) {
374		int i;
375		data = *buf++;
376		if (priv->write_msb) {
377			for (i = 7; i >= 0;i--) {
378				local_irq_save(flags);
379				shadow = *port;
380				*port = shadow &= ~clk_mask;
381				if (data & 1<<i)
382					*port = shadow |= data_mask;
383				else
384					*port = shadow &= ~data_mask;
385			/* For FPGA: min 5.0ns (DCC) before CCLK high */
386				*port = shadow |= clk_mask;
387				local_irq_restore(flags);
388			}
389		} else {
390			for (i = 0; i <= 7;i++) {
391				local_irq_save(flags);
392				shadow = *port;
393				*port = shadow &= ~clk_mask;
394				if (data & 1<<i)
395					*port = shadow |= data_mask;
396				else
397					*port = shadow &= ~data_mask;
398			/* For FPGA: min 5.0ns (DCC) before CCLK high */
399				*port = shadow |= clk_mask;
400				local_irq_restore(flags);
401			}
402		}
403	}
404	return retval;
405}
406
407
408
409static int
410gpio_open(struct inode *inode, struct file *filp)
411{
412	struct gpio_private *priv;
413	int p = iminor(inode);
414
415	if (p > GPIO_MINOR_LAST)
416		return -EINVAL;
417
418	priv = kmalloc(sizeof(struct gpio_private),
419					      GFP_KERNEL);
420
421	if (!priv)
422		return -ENOMEM;
423
424	priv->minor = p;
425
426	/* initialize the io/alarm struct and link it into our alarmlist */
427
428	priv->next = alarmlist;
429	alarmlist = priv;
430	priv->clk_mask = 0;
431	priv->data_mask = 0;
432	priv->highalarm = 0;
433	priv->lowalarm = 0;
434	init_waitqueue_head(&priv->alarm_wq);
435
436	filp->private_data = (void *)priv;
437
438	return 0;
439}
440
441static int
442gpio_release(struct inode *inode, struct file *filp)
443{
444	struct gpio_private *p = alarmlist;
445	struct gpio_private *todel = (struct gpio_private *)filp->private_data;
446	/* local copies while updating them: */
447	unsigned long a_high, a_low;
448	unsigned long some_alarms;
449
450	/* unlink from alarmlist and free the private structure */
451
452	if (p == todel) {
453		alarmlist = todel->next;
454	} else {
455		while (p->next != todel)
456			p = p->next;
457		p->next = todel->next;
458	}
459
460	kfree(todel);
461	/* Check if there are still any alarms set */
462	p = alarmlist;
463        some_alarms = 0;
464	a_high = 0;
465	a_low = 0;
466	while (p) {
467		if (p->minor == GPIO_MINOR_A) {
468			a_high |= p->highalarm;
469			a_low |= p->lowalarm;
470		}
471
472		if (p->highalarm | p->lowalarm) {
473			some_alarms = 1;
474		}
475		p = p->next;
476	}
477
478	spin_lock(&alarm_lock);
479	gpio_some_alarms = some_alarms;
480	gpio_pa_high_alarms = a_high;
481	gpio_pa_low_alarms = a_low;
482	spin_unlock(&alarm_lock);
483
484	return 0;
485}
486
487/* Main device API. ioctl's to read/set/clear bits, as well as to
488 * set alarms to wait for using a subsequent select().
489 */
490
491unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
492{
493	/* Set direction 0=unchanged 1=input,
494	 * return mask with 1=input
495	 */
496	unsigned long flags;
497	unsigned long dir_shadow;
498
499	local_irq_save(flags);
500	dir_shadow = *dir_oe[priv->minor];
501	dir_shadow &= ~(arg & changeable_dir[priv->minor]);
502	*dir_oe[priv->minor] = dir_shadow;
503	local_irq_restore(flags);
504
505	if (priv->minor == GPIO_MINOR_A)
506		dir_shadow ^= 0xFF;    /* Only 8 bits */
507	else
508		dir_shadow ^= 0x3FFFF; /* Only 18 bits */
509	return dir_shadow;
510
511} /* setget_input */
512
513unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)
514{
515	unsigned long flags;
516	unsigned long dir_shadow;
517
518	local_irq_save(flags);
519	dir_shadow = *dir_oe[priv->minor];
520	dir_shadow |=  (arg & changeable_dir[priv->minor]);
521	*dir_oe[priv->minor] = dir_shadow;
522	local_irq_restore(flags);
523	return dir_shadow;
524} /* setget_output */
525
526static int
527gpio_leds_ioctl(unsigned int cmd, unsigned long arg);
528
529static int
530gpio_ioctl(struct inode *inode, struct file *file,
531	   unsigned int cmd, unsigned long arg)
532{
533	unsigned long flags;
534	unsigned long val;
535	unsigned long shadow;
536	struct gpio_private *priv = (struct gpio_private *)file->private_data;
537	if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
538		return -EINVAL;
539	}
540
541	switch (_IOC_NR(cmd)) {
542	case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
543		// read the port
544		return *data_in[priv->minor];
545		break;
546	case IO_SETBITS:
547		local_irq_save(flags);
548                if (arg & 0x04)
549                  printk("GPIO SET 2\n");
550		// set changeable bits with a 1 in arg
551		shadow = *data_out[priv->minor];
552		shadow |=  (arg & changeable_bits[priv->minor]);
553		*data_out[priv->minor] = shadow;
554		local_irq_restore(flags);
555		break;
556	case IO_CLRBITS:
557		local_irq_save(flags);
558                if (arg & 0x04)
559                  printk("GPIO CLR 2\n");
560		// clear changeable bits with a 1 in arg
561		shadow = *data_out[priv->minor];
562		shadow &=  ~(arg & changeable_bits[priv->minor]);
563		*data_out[priv->minor] = shadow;
564		local_irq_restore(flags);
565		break;
566	case IO_HIGHALARM:
567		// set alarm when bits with 1 in arg go high
568		priv->highalarm |= arg;
569		spin_lock(&alarm_lock);
570		gpio_some_alarms = 1;
571		if (priv->minor == GPIO_MINOR_A) {
572			gpio_pa_high_alarms |= arg;
573		}
574		spin_unlock(&alarm_lock);
575		break;
576	case IO_LOWALARM:
577		// set alarm when bits with 1 in arg go low
578		priv->lowalarm |= arg;
579		spin_lock(&alarm_lock);
580		gpio_some_alarms = 1;
581		if (priv->minor == GPIO_MINOR_A) {
582			gpio_pa_low_alarms |= arg;
583		}
584		spin_unlock(&alarm_lock);
585		break;
586	case IO_CLRALARM:
587		// clear alarm for bits with 1 in arg
588		priv->highalarm &= ~arg;
589		priv->lowalarm  &= ~arg;
590		spin_lock(&alarm_lock);
591		if (priv->minor == GPIO_MINOR_A) {
592			if (gpio_pa_high_alarms & arg ||
593			    gpio_pa_low_alarms & arg) {
594				/* Must update the gpio_pa_*alarms masks */
595			}
596		}
597		spin_unlock(&alarm_lock);
598		break;
599	case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
600		/* Read direction 0=input 1=output */
601		return *dir_oe[priv->minor];
602	case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */
603		/* Set direction 0=unchanged 1=input,
604		 * return mask with 1=input
605		 */
606		return setget_input(priv, arg);
607		break;
608	case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */
609		/* Set direction 0=unchanged 1=output,
610		 * return mask with 1=output
611		 */
612		return setget_output(priv, arg);
613
614	case IO_CFG_WRITE_MODE:
615	{
616		unsigned long dir_shadow;
617		dir_shadow = *dir_oe[priv->minor];
618
619		priv->clk_mask = arg & 0xFF;
620		priv->data_mask = (arg >> 8) & 0xFF;
621		priv->write_msb = (arg >> 16) & 0x01;
622		/* Check if we're allowed to change the bits and
623		 * the direction is correct
624		 */
625		if (!((priv->clk_mask & changeable_bits[priv->minor]) &&
626		      (priv->data_mask & changeable_bits[priv->minor]) &&
627		      (priv->clk_mask & dir_shadow) &&
628		      (priv->data_mask & dir_shadow)))
629		{
630			priv->clk_mask = 0;
631			priv->data_mask = 0;
632			return -EPERM;
633		}
634		break;
635	}
636	case IO_READ_INBITS:
637		/* *arg is result of reading the input pins */
638		val = *data_in[priv->minor];
639		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
640			return -EFAULT;
641		return 0;
642		break;
643	case IO_READ_OUTBITS:
644		 /* *arg is result of reading the output shadow */
645		val = *data_out[priv->minor];
646		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
647			return -EFAULT;
648		break;
649	case IO_SETGET_INPUT:
650		/* bits set in *arg is set to input,
651		 * *arg updated with current input pins.
652		 */
653		if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
654			return -EFAULT;
655		val = setget_input(priv, val);
656		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
657			return -EFAULT;
658		break;
659	case IO_SETGET_OUTPUT:
660		/* bits set in *arg is set to output,
661		 * *arg updated with current output pins.
662		 */
663		if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
664			return -EFAULT;
665		val = setget_output(priv, val);
666		if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
667			return -EFAULT;
668		break;
669	default:
670		if (priv->minor == GPIO_MINOR_LEDS)
671			return gpio_leds_ioctl(cmd, arg);
672		else
673			return -EINVAL;
674	} /* switch */
675
676	return 0;
677}
678
679static int
680gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
681{
682	unsigned char green;
683	unsigned char red;
684
685	switch (_IOC_NR(cmd)) {
686	case IO_LEDACTIVE_SET:
687		green = ((unsigned char) arg) & 1;
688		red   = (((unsigned char) arg) >> 1) & 1;
689		LED_ACTIVE_SET_G(green);
690		LED_ACTIVE_SET_R(red);
691		break;
692
693	default:
694		return -EINVAL;
695	} /* switch */
696
697	return 0;
698}
699
700const struct file_operations gpio_fops = {
701	.owner       = THIS_MODULE,
702	.poll        = gpio_poll,
703	.ioctl       = gpio_ioctl,
704	.write       = gpio_write,
705	.open        = gpio_open,
706	.release     = gpio_release,
707};
708
709
710/* main driver initialization routine, called from mem.c */
711
712static __init int
713gpio_init(void)
714{
715	int res;
716	reg_intr_vect_rw_mask intr_mask;
717
718	/* do the formalities */
719
720	res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);
721	if (res < 0) {
722		printk(KERN_ERR "gpio: couldn't get a major number.\n");
723		return res;
724	}
725
726	/* Clear all leds */
727	LED_NETWORK_SET(0);
728	LED_ACTIVE_SET(0);
729	LED_DISK_READ(0);
730	LED_DISK_WRITE(0);
731
732	printk("ETRAX FS GPIO driver v2.5, (c) 2003-2005 Axis Communications AB\n");
733	/* We call etrax_gpio_wake_up_check() from timer interrupt and
734	 * from cpu_idle() in kernel/process.c
735	 * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms
736	 * in some tests.
737	 */
738	if (request_irq(TIMER_INTR_VECT, gpio_poll_timer_interrupt,
739			IRQF_SHARED | IRQF_DISABLED,"gpio poll", &alarmlist)) {
740		printk("err: timer0 irq for gpio\n");
741	}
742	if (request_irq(GEN_IO_INTR_VECT, gpio_pa_interrupt,
743			IRQF_SHARED | IRQF_DISABLED,"gpio PA", &alarmlist)) {
744		printk("err: PA irq for gpio\n");
745	}
746	/* enable the gio and timer irq in global config */
747	intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
748	intr_mask.timer = 1;
749	intr_mask.gen_io = 1;
750	REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
751
752	return res;
753}
754
755/* this makes sure that gpio_init is called during kernel boot */
756
757module_init(gpio_init);
758