diff options
Diffstat (limited to 'arch/cris/arch-v10/drivers/gpio.c')
-rw-r--r-- | arch/cris/arch-v10/drivers/gpio.c | 201 |
1 files changed, 106 insertions, 95 deletions
diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c index c095de82a0da..09963fe299a7 100644 --- a/arch/cris/arch-v10/drivers/gpio.c +++ b/arch/cris/arch-v10/drivers/gpio.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $Id: gpio.c,v 1.12 2004/08/24 07:19:59 starvik Exp $ | 1 | /* $Id: gpio.c,v 1.17 2005/06/19 17:06:46 starvik Exp $ |
2 | * | 2 | * |
3 | * Etrax general port I/O device | 3 | * Etrax general port I/O device |
4 | * | 4 | * |
@@ -9,6 +9,18 @@ | |||
9 | * Johan Adolfsson (read/set directions, write, port G) | 9 | * Johan Adolfsson (read/set directions, write, port G) |
10 | * | 10 | * |
11 | * $Log: gpio.c,v $ | 11 | * $Log: gpio.c,v $ |
12 | * Revision 1.17 2005/06/19 17:06:46 starvik | ||
13 | * Merge of Linux 2.6.12. | ||
14 | * | ||
15 | * Revision 1.16 2005/03/07 13:02:29 starvik | ||
16 | * Protect driver global states with spinlock | ||
17 | * | ||
18 | * Revision 1.15 2005/01/05 06:08:55 starvik | ||
19 | * No need to do local_irq_disable after local_irq_save. | ||
20 | * | ||
21 | * Revision 1.14 2004/12/13 12:21:52 starvik | ||
22 | * Added I/O and DMA allocators from Linux 2.4 | ||
23 | * | ||
12 | * Revision 1.12 2004/08/24 07:19:59 starvik | 24 | * Revision 1.12 2004/08/24 07:19:59 starvik |
13 | * Whitespace cleanup | 25 | * Whitespace cleanup |
14 | * | 26 | * |
@@ -142,6 +154,7 @@ | |||
142 | #include <asm/io.h> | 154 | #include <asm/io.h> |
143 | #include <asm/system.h> | 155 | #include <asm/system.h> |
144 | #include <asm/irq.h> | 156 | #include <asm/irq.h> |
157 | #include <asm/arch/io_interface_mux.h> | ||
145 | 158 | ||
146 | #define GPIO_MAJOR 120 /* experimental MAJOR number */ | 159 | #define GPIO_MAJOR 120 /* experimental MAJOR number */ |
147 | 160 | ||
@@ -194,6 +207,8 @@ static struct gpio_private *alarmlist = 0; | |||
194 | static int gpio_some_alarms = 0; /* Set if someone uses alarm */ | 207 | static int gpio_some_alarms = 0; /* Set if someone uses alarm */ |
195 | static unsigned long gpio_pa_irq_enabled_mask = 0; | 208 | static unsigned long gpio_pa_irq_enabled_mask = 0; |
196 | 209 | ||
210 | static DEFINE_SPINLOCK(gpio_lock); /* Protect directions etc */ | ||
211 | |||
197 | /* Port A and B use 8 bit access, but Port G is 32 bit */ | 212 | /* Port A and B use 8 bit access, but Port G is 32 bit */ |
198 | #define NUM_PORTS (GPIO_MINOR_B+1) | 213 | #define NUM_PORTS (GPIO_MINOR_B+1) |
199 | 214 | ||
@@ -241,6 +256,9 @@ static volatile unsigned char *dir_shadow[NUM_PORTS] = { | |||
241 | &port_pb_dir_shadow | 256 | &port_pb_dir_shadow |
242 | }; | 257 | }; |
243 | 258 | ||
259 | /* All bits in port g that can change dir. */ | ||
260 | static const unsigned long int changeable_dir_g_mask = 0x01FFFF01; | ||
261 | |||
244 | /* Port G is 32 bit, handle it special, some bits are both inputs | 262 | /* Port G is 32 bit, handle it special, some bits are both inputs |
245 | and outputs at the same time, only some of the bits can change direction | 263 | and outputs at the same time, only some of the bits can change direction |
246 | and some of them in groups of 8 bit. */ | 264 | and some of them in groups of 8 bit. */ |
@@ -260,6 +278,7 @@ gpio_poll(struct file *file, | |||
260 | unsigned int mask = 0; | 278 | unsigned int mask = 0; |
261 | struct gpio_private *priv = (struct gpio_private *)file->private_data; | 279 | struct gpio_private *priv = (struct gpio_private *)file->private_data; |
262 | unsigned long data; | 280 | unsigned long data; |
281 | spin_lock(&gpio_lock); | ||
263 | poll_wait(file, &priv->alarm_wq, wait); | 282 | poll_wait(file, &priv->alarm_wq, wait); |
264 | if (priv->minor == GPIO_MINOR_A) { | 283 | if (priv->minor == GPIO_MINOR_A) { |
265 | unsigned long flags; | 284 | unsigned long flags; |
@@ -270,10 +289,10 @@ gpio_poll(struct file *file, | |||
270 | */ | 289 | */ |
271 | tmp = ~data & priv->highalarm & 0xFF; | 290 | tmp = ~data & priv->highalarm & 0xFF; |
272 | tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR); | 291 | tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR); |
273 | save_flags(flags); cli(); | 292 | local_irq_save(flags); |
274 | gpio_pa_irq_enabled_mask |= tmp; | 293 | gpio_pa_irq_enabled_mask |= tmp; |
275 | *R_IRQ_MASK1_SET = tmp; | 294 | *R_IRQ_MASK1_SET = tmp; |
276 | restore_flags(flags); | 295 | local_irq_restore(flags); |
277 | 296 | ||
278 | } else if (priv->minor == GPIO_MINOR_B) | 297 | } else if (priv->minor == GPIO_MINOR_B) |
279 | data = *R_PORT_PB_DATA; | 298 | data = *R_PORT_PB_DATA; |
@@ -286,8 +305,11 @@ gpio_poll(struct file *file, | |||
286 | (~data & priv->lowalarm)) { | 305 | (~data & priv->lowalarm)) { |
287 | mask = POLLIN|POLLRDNORM; | 306 | mask = POLLIN|POLLRDNORM; |
288 | } | 307 | } |
308 | |||
309 | spin_unlock(&gpio_lock); | ||
289 | 310 | ||
290 | DP(printk("gpio_poll ready: mask 0x%08X\n", mask)); | 311 | DP(printk("gpio_poll ready: mask 0x%08X\n", mask)); |
312 | |||
291 | return mask; | 313 | return mask; |
292 | } | 314 | } |
293 | 315 | ||
@@ -296,6 +318,7 @@ int etrax_gpio_wake_up_check(void) | |||
296 | struct gpio_private *priv = alarmlist; | 318 | struct gpio_private *priv = alarmlist; |
297 | unsigned long data = 0; | 319 | unsigned long data = 0; |
298 | int ret = 0; | 320 | int ret = 0; |
321 | spin_lock(&gpio_lock); | ||
299 | while (priv) { | 322 | while (priv) { |
300 | if (USE_PORTS(priv)) { | 323 | if (USE_PORTS(priv)) { |
301 | data = *priv->port; | 324 | data = *priv->port; |
@@ -310,6 +333,7 @@ int etrax_gpio_wake_up_check(void) | |||
310 | } | 333 | } |
311 | priv = priv->next; | 334 | priv = priv->next; |
312 | } | 335 | } |
336 | spin_unlock(&gpio_lock); | ||
313 | return ret; | 337 | return ret; |
314 | } | 338 | } |
315 | 339 | ||
@@ -327,6 +351,7 @@ static irqreturn_t | |||
327 | gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 351 | gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
328 | { | 352 | { |
329 | unsigned long tmp; | 353 | unsigned long tmp; |
354 | spin_lock(&gpio_lock); | ||
330 | /* Find what PA interrupts are active */ | 355 | /* Find what PA interrupts are active */ |
331 | tmp = (*R_IRQ_READ1); | 356 | tmp = (*R_IRQ_READ1); |
332 | 357 | ||
@@ -337,6 +362,8 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
337 | *R_IRQ_MASK1_CLR = tmp; | 362 | *R_IRQ_MASK1_CLR = tmp; |
338 | gpio_pa_irq_enabled_mask &= ~tmp; | 363 | gpio_pa_irq_enabled_mask &= ~tmp; |
339 | 364 | ||
365 | spin_unlock(&gpio_lock); | ||
366 | |||
340 | if (gpio_some_alarms) { | 367 | if (gpio_some_alarms) { |
341 | return IRQ_RETVAL(etrax_gpio_wake_up_check()); | 368 | return IRQ_RETVAL(etrax_gpio_wake_up_check()); |
342 | } | 369 | } |
@@ -350,6 +377,9 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, | |||
350 | struct gpio_private *priv = (struct gpio_private *)file->private_data; | 377 | struct gpio_private *priv = (struct gpio_private *)file->private_data; |
351 | unsigned char data, clk_mask, data_mask, write_msb; | 378 | unsigned char data, clk_mask, data_mask, write_msb; |
352 | unsigned long flags; | 379 | unsigned long flags; |
380 | |||
381 | spin_lock(&gpio_lock); | ||
382 | |||
353 | ssize_t retval = count; | 383 | ssize_t retval = count; |
354 | if (priv->minor !=GPIO_MINOR_A && priv->minor != GPIO_MINOR_B) { | 384 | if (priv->minor !=GPIO_MINOR_A && priv->minor != GPIO_MINOR_B) { |
355 | return -EFAULT; | 385 | return -EFAULT; |
@@ -372,7 +402,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, | |||
372 | data = *buf++; | 402 | data = *buf++; |
373 | if (priv->write_msb) { | 403 | if (priv->write_msb) { |
374 | for (i = 7; i >= 0;i--) { | 404 | for (i = 7; i >= 0;i--) { |
375 | local_irq_save(flags); local_irq_disable(); | 405 | local_irq_save(flags); |
376 | *priv->port = *priv->shadow &= ~clk_mask; | 406 | *priv->port = *priv->shadow &= ~clk_mask; |
377 | if (data & 1<<i) | 407 | if (data & 1<<i) |
378 | *priv->port = *priv->shadow |= data_mask; | 408 | *priv->port = *priv->shadow |= data_mask; |
@@ -384,7 +414,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, | |||
384 | } | 414 | } |
385 | } else { | 415 | } else { |
386 | for (i = 0; i <= 7;i++) { | 416 | for (i = 0; i <= 7;i++) { |
387 | local_irq_save(flags); local_irq_disable(); | 417 | local_irq_save(flags); |
388 | *priv->port = *priv->shadow &= ~clk_mask; | 418 | *priv->port = *priv->shadow &= ~clk_mask; |
389 | if (data & 1<<i) | 419 | if (data & 1<<i) |
390 | *priv->port = *priv->shadow |= data_mask; | 420 | *priv->port = *priv->shadow |= data_mask; |
@@ -396,6 +426,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, | |||
396 | } | 426 | } |
397 | } | 427 | } |
398 | } | 428 | } |
429 | spin_unlock(&gpio_lock); | ||
399 | return retval; | 430 | return retval; |
400 | } | 431 | } |
401 | 432 | ||
@@ -452,9 +483,14 @@ gpio_open(struct inode *inode, struct file *filp) | |||
452 | static int | 483 | static int |
453 | gpio_release(struct inode *inode, struct file *filp) | 484 | gpio_release(struct inode *inode, struct file *filp) |
454 | { | 485 | { |
455 | struct gpio_private *p = alarmlist; | 486 | struct gpio_private *p; |
456 | struct gpio_private *todel = (struct gpio_private *)filp->private_data; | 487 | struct gpio_private *todel; |
457 | 488 | ||
489 | spin_lock(&gpio_lock); | ||
490 | |||
491 | p = alarmlist; | ||
492 | todel = (struct gpio_private *)filp->private_data; | ||
493 | |||
458 | /* unlink from alarmlist and free the private structure */ | 494 | /* unlink from alarmlist and free the private structure */ |
459 | 495 | ||
460 | if (p == todel) { | 496 | if (p == todel) { |
@@ -476,7 +512,7 @@ gpio_release(struct inode *inode, struct file *filp) | |||
476 | p = p->next; | 512 | p = p->next; |
477 | } | 513 | } |
478 | gpio_some_alarms = 0; | 514 | gpio_some_alarms = 0; |
479 | 515 | spin_unlock(&gpio_lock); | |
480 | return 0; | 516 | return 0; |
481 | } | 517 | } |
482 | 518 | ||
@@ -491,14 +527,14 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) | |||
491 | */ | 527 | */ |
492 | unsigned long flags; | 528 | unsigned long flags; |
493 | if (USE_PORTS(priv)) { | 529 | if (USE_PORTS(priv)) { |
494 | local_irq_save(flags); local_irq_disable(); | 530 | local_irq_save(flags); |
495 | *priv->dir = *priv->dir_shadow &= | 531 | *priv->dir = *priv->dir_shadow &= |
496 | ~((unsigned char)arg & priv->changeable_dir); | 532 | ~((unsigned char)arg & priv->changeable_dir); |
497 | local_irq_restore(flags); | 533 | local_irq_restore(flags); |
498 | return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */ | 534 | return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */ |
499 | } else if (priv->minor == GPIO_MINOR_G) { | 535 | } else if (priv->minor == GPIO_MINOR_G) { |
500 | /* We must fiddle with R_GEN_CONFIG to change dir */ | 536 | /* We must fiddle with R_GEN_CONFIG to change dir */ |
501 | save_flags(flags); cli(); | 537 | local_irq_save(flags); |
502 | if (((arg & dir_g_in_bits) != arg) && | 538 | if (((arg & dir_g_in_bits) != arg) && |
503 | (arg & changeable_dir_g)) { | 539 | (arg & changeable_dir_g)) { |
504 | arg &= changeable_dir_g; | 540 | arg &= changeable_dir_g; |
@@ -533,7 +569,7 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) | |||
533 | /* Must be a >120 ns delay before writing this again */ | 569 | /* Must be a >120 ns delay before writing this again */ |
534 | 570 | ||
535 | } | 571 | } |
536 | restore_flags(flags); | 572 | local_irq_restore(flags); |
537 | return dir_g_in_bits; | 573 | return dir_g_in_bits; |
538 | } | 574 | } |
539 | return 0; | 575 | return 0; |
@@ -543,14 +579,14 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) | |||
543 | { | 579 | { |
544 | unsigned long flags; | 580 | unsigned long flags; |
545 | if (USE_PORTS(priv)) { | 581 | if (USE_PORTS(priv)) { |
546 | local_irq_save(flags); local_irq_disable(); | 582 | local_irq_save(flags); |
547 | *priv->dir = *priv->dir_shadow |= | 583 | *priv->dir = *priv->dir_shadow |= |
548 | ((unsigned char)arg & priv->changeable_dir); | 584 | ((unsigned char)arg & priv->changeable_dir); |
549 | local_irq_restore(flags); | 585 | local_irq_restore(flags); |
550 | return *priv->dir_shadow; | 586 | return *priv->dir_shadow; |
551 | } else if (priv->minor == GPIO_MINOR_G) { | 587 | } else if (priv->minor == GPIO_MINOR_G) { |
552 | /* We must fiddle with R_GEN_CONFIG to change dir */ | 588 | /* We must fiddle with R_GEN_CONFIG to change dir */ |
553 | save_flags(flags); cli(); | 589 | local_irq_save(flags); |
554 | if (((arg & dir_g_out_bits) != arg) && | 590 | if (((arg & dir_g_out_bits) != arg) && |
555 | (arg & changeable_dir_g)) { | 591 | (arg & changeable_dir_g)) { |
556 | /* Set bits in genconfig to set to output */ | 592 | /* Set bits in genconfig to set to output */ |
@@ -583,7 +619,7 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) | |||
583 | *R_GEN_CONFIG = genconfig_shadow; | 619 | *R_GEN_CONFIG = genconfig_shadow; |
584 | /* Must be a >120 ns delay before writing this again */ | 620 | /* Must be a >120 ns delay before writing this again */ |
585 | } | 621 | } |
586 | restore_flags(flags); | 622 | local_irq_restore(flags); |
587 | return dir_g_out_bits & 0x7FFFFFFF; | 623 | return dir_g_out_bits & 0x7FFFFFFF; |
588 | } | 624 | } |
589 | return 0; | 625 | return 0; |
@@ -598,22 +634,26 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
598 | { | 634 | { |
599 | unsigned long flags; | 635 | unsigned long flags; |
600 | unsigned long val; | 636 | unsigned long val; |
637 | int ret = 0; | ||
638 | |||
601 | struct gpio_private *priv = (struct gpio_private *)file->private_data; | 639 | struct gpio_private *priv = (struct gpio_private *)file->private_data; |
602 | if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { | 640 | if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { |
603 | return -EINVAL; | 641 | return -EINVAL; |
604 | } | 642 | } |
605 | 643 | ||
644 | spin_lock(&gpio_lock); | ||
645 | |||
606 | switch (_IOC_NR(cmd)) { | 646 | switch (_IOC_NR(cmd)) { |
607 | case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ | 647 | case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ |
608 | // read the port | 648 | // read the port |
609 | if (USE_PORTS(priv)) { | 649 | if (USE_PORTS(priv)) { |
610 | return *priv->port; | 650 | ret = *priv->port; |
611 | } else if (priv->minor == GPIO_MINOR_G) { | 651 | } else if (priv->minor == GPIO_MINOR_G) { |
612 | return (*R_PORT_G_DATA) & 0x7FFFFFFF; | 652 | ret = (*R_PORT_G_DATA) & 0x7FFFFFFF; |
613 | } | 653 | } |
614 | break; | 654 | break; |
615 | case IO_SETBITS: | 655 | case IO_SETBITS: |
616 | local_irq_save(flags); local_irq_disable(); | 656 | local_irq_save(flags); |
617 | // set changeable bits with a 1 in arg | 657 | // set changeable bits with a 1 in arg |
618 | if (USE_PORTS(priv)) { | 658 | if (USE_PORTS(priv)) { |
619 | *priv->port = *priv->shadow |= | 659 | *priv->port = *priv->shadow |= |
@@ -624,7 +664,7 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
624 | local_irq_restore(flags); | 664 | local_irq_restore(flags); |
625 | break; | 665 | break; |
626 | case IO_CLRBITS: | 666 | case IO_CLRBITS: |
627 | local_irq_save(flags); local_irq_disable(); | 667 | local_irq_save(flags); |
628 | // clear changeable bits with a 1 in arg | 668 | // clear changeable bits with a 1 in arg |
629 | if (USE_PORTS(priv)) { | 669 | if (USE_PORTS(priv)) { |
630 | *priv->port = *priv->shadow &= | 670 | *priv->port = *priv->shadow &= |
@@ -666,33 +706,34 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
666 | case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ | 706 | case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ |
667 | /* Read direction 0=input 1=output */ | 707 | /* Read direction 0=input 1=output */ |
668 | if (USE_PORTS(priv)) { | 708 | if (USE_PORTS(priv)) { |
669 | return *priv->dir_shadow; | 709 | ret = *priv->dir_shadow; |
670 | } else if (priv->minor == GPIO_MINOR_G) { | 710 | } else if (priv->minor == GPIO_MINOR_G) { |
671 | /* Note: Some bits are both in and out, | 711 | /* Note: Some bits are both in and out, |
672 | * Those that are dual is set here as well. | 712 | * Those that are dual is set here as well. |
673 | */ | 713 | */ |
674 | return (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF; | 714 | ret = (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF; |
675 | } | 715 | } |
716 | break; | ||
676 | case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ | 717 | case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ |
677 | /* Set direction 0=unchanged 1=input, | 718 | /* Set direction 0=unchanged 1=input, |
678 | * return mask with 1=input | 719 | * return mask with 1=input |
679 | */ | 720 | */ |
680 | return setget_input(priv, arg) & 0x7FFFFFFF; | 721 | ret = setget_input(priv, arg) & 0x7FFFFFFF; |
681 | break; | 722 | break; |
682 | case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ | 723 | case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ |
683 | /* Set direction 0=unchanged 1=output, | 724 | /* Set direction 0=unchanged 1=output, |
684 | * return mask with 1=output | 725 | * return mask with 1=output |
685 | */ | 726 | */ |
686 | return setget_output(priv, arg) & 0x7FFFFFFF; | 727 | ret = setget_output(priv, arg) & 0x7FFFFFFF; |
687 | 728 | break; | |
688 | case IO_SHUTDOWN: | 729 | case IO_SHUTDOWN: |
689 | SOFT_SHUTDOWN(); | 730 | SOFT_SHUTDOWN(); |
690 | break; | 731 | break; |
691 | case IO_GET_PWR_BT: | 732 | case IO_GET_PWR_BT: |
692 | #if defined (CONFIG_ETRAX_SOFT_SHUTDOWN) | 733 | #if defined (CONFIG_ETRAX_SOFT_SHUTDOWN) |
693 | return (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); | 734 | ret = (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); |
694 | #else | 735 | #else |
695 | return 0; | 736 | ret = 0; |
696 | #endif | 737 | #endif |
697 | break; | 738 | break; |
698 | case IO_CFG_WRITE_MODE: | 739 | case IO_CFG_WRITE_MODE: |
@@ -709,7 +750,7 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
709 | { | 750 | { |
710 | priv->clk_mask = 0; | 751 | priv->clk_mask = 0; |
711 | priv->data_mask = 0; | 752 | priv->data_mask = 0; |
712 | return -EPERM; | 753 | ret = -EPERM; |
713 | } | 754 | } |
714 | break; | 755 | break; |
715 | case IO_READ_INBITS: | 756 | case IO_READ_INBITS: |
@@ -720,8 +761,7 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
720 | val = *R_PORT_G_DATA; | 761 | val = *R_PORT_G_DATA; |
721 | } | 762 | } |
722 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) | 763 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) |
723 | return -EFAULT; | 764 | ret = -EFAULT; |
724 | return 0; | ||
725 | break; | 765 | break; |
726 | case IO_READ_OUTBITS: | 766 | case IO_READ_OUTBITS: |
727 | /* *arg is result of reading the output shadow */ | 767 | /* *arg is result of reading the output shadow */ |
@@ -731,36 +771,43 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
731 | val = port_g_data_shadow; | 771 | val = port_g_data_shadow; |
732 | } | 772 | } |
733 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) | 773 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) |
734 | return -EFAULT; | 774 | ret = -EFAULT; |
735 | break; | 775 | break; |
736 | case IO_SETGET_INPUT: | 776 | case IO_SETGET_INPUT: |
737 | /* bits set in *arg is set to input, | 777 | /* bits set in *arg is set to input, |
738 | * *arg updated with current input pins. | 778 | * *arg updated with current input pins. |
739 | */ | 779 | */ |
740 | if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) | 780 | if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) |
741 | return -EFAULT; | 781 | { |
782 | ret = -EFAULT; | ||
783 | break; | ||
784 | } | ||
742 | val = setget_input(priv, val); | 785 | val = setget_input(priv, val); |
743 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) | 786 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) |
744 | return -EFAULT; | 787 | ret = -EFAULT; |
745 | break; | 788 | break; |
746 | case IO_SETGET_OUTPUT: | 789 | case IO_SETGET_OUTPUT: |
747 | /* bits set in *arg is set to output, | 790 | /* bits set in *arg is set to output, |
748 | * *arg updated with current output pins. | 791 | * *arg updated with current output pins. |
749 | */ | 792 | */ |
750 | if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) | 793 | if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) |
751 | return -EFAULT; | 794 | { |
795 | ret = -EFAULT; | ||
796 | break; | ||
797 | } | ||
752 | val = setget_output(priv, val); | 798 | val = setget_output(priv, val); |
753 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) | 799 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) |
754 | return -EFAULT; | 800 | ret = -EFAULT; |
755 | break; | 801 | break; |
756 | default: | 802 | default: |
757 | if (priv->minor == GPIO_MINOR_LEDS) | 803 | if (priv->minor == GPIO_MINOR_LEDS) |
758 | return gpio_leds_ioctl(cmd, arg); | 804 | ret = gpio_leds_ioctl(cmd, arg); |
759 | else | 805 | else |
760 | return -EINVAL; | 806 | ret = -EINVAL; |
761 | } /* switch */ | 807 | } /* switch */ |
762 | 808 | ||
763 | return 0; | 809 | spin_unlock(&gpio_lock); |
810 | return ret; | ||
764 | } | 811 | } |
765 | 812 | ||
766 | static int | 813 | static int |
@@ -802,60 +849,20 @@ struct file_operations gpio_fops = { | |||
802 | }; | 849 | }; |
803 | 850 | ||
804 | 851 | ||
805 | static void __init gpio_init_port_g(void) | 852 | void ioif_watcher(const unsigned int gpio_in_available, |
853 | const unsigned int gpio_out_available, | ||
854 | const unsigned char pa_available, | ||
855 | const unsigned char pb_available) | ||
806 | { | 856 | { |
807 | #define GROUPA (0x0000FF3F) | 857 | unsigned long int flags; |
808 | #define GROUPB (1<<6 | 1<<7) | 858 | D(printk("gpio.c: ioif_watcher called\n")); |
809 | #define GROUPC (1<<30 | 1<<31) | 859 | D(printk("gpio.c: G in: 0x%08x G out: 0x%08x PA: 0x%02x PB: 0x%02x\n", |
810 | #define GROUPD (0x3FFF0000) | 860 | gpio_in_available, gpio_out_available, pa_available, pb_available)); |
811 | #define GROUPD_LOW (0x00FF0000) | ||
812 | unsigned long used_in_bits = 0; | ||
813 | unsigned long used_out_bits = 0; | ||
814 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0, select)){ | ||
815 | used_in_bits |= GROUPA | GROUPB | 0 | 0; | ||
816 | used_out_bits |= GROUPA | GROUPB | 0 | 0; | ||
817 | } | ||
818 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ata, select)) { | ||
819 | used_in_bits |= GROUPA | GROUPB | GROUPC | (GROUPD & ~(1<<25|1<<26)); | ||
820 | used_out_bits |= GROUPA | GROUPB | GROUPC | GROUPD; | ||
821 | } | ||
822 | 861 | ||
823 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par0, select)) { | 862 | spin_lock_irqsave(&gpio_lock, flags); |
824 | used_in_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0; | ||
825 | used_out_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0; | ||
826 | } | ||
827 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser2, select)) { | ||
828 | used_in_bits |= 0 | GROUPB | 0 | 0; | ||
829 | used_out_bits |= 0 | GROUPB | 0 | 0; | ||
830 | } | ||
831 | /* mio same as shared RAM ? */ | ||
832 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio, select)) { | ||
833 | used_in_bits |= (GROUPA & ~(1<<0)) | 0 |0 |GROUPD_LOW; | ||
834 | used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 |0 |GROUPD_LOW; | ||
835 | } | ||
836 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi1, select)) { | ||
837 | used_in_bits |= 0 | 0 | GROUPC | GROUPD; | ||
838 | used_out_bits |= 0 | 0 | GROUPC | GROUPD; | ||
839 | } | ||
840 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0w, select)) { | ||
841 | used_in_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24); | ||
842 | used_out_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24 | 1<<25|1<<26); | ||
843 | } | ||
844 | 863 | ||
845 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par1, select)) { | 864 | dir_g_in_bits = gpio_in_available; |
846 | used_in_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24)); | 865 | dir_g_out_bits = gpio_out_available; |
847 | used_out_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24)); | ||
848 | } | ||
849 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser3, select)) { | ||
850 | used_in_bits |= 0 | 0 | GROUPC | 0; | ||
851 | used_out_bits |= 0 | 0 | GROUPC | 0; | ||
852 | } | ||
853 | /* mio same as shared RAM-W? */ | ||
854 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio_w, select)) { | ||
855 | used_in_bits |= (GROUPA & ~(1<<0)) | 0 | 0 |GROUPD_LOW; | ||
856 | used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 | 0 |GROUPD_LOW; | ||
857 | } | ||
858 | /* TODO: USB p2, parw, sync ser3? */ | ||
859 | 866 | ||
860 | /* Initialise the dir_g_shadow etc. depending on genconfig */ | 867 | /* Initialise the dir_g_shadow etc. depending on genconfig */ |
861 | /* 0=input 1=output */ | 868 | /* 0=input 1=output */ |
@@ -868,10 +875,7 @@ static void __init gpio_init_port_g(void) | |||
868 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g24dir, out)) | 875 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g24dir, out)) |
869 | dir_g_shadow |= (1 << 24); | 876 | dir_g_shadow |= (1 << 24); |
870 | 877 | ||
871 | dir_g_in_bits = ~used_in_bits; | 878 | changeable_dir_g = changeable_dir_g_mask; |
872 | dir_g_out_bits = ~used_out_bits; | ||
873 | |||
874 | changeable_dir_g = 0x01FFFF01; /* all that can change dir */ | ||
875 | changeable_dir_g &= dir_g_out_bits; | 879 | changeable_dir_g &= dir_g_out_bits; |
876 | changeable_dir_g &= dir_g_in_bits; | 880 | changeable_dir_g &= dir_g_in_bits; |
877 | /* Correct the bits that can change direction */ | 881 | /* Correct the bits that can change direction */ |
@@ -880,6 +884,7 @@ static void __init gpio_init_port_g(void) | |||
880 | dir_g_in_bits &= ~changeable_dir_g; | 884 | dir_g_in_bits &= ~changeable_dir_g; |
881 | dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g); | 885 | dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g); |
882 | 886 | ||
887 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
883 | 888 | ||
884 | printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n", | 889 | printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n", |
885 | dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA); | 890 | dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA); |
@@ -896,6 +901,7 @@ gpio_init(void) | |||
896 | #if defined (CONFIG_ETRAX_CSP0_LEDS) | 901 | #if defined (CONFIG_ETRAX_CSP0_LEDS) |
897 | int i; | 902 | int i; |
898 | #endif | 903 | #endif |
904 | printk("gpio init\n"); | ||
899 | 905 | ||
900 | /* do the formalities */ | 906 | /* do the formalities */ |
901 | 907 | ||
@@ -919,8 +925,13 @@ gpio_init(void) | |||
919 | #endif | 925 | #endif |
920 | 926 | ||
921 | #endif | 927 | #endif |
922 | gpio_init_port_g(); | 928 | /* The I/O interface allocation watcher will be called when |
923 | printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n"); | 929 | * registering it. */ |
930 | if (cris_io_interface_register_watcher(ioif_watcher)){ | ||
931 | printk(KERN_WARNING "gpio_init: Failed to install IO if allocator watcher\n"); | ||
932 | } | ||
933 | |||
934 | printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002, 2003, 2004 Axis Communications AB\n"); | ||
924 | /* We call etrax_gpio_wake_up_check() from timer interrupt and | 935 | /* We call etrax_gpio_wake_up_check() from timer interrupt and |
925 | * from cpu_idle() in kernel/process.c | 936 | * from cpu_idle() in kernel/process.c |
926 | * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms | 937 | * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms |