OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [cris/] [drivers/] [gpio.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* $Id: gpio.c,v 1.1.1.1 2004-04-15 01:22:20 phoenix Exp $
2
 *
3
 * Etrax general port I/O device
4
 *
5
 * Copyright (c) 1999, 2000, 2001, 2002 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
 *
11
 * $Log: not supported by cvs2svn $
12
 * Revision 1.25  2003/06/24 07:24:31  johana
13
 * Added gpio_pa_irq_enabled_mask to keep track of what interrupts we have
14
 * enabled so we anly clear those that we have enabled and let bits/pins
15
 * used by other drivers alone.
16
 * Update gpio_some_alarms in IO_CLRALARM ioctl().
17
 *
18
 * Revision 1.24  2003/06/19 08:58:25  johana
19
 * Turn off interrupts while fiddling with genconfig_shadow.
20
 * Put some printk within D() macro.
21
 *
22
 * Revision 1.23  2003/04/01 14:12:06  starvik
23
 * Added loglevel for lots of printks
24
 *
25
 * Revision 1.22  2003/01/09 18:03:47  starvik
26
 * init_ioremap is now called by kernel before device drivers are initialized
27
 *
28
 * Revision 1.21  2002/12/02 08:11:41  starvik
29
 * Merge of Linux 2.4.20
30
 *
31
 * Revision 1.20  2002/10/16 21:16:24  johana
32
 * Added support for PA high level interrupt.
33
 * That gives 2ms response time with iodtest for high levels and 2-12 ms
34
 * response time on low levels if the check is not made in
35
 * process.c:cpu_idle() as well.
36
 *
37
 * Revision 1.19  2002/10/14 18:27:33  johana
38
 * Implemented alarm handling so select() now works.
39
 * Latency is around 6-9 ms with a etrax_gpio_wake_up_check() in
40
 * cpu_idle().
41
 * Otherwise I get 15-18 ms (same as doing the poll in userspace -
42
 * but less overhead).
43
 * TODO? Perhaps we should add the check in IMMEDIATE_BH (or whatever it
44
 * is in 2.4) as well?
45
 * TODO? Perhaps call request_irq()/free_irq() only when needed?
46
 * Increased version to 2.5
47
 *
48
 * Revision 1.18  2002/10/11 15:02:00  johana
49
 * Mask inverted 8 bit value in setget_input().
50
 *
51
 * Revision 1.17  2002/06/17 15:53:01  johana
52
 * Added IO_READ_INBITS, IO_READ_OUTBITS, IO_SETGET_INPUT and IO_SETGET_OUTPUT
53
 * that take a pointer as argument and thus can handle 32 bit ports (G)
54
 * correctly.
55
 * These should be used instead of IO_READBITS, IO_SETINPUT and IO_SETOUTPUT.
56
 * (especially if Port G bit 31 is used)
57
 *
58
 * Revision 1.16  2002/06/17 09:59:51  johana
59
 * Returning 32 bit values in the ioctl return value doesn't work if bit
60
 * 31 is set (could happen for port G), so mask it of with 0x7FFFFFFF.
61
 * A new set of ioctl's will be added.
62
 *
63
 * Revision 1.15  2002/05/06 13:19:13  johana
64
 * IO_SETINPUT returns mask with bit set = inputs for PA and PB as well.
65
 *
66
 * Revision 1.14  2002/04/12 12:01:53  johana
67
 * Use global r_port_g_data_shadow.
68
 * Moved gpio_init_port_g() closer to gpio_init() and marked it __init.
69
 *
70
 * Revision 1.13  2002/04/10 12:03:55  johana
71
 * Added support for port G /dev/gpiog (minor 3).
72
 * Changed indentation on switch cases.
73
 * Fixed other spaces to tabs.
74
 *
75
 * Revision 1.12  2001/11/12 19:42:15  pkj
76
 * * Corrected return values from gpio_leds_ioctl().
77
 * * Fixed compiler warnings.
78
 *
79
 * Revision 1.11  2001/10/30 14:39:12  johana
80
 * Added D() around gpio_write printk.
81
 *
82
 * Revision 1.10  2001/10/25 10:24:42  johana
83
 * Added IO_CFG_WRITE_MODE ioctl and write method that can do fast
84
 * bittoggling in the kernel. (This speeds up programming an FPGA with 450kB
85
 * from ~60 seconds to 4 seconds).
86
 * Added save_flags/cli/restore_flags in ioctl.
87
 *
88
 * Revision 1.9  2001/05/04 14:16:07  matsfg
89
 * Corrected spelling error
90
 *
91
 * Revision 1.8  2001/04/27 13:55:26  matsfg
92
 * Moved initioremap.
93
 * Turns off all LEDS on init.
94
 * Added support for shutdown and powerbutton.
95
 *
96
 * Revision 1.7  2001/04/04 13:30:08  matsfg
97
 * Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping
98
 *
99
 * Revision 1.6  2001/03/26 16:03:06  bjornw
100
 * Needs linux/config.h
101
 *
102
 * Revision 1.5  2001/03/26 14:22:03  bjornw
103
 * Namechange of some config options
104
 *
105
 * Revision 1.4  2001/02/27 13:52:48  bjornw
106
 * malloc.h -> slab.h
107
 *
108
 * Revision 1.3  2001/01/24 15:06:48  bjornw
109
 * gpio_wq correct type
110
 *
111
 * Revision 1.2  2001/01/18 16:07:30  bjornw
112
 * 2.4 port
113
 *
114
 * Revision 1.1  2001/01/18 15:55:16  bjornw
115
 * Verbatim copy of etraxgpio.c from elinux 2.0 added
116
 *
117
 *
118
 */
119
 
120
#include <linux/config.h>
121
 
122
#include <linux/module.h>
123
#include <linux/sched.h>
124
#include <linux/slab.h>
125
#include <linux/ioport.h>
126
#include <linux/errno.h>
127
#include <linux/kernel.h>
128
#include <linux/fs.h>
129
#include <linux/string.h>
130
#include <linux/poll.h>
131
#include <linux/init.h>
132
 
133
#include <asm/etraxgpio.h>
134
#include <asm/svinto.h>
135
#include <asm/io.h>
136
#include <asm/system.h>
137
#include <asm/irq.h>
138
 
139
#define GPIO_MAJOR 120  /* experimental MAJOR number */
140
 
141
#define D(x)
142
 
143
#if 0
144
static int dp_cnt;
145
#define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0)
146
#else
147
#define DP(x)
148
#endif
149
 
150
static char gpio_name[] = "etrax gpio";
151
 
152
#if 0
153
static wait_queue_head_t *gpio_wq;
154
#endif
155
 
156
static int gpio_ioctl(struct inode *inode, struct file *file,
157
                      unsigned int cmd, unsigned long arg);
158
static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
159
                          loff_t *off);
160
static int gpio_open(struct inode *inode, struct file *filp);
161
static int gpio_release(struct inode *inode, struct file *filp);
162
static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait);
163
 
164
/* private data per open() of this driver */
165
 
166
struct gpio_private {
167
        struct gpio_private *next;
168
        /* These fields are for PA and PB only */
169
        volatile unsigned char *port, *shadow;
170
        volatile unsigned char *dir, *dir_shadow;
171
        unsigned char changeable_dir;
172
        unsigned char changeable_bits;
173
        unsigned char clk_mask;
174
        unsigned char data_mask;
175
        unsigned char write_msb;
176
        unsigned char pad1, pad2, pad3;
177
        /* These fields are generic */
178
        unsigned long highalarm, lowalarm;
179
        wait_queue_head_t alarm_wq;
180
        int minor;
181
};
182
 
183
/* linked list of alarms to check for */
184
 
185
static struct gpio_private *alarmlist = 0;
186
 
187
static int gpio_some_alarms = 0; /* Set if someone uses alarm */
188
static unsigned long gpio_pa_irq_enabled_mask = 0;
189
 
190
/* Port A and B use 8 bit access, but Port G is 32 bit */
191
#define NUM_PORTS (GPIO_MINOR_B+1)
192
 
193
static volatile unsigned char *ports[NUM_PORTS] = {
194
        R_PORT_PA_DATA,
195
        R_PORT_PB_DATA,
196
};
197
static volatile unsigned char *shads[NUM_PORTS] = {
198
        &port_pa_data_shadow,
199
        &port_pb_data_shadow
200
};
201
 
202
/* What direction bits that are user changeable 1=changeable*/
203
#ifndef CONFIG_ETRAX_PA_CHANGEABLE_DIR
204
#define CONFIG_ETRAX_PA_CHANGEABLE_DIR 0x00
205
#endif
206
#ifndef CONFIG_ETRAX_PB_CHANGEABLE_DIR
207
#define CONFIG_ETRAX_PB_CHANGEABLE_DIR 0x00
208
#endif
209
 
210
#ifndef CONFIG_ETRAX_PA_CHANGEABLE_BITS
211
#define CONFIG_ETRAX_PA_CHANGEABLE_BITS 0xFF
212
#endif
213
#ifndef CONFIG_ETRAX_PB_CHANGEABLE_BITS
214
#define CONFIG_ETRAX_PB_CHANGEABLE_BITS 0xFF
215
#endif
216
 
217
 
218
static unsigned char changeable_dir[NUM_PORTS] = {
219
        CONFIG_ETRAX_PA_CHANGEABLE_DIR,
220
        CONFIG_ETRAX_PB_CHANGEABLE_DIR
221
};
222
static unsigned char changeable_bits[NUM_PORTS] = {
223
        CONFIG_ETRAX_PA_CHANGEABLE_BITS,
224
        CONFIG_ETRAX_PB_CHANGEABLE_BITS
225
};
226
 
227
static volatile unsigned char *dir[NUM_PORTS] = {
228
        R_PORT_PA_DIR,
229
        R_PORT_PB_DIR
230
};
231
 
232
static volatile unsigned char *dir_shadow[NUM_PORTS] = {
233
        &port_pa_dir_shadow,
234
        &port_pb_dir_shadow
235
};
236
 
237
/* Port G is 32 bit, handle it special, some bits are both inputs
238
   and outputs at the same time, only some of the bits can change direction
239
   and some of them in groups of 8 bit. */
240
static unsigned long changeable_dir_g;
241
static unsigned long dir_g_in_bits;
242
static unsigned long dir_g_out_bits;
243
static unsigned long dir_g_shadow; /* 1=output */
244
 
245
#define USE_PORTS(priv) ((priv)->minor <= GPIO_MINOR_B)
246
 
247
 
248
 
249
static unsigned int
250
gpio_poll(struct file *file,
251
          poll_table *wait)
252
{
253
        unsigned int mask = 0;
254
        struct gpio_private *priv = (struct gpio_private *)file->private_data;
255
        unsigned long data;
256
        poll_wait(file, &priv->alarm_wq, wait);
257
        if (priv->minor == GPIO_MINOR_A) {
258
                unsigned long flags;
259
                unsigned long tmp;
260
                data = *R_PORT_PA_DATA;
261
                /* PA has support for high level interrupt -
262
                 * lets activate for those low and with highalarm set
263
                 */
264
                tmp = ~data & priv->highalarm & 0xFF;
265
                tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR);
266
                save_flags(flags); cli();
267
                gpio_pa_irq_enabled_mask |= tmp;
268
                *R_IRQ_MASK1_SET = tmp;
269
                restore_flags(flags);
270
 
271
        } else if (priv->minor == GPIO_MINOR_B)
272
                data = *R_PORT_PB_DATA;
273
        else if (priv->minor == GPIO_MINOR_G)
274
                data = *R_PORT_G_DATA;
275
        else
276
                return 0;
277
 
278
        if ((data & priv->highalarm) ||
279
            (~data & priv->lowalarm)) {
280
                mask = POLLIN|POLLRDNORM;
281
        }
282
 
283
        DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
284
        return mask;
285
}
286
 
287
void etrax_gpio_wake_up_check(void)
288
{
289
        struct gpio_private *priv = alarmlist;
290
        unsigned long data = 0;
291
        while (priv) {
292
                if (USE_PORTS(priv)) {
293
                        data = *priv->port;
294
                } else if (priv->minor == GPIO_MINOR_G) {
295
                        data = *R_PORT_G_DATA;
296
                }
297
                if ((data & priv->highalarm) ||
298
                    (~data & priv->lowalarm)) {
299
                        DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor));
300
                        wake_up_interruptible(&priv->alarm_wq);
301
                }
302
                priv = priv->next;
303
        }
304
}
305
 
306
static void
307
gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
308
{
309
        if (gpio_some_alarms) {
310
                etrax_gpio_wake_up_check();
311
        }
312
}
313
 
314
static void
315
gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
316
{
317
        unsigned long tmp;
318
        /* Find what PA interrupts are active */
319
        tmp = (*R_IRQ_READ1);
320
 
321
        /* Find those that we have enabled */
322
        tmp &= gpio_pa_irq_enabled_mask;
323
 
324
        /* Clear them.. */
325
        *R_IRQ_MASK1_CLR = tmp;
326
        gpio_pa_irq_enabled_mask &= ~tmp;
327
 
328
        if (gpio_some_alarms) {
329
                etrax_gpio_wake_up_check();
330
        }
331
}
332
 
333
 
334
static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
335
                          loff_t *off)
336
{
337
        struct gpio_private *priv = (struct gpio_private *)file->private_data;
338
        unsigned char data, clk_mask, data_mask, write_msb;
339
        unsigned long flags;
340
        ssize_t retval = count;
341
        if (priv->minor !=GPIO_MINOR_A && priv->minor != GPIO_MINOR_B) {
342
                return -EFAULT;
343
        }
344
 
345
        if (verify_area(VERIFY_READ, buf, count)) {
346
                return -EFAULT;
347
        }
348
        clk_mask = priv->clk_mask;
349
        data_mask = priv->data_mask;
350
        /* It must have been configured using the IO_CFG_WRITE_MODE */
351
        /* Perhaps a better error code? */
352
        if (clk_mask == 0 || data_mask == 0) {
353
                return -EPERM;
354
        }
355
        write_msb = priv->write_msb;
356
        D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %i\n",count, data_mask, clk_mask, write_msb));
357
        while (count--) {
358
                int i;
359
                data = *buf++;
360
                if (priv->write_msb) {
361
                        for (i = 7; i >= 0;i--) {
362
                                save_flags(flags); cli();
363
                                *priv->port = *priv->shadow &= ~clk_mask;
364
                                if (data & 1<<i)
365
                                        *priv->port = *priv->shadow |= data_mask;
366
                                else
367
                                        *priv->port = *priv->shadow &= ~data_mask;
368
                        /* For FPGA: min 5.0ns (DCC) before CCLK high */
369
                                *priv->port = *priv->shadow |= clk_mask;
370
                                restore_flags(flags);
371
                        }
372
                } else {
373
                        for (i = 0; i <= 7;i++) {
374
                                save_flags(flags); cli();
375
                                *priv->port = *priv->shadow &= ~clk_mask;
376
                                if (data & 1<<i)
377
                                        *priv->port = *priv->shadow |= data_mask;
378
                                else
379
                                        *priv->port = *priv->shadow &= ~data_mask;
380
                        /* For FPGA: min 5.0ns (DCC) before CCLK high */
381
                                *priv->port = *priv->shadow |= clk_mask;
382
                                restore_flags(flags);
383
                        }
384
                }
385
        }
386
        return retval;
387
}
388
 
389
 
390
 
391
static int
392
gpio_open(struct inode *inode, struct file *filp)
393
{
394
        struct gpio_private *priv;
395
        int p = MINOR(inode->i_rdev);
396
 
397
        if (p > GPIO_MINOR_LAST)
398
                return -EINVAL;
399
 
400
        priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private),
401
                                              GFP_KERNEL);
402
 
403
        if (!priv)
404
                return -ENOMEM;
405
 
406
        priv->minor = p;
407
 
408
        /* initialize the io/alarm struct and link it into our alarmlist */
409
 
410
        priv->next = alarmlist;
411
        alarmlist = priv;
412
        if (USE_PORTS(priv)) { /* A and B */
413
                priv->port = ports[p];
414
                priv->shadow = shads[p];
415
                priv->dir = dir[p];
416
                priv->dir_shadow = dir_shadow[p];
417
                priv->changeable_dir = changeable_dir[p];
418
                priv->changeable_bits = changeable_bits[p];
419
        } else {
420
                priv->port = NULL;
421
                priv->shadow = NULL;
422
                priv->dir = NULL;
423
                priv->dir_shadow = NULL;
424
                priv->changeable_dir = 0;
425
                priv->changeable_bits = 0;
426
        }
427
 
428
        priv->highalarm = 0;
429
        priv->lowalarm = 0;
430
        priv->clk_mask = 0;
431
        priv->data_mask = 0;
432
        init_waitqueue_head(&priv->alarm_wq);
433
 
434
        filp->private_data = (void *)priv;
435
 
436
        return 0;
437
}
438
 
439
static int
440
gpio_release(struct inode *inode, struct file *filp)
441
{
442
        struct gpio_private *p = alarmlist;
443
        struct gpio_private *todel = (struct gpio_private *)filp->private_data;
444
 
445
        /* unlink from alarmlist and free the private structure */
446
 
447
        if (p == todel) {
448
                alarmlist = todel->next;
449
        } else {
450
                while (p->next != todel)
451
                        p = p->next;
452
                p->next = todel->next;
453
        }
454
 
455
        kfree(todel);
456
        /* Check if there are still any alarms set */
457
        p = alarmlist;
458
        while (p) {
459
                if (p->highalarm | p->lowalarm) {
460
                        gpio_some_alarms = 1;
461
                        return 0;
462
                }
463
                p = p->next;
464
        }
465
        gpio_some_alarms = 0;
466
 
467
        return 0;
468
}
469
 
470
/* Main device API. ioctl's to read/set/clear bits, as well as to
471
 * set alarms to wait for using a subsequent select().
472
 */
473
 
474
unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
475
{
476
        /* Set direction 0=unchanged 1=input,
477
         * return mask with 1=input
478
         */
479
        unsigned long flags;
480
        if (USE_PORTS(priv)) {
481
                save_flags(flags); cli();
482
                *priv->dir = *priv->dir_shadow &=
483
                ~((unsigned char)arg & priv->changeable_dir);
484
                restore_flags(flags);
485
                return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */
486
        } else if (priv->minor == GPIO_MINOR_G) {
487
                /* We must fiddle with R_GEN_CONFIG to change dir */
488
                save_flags(flags); cli();
489
                if (((arg & dir_g_in_bits) != arg) &&
490
                    (arg & changeable_dir_g)) {
491
                        arg &= changeable_dir_g;
492
                        /* Clear bits in genconfig to set to input */
493
                        if (arg & (1<<0)) {
494
                                genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g0dir);
495
                                dir_g_in_bits |= (1<<0);
496
                                dir_g_out_bits &= ~(1<<0);
497
                        }
498
                        if ((arg & 0x0000FF00) == 0x0000FF00) {
499
                                genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g8_15dir);
500
                                dir_g_in_bits |= 0x0000FF00;
501
                                dir_g_out_bits &= ~0x0000FF00;
502
                        }
503
                        if ((arg & 0x00FF0000) == 0x00FF0000) {
504
                                genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g16_23dir);
505
                                dir_g_in_bits |= 0x00FF0000;
506
                                dir_g_out_bits &= ~0x00FF0000;
507
                        }
508
                        if (arg & (1<<24)) {
509
                                genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g24dir);
510
                                dir_g_in_bits |= (1<<24);
511
                                dir_g_out_bits &= ~(1<<24);
512
                        }
513
                        D(printk(KERN_INFO "gpio: SETINPUT on port G set "
514
                                 "genconfig to 0x%08lX "
515
                                 "in_bits: 0x%08lX "
516
                                 "out_bits: 0x%08lX\n",
517
                                 (unsigned long)genconfig_shadow,
518
                                 dir_g_in_bits, dir_g_out_bits));
519
                        *R_GEN_CONFIG = genconfig_shadow;
520
                        /* Must be a >120 ns delay before writing this again */
521
 
522
                }
523
                restore_flags(flags);
524
                return dir_g_in_bits;
525
        }
526
        return 0;
527
} /* setget_input */
528
 
529
unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)
530
{
531
        unsigned long flags;
532
        if (USE_PORTS(priv)) {
533
                save_flags(flags); cli();
534
                *priv->dir = *priv->dir_shadow |=
535
                  ((unsigned char)arg & priv->changeable_dir);
536
                restore_flags(flags);
537
                return *priv->dir_shadow;
538
        } else if (priv->minor == GPIO_MINOR_G) {
539
                /* We must fiddle with R_GEN_CONFIG to change dir */
540
                save_flags(flags); cli();
541
                if (((arg & dir_g_out_bits) != arg) &&
542
                    (arg & changeable_dir_g)) {
543
                        /* Set bits in genconfig to set to output */
544
                        if (arg & (1<<0)) {
545
                                genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g0dir);
546
                                dir_g_out_bits |= (1<<0);
547
                                dir_g_in_bits &= ~(1<<0);
548
                        }
549
                        if ((arg & 0x0000FF00) == 0x0000FF00) {
550
                                genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g8_15dir);
551
                                dir_g_out_bits |= 0x0000FF00;
552
                                dir_g_in_bits &= ~0x0000FF00;
553
                        }
554
                        if ((arg & 0x00FF0000) == 0x00FF0000) {
555
                                genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g16_23dir);
556
                                dir_g_out_bits |= 0x00FF0000;
557
                                dir_g_in_bits &= ~0x00FF0000;
558
                        }
559
                        if (arg & (1<<24)) {
560
                                genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g24dir);
561
                                dir_g_out_bits |= (1<<24);
562
                                dir_g_in_bits &= ~(1<<24);
563
                        }
564
                        D(printk(KERN_INFO "gpio: SETOUTPUT on port G set "
565
                                 "genconfig to 0x%08lX "
566
                                 "in_bits: 0x%08lX "
567
                                 "out_bits: 0x%08lX\n",
568
                                 (unsigned long)genconfig_shadow,
569
                                 dir_g_in_bits, dir_g_out_bits));
570
                        *R_GEN_CONFIG = genconfig_shadow;
571
                        /* Must be a >120 ns delay before writing this again */
572
                }
573
                restore_flags(flags);
574
                return dir_g_out_bits & 0x7FFFFFFF;
575
        }
576
        return 0;
577
} /* setget_output */
578
 
579
static int
580
gpio_leds_ioctl(unsigned int cmd, unsigned long arg);
581
 
582
static int
583
gpio_ioctl(struct inode *inode, struct file *file,
584
           unsigned int cmd, unsigned long arg)
585
{
586
        unsigned long flags;
587
        unsigned long val;
588
        struct gpio_private *priv = (struct gpio_private *)file->private_data;
589
        if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
590
                return -EINVAL;
591
        }
592
 
593
        switch (_IOC_NR(cmd)) {
594
        case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
595
                // read the port
596
                if (USE_PORTS(priv)) {
597
                        return *priv->port;
598
                } else if (priv->minor == GPIO_MINOR_G) {
599
                        return (*R_PORT_G_DATA) & 0x7FFFFFFF;
600
                }
601
                break;
602
        case IO_SETBITS:
603
                save_flags(flags); cli();
604
                // set changeable bits with a 1 in arg
605
                if (USE_PORTS(priv)) {
606
                        *priv->port = *priv->shadow |=
607
                          ((unsigned char)arg & priv->changeable_bits);
608
                } else if (priv->minor == GPIO_MINOR_G) {
609
                        *R_PORT_G_DATA = port_g_data_shadow |= (arg & dir_g_out_bits);
610
                }
611
                restore_flags(flags);
612
                break;
613
        case IO_CLRBITS:
614
                save_flags(flags); cli();
615
                // clear changeable bits with a 1 in arg
616
                if (USE_PORTS(priv)) {
617
                        *priv->port = *priv->shadow &=
618
                         ~((unsigned char)arg & priv->changeable_bits);
619
                } else if (priv->minor == GPIO_MINOR_G) {
620
                        *R_PORT_G_DATA = port_g_data_shadow &= ~((unsigned long)arg & dir_g_out_bits);
621
                }
622
                restore_flags(flags);
623
                break;
624
        case IO_HIGHALARM:
625
                // set alarm when bits with 1 in arg go high
626
                priv->highalarm |= arg;
627
                gpio_some_alarms = 1;
628
                break;
629
        case IO_LOWALARM:
630
                // set alarm when bits with 1 in arg go low
631
                priv->lowalarm |= arg;
632
                gpio_some_alarms = 1;
633
                break;
634
        case IO_CLRALARM:
635
                // clear alarm for bits with 1 in arg
636
                priv->highalarm &= ~arg;
637
                priv->lowalarm  &= ~arg;
638
                {
639
                        /* Must update gpio_some_alarms */
640
                        struct gpio_private *p = alarmlist;
641
                        int some_alarms;
642
                        some_alarms = 0;
643
                        while (p) {
644
                                if (p->highalarm | p->lowalarm) {
645
                                        some_alarms = 1;
646
                                        break;
647
                                }
648
                                p = p->next;
649
                        }
650
                        gpio_some_alarms = some_alarms;
651
                }
652
                break;
653
        case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
654
                /* Read direction 0=input 1=output */
655
                if (USE_PORTS(priv)) {
656
                        return *priv->dir_shadow;
657
                } else if (priv->minor == GPIO_MINOR_G) {
658
                        /* Note: Some bits are both in and out,
659
                         * Those that are dual is set here as well.
660
                         */
661
                        return (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF;
662
                }
663
        case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */
664
                /* Set direction 0=unchanged 1=input,
665
                 * return mask with 1=input
666
                 */
667
                return setget_input(priv, arg) & 0x7FFFFFFF;
668
                break;
669
        case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */
670
                /* Set direction 0=unchanged 1=output,
671
                 * return mask with 1=output
672
                 */
673
                return setget_output(priv, arg) & 0x7FFFFFFF;
674
 
675
        case IO_SHUTDOWN:
676
                SOFT_SHUTDOWN();
677
                break;
678
        case IO_GET_PWR_BT:
679
#if defined (CONFIG_ETRAX_SOFT_SHUTDOWN)
680
                return (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT));
681
#else
682
                return 0;
683
#endif
684
                break;
685
        case IO_CFG_WRITE_MODE:
686
                priv->clk_mask = arg & 0xFF;
687
                priv->data_mask = (arg >> 8) & 0xFF;
688
                priv->write_msb = (arg >> 16) & 0x01;
689
                /* Check if we're allowed to change the bits and
690
                 * the direction is correct
691
                 */
692
                if (!((priv->clk_mask & priv->changeable_bits) &&
693
                      (priv->data_mask & priv->changeable_bits) &&
694
                      (priv->clk_mask & *priv->dir_shadow) &&
695
                      (priv->data_mask & *priv->dir_shadow)))
696
                {
697
                        priv->clk_mask = 0;
698
                        priv->data_mask = 0;
699
                        return -EPERM;
700
                }
701
                break;
702
        case IO_READ_INBITS:
703
                /* *arg is result of reading the input pins */
704
                if (USE_PORTS(priv)) {
705
                        val = *priv->port;
706
                } else if (priv->minor == GPIO_MINOR_G) {
707
                        val = *R_PORT_G_DATA;
708
                }
709
                if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
710
                        return -EFAULT;
711
                return 0;
712
                break;
713
        case IO_READ_OUTBITS:
714
                 /* *arg is result of reading the output shadow */
715
                if (USE_PORTS(priv)) {
716
                        val = *priv->shadow;
717
                } else if (priv->minor == GPIO_MINOR_G) {
718
                        val = port_g_data_shadow;
719
                }
720
                if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
721
                        return -EFAULT;
722
                break;
723
        case IO_SETGET_INPUT:
724
                /* bits set in *arg is set to input,
725
                 * *arg updated with current input pins.
726
                 */
727
                if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
728
                        return -EFAULT;
729
                val = setget_input(priv, val);
730
                if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
731
                        return -EFAULT;
732
                break;
733
        case IO_SETGET_OUTPUT:
734
                /* bits set in *arg is set to output,
735
                 * *arg updated with current output pins.
736
                 */
737
                if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
738
                        return -EFAULT;
739
                val = setget_output(priv, val);
740
                if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
741
                        return -EFAULT;
742
                break;
743
        default:
744
                if (priv->minor == GPIO_MINOR_LEDS)
745
                        return gpio_leds_ioctl(cmd, arg);
746
                else
747
                        return -EINVAL;
748
        } /* switch */
749
 
750
        return 0;
751
}
752
 
753
static int
754
gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
755
{
756
        unsigned char green;
757
        unsigned char red;
758
 
759
        switch (_IOC_NR(cmd)) {
760
        case IO_LEDACTIVE_SET:
761
                green = ((unsigned char) arg) & 1;
762
                red   = (((unsigned char) arg) >> 1) & 1;
763
                LED_ACTIVE_SET_G(green);
764
                LED_ACTIVE_SET_R(red);
765
                break;
766
 
767
        case IO_LED_SETBIT:
768
                LED_BIT_SET(arg);
769
                break;
770
 
771
        case IO_LED_CLRBIT:
772
                LED_BIT_CLR(arg);
773
                break;
774
 
775
        default:
776
                return -EINVAL;
777
        } /* switch */
778
 
779
        return 0;
780
}
781
 
782
struct file_operations gpio_fops = {
783
        owner:       THIS_MODULE,
784
        poll:        gpio_poll,
785
        ioctl:       gpio_ioctl,
786
        write:       gpio_write,
787
        open:        gpio_open,
788
        release:     gpio_release,
789
};
790
 
791
 
792
static void __init gpio_init_port_g(void)
793
{
794
#define GROUPA (0x0000FF3F)
795
#define GROUPB (1<<6 | 1<<7)
796
#define GROUPC (1<<30 | 1<<31)
797
#define GROUPD (0x3FFF0000)
798
#define GROUPD_LOW (0x00FF0000)
799
        unsigned long used_in_bits = 0;
800
        unsigned long used_out_bits = 0;
801
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0, select)){
802
                used_in_bits  |= GROUPA | GROUPB | 0 | 0;
803
                used_out_bits |= GROUPA | GROUPB | 0 | 0;
804
        }
805
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ata, select)) {
806
                used_in_bits  |= GROUPA | GROUPB | GROUPC | (GROUPD & ~(1<<25|1<<26));
807
                used_out_bits |= GROUPA | GROUPB | GROUPC | GROUPD;
808
        }
809
 
810
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par0, select)) {
811
                used_in_bits  |= (GROUPA & ~(1<<0)) | 0 | 0 | 0;
812
                used_out_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0;
813
        }
814
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser2, select)) {
815
                used_in_bits  |= 0 | GROUPB | 0 | 0;
816
                used_out_bits |= 0 | GROUPB | 0 | 0;
817
        }
818
        /* mio same as shared RAM ? */
819
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio, select)) {
820
                used_in_bits  |= (GROUPA & ~(1<<0)) | 0 |0 |GROUPD_LOW;
821
                used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 |0 |GROUPD_LOW;
822
        }
823
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi1, select)) {
824
                used_in_bits  |= 0 | 0 | GROUPC | GROUPD;
825
                used_out_bits |= 0 | 0 | GROUPC | GROUPD;
826
        }
827
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0w, select)) {
828
                used_in_bits  |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24);
829
                used_out_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24 | 1<<25|1<<26);
830
        }
831
 
832
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par1, select)) {
833
                used_in_bits  |= 0 | 0 | 0 | (GROUPD & ~(1<<24));
834
                used_out_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24));
835
        }
836
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser3, select)) {
837
                used_in_bits  |= 0 | 0 | GROUPC | 0;
838
                used_out_bits |= 0 | 0 | GROUPC | 0;
839
        }
840
        /* mio same as shared RAM-W? */
841
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio_w, select)) {
842
                used_in_bits  |= (GROUPA & ~(1<<0)) | 0 | 0 |GROUPD_LOW;
843
                used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 | 0 |GROUPD_LOW;
844
        }
845
        /* TODO: USB p2, parw, sync ser3? */
846
 
847
        /* Initialise the dir_g_shadow etc. depending on genconfig */
848
        /* 0=input 1=output */
849
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g0dir, out))
850
                dir_g_shadow |= (1 << 0);
851
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g8_15dir, out))
852
                dir_g_shadow |= 0x0000FF00;
853
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g16_23dir, out))
854
                dir_g_shadow |= 0x00FF0000;
855
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g24dir, out))
856
                dir_g_shadow |= (1 << 24);
857
 
858
        dir_g_in_bits = ~used_in_bits;
859
        dir_g_out_bits = ~used_out_bits;
860
 
861
        changeable_dir_g = 0x01FFFF01; /* all that can change dir */
862
        changeable_dir_g &= dir_g_out_bits;
863
        changeable_dir_g &= dir_g_in_bits;
864
        /* Correct the bits that can change direction */
865
        dir_g_out_bits &= ~changeable_dir_g;
866
        dir_g_out_bits |= dir_g_shadow;
867
        dir_g_in_bits &= ~changeable_dir_g;
868
        dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g);
869
 
870
 
871
        printk(KERN_INFO
872
               "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n",
873
               dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA);
874
        printk(KERN_INFO
875
               "GPIO port G: dir: %08lX changeable: %08lX\n",
876
               dir_g_shadow, changeable_dir_g);
877
}
878
 
879
/* main driver initialization routine, called from mem.c */
880
 
881
static __init int
882
gpio_init(void)
883
{
884
        int res;
885
#if defined (CONFIG_ETRAX_CSP0_LEDS)
886
        int i;
887
#endif
888
 
889
        /* do the formalities */
890
 
891
        res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);
892
        if (res < 0) {
893
                printk(KERN_ERR "gpio: couldn't get a major number.\n");
894
                return res;
895
        }
896
 
897
        /* Clear all leds */
898
#if defined (CONFIG_ETRAX_CSP0_LEDS) ||  defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS)
899
        LED_NETWORK_SET(0);
900
        LED_ACTIVE_SET(0);
901
        LED_DISK_READ(0);
902
        LED_DISK_WRITE(0);
903
 
904
#if defined (CONFIG_ETRAX_CSP0_LEDS)
905
        for (i = 0; i < 32; i++) {
906
                LED_BIT_SET(i);
907
        }
908
#endif
909
 
910
#endif
911
        gpio_init_port_g();
912
        printk(KERN_INFO
913
               "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n");
914
        /* We call etrax_gpio_wake_up_check() from timer interrupt and
915
         * from cpu_idle() in kernel/process.c
916
         * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms
917
         * in some tests.
918
         */
919
        if (request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt,
920
                        SA_SHIRQ | SA_INTERRUPT,"gpio poll", NULL)) {
921
                printk(KERN_CRIT "err: timer0 irq for gpio\n");
922
        }
923
        if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt,
924
                        SA_SHIRQ | SA_INTERRUPT,"gpio PA", NULL)) {
925
                printk(KERN_CRIT "err: PA irq for gpio\n");
926
        }
927
 
928
        return res;
929
}
930
 
931
/* this makes sure that gpio_init is called during kernel boot */
932
 
933
module_init(gpio_init);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.