diff options
Diffstat (limited to 'arch/cris/arch-v10/drivers/i2c.c')
-rw-r--r-- | arch/cris/arch-v10/drivers/i2c.c | 62 |
1 files changed, 55 insertions, 7 deletions
diff --git a/arch/cris/arch-v10/drivers/i2c.c b/arch/cris/arch-v10/drivers/i2c.c index 8bbe233ba7b1..b38267d60d30 100644 --- a/arch/cris/arch-v10/drivers/i2c.c +++ b/arch/cris/arch-v10/drivers/i2c.c | |||
@@ -12,6 +12,15 @@ | |||
12 | *! don't use PB_I2C if DS1302 uses same bits, | 12 | *! don't use PB_I2C if DS1302 uses same bits, |
13 | *! use PB. | 13 | *! use PB. |
14 | *! $Log: i2c.c,v $ | 14 | *! $Log: i2c.c,v $ |
15 | *! Revision 1.13 2005/03/07 13:13:07 starvik | ||
16 | *! Added spinlocks to protect states etc | ||
17 | *! | ||
18 | *! Revision 1.12 2005/01/05 06:11:22 starvik | ||
19 | *! No need to do local_irq_disable after local_irq_save. | ||
20 | *! | ||
21 | *! Revision 1.11 2004/12/13 12:21:52 starvik | ||
22 | *! Added I/O and DMA allocators from Linux 2.4 | ||
23 | *! | ||
15 | *! Revision 1.9 2004/08/24 06:49:14 starvik | 24 | *! Revision 1.9 2004/08/24 06:49:14 starvik |
16 | *! Whitespace cleanup | 25 | *! Whitespace cleanup |
17 | *! | 26 | *! |
@@ -75,7 +84,7 @@ | |||
75 | *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN | 84 | *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN |
76 | *! | 85 | *! |
77 | *!***************************************************************************/ | 86 | *!***************************************************************************/ |
78 | /* $Id: i2c.c,v 1.9 2004/08/24 06:49:14 starvik Exp $ */ | 87 | /* $Id: i2c.c,v 1.13 2005/03/07 13:13:07 starvik Exp $ */ |
79 | 88 | ||
80 | /****************** INCLUDE FILES SECTION ***********************************/ | 89 | /****************** INCLUDE FILES SECTION ***********************************/ |
81 | 90 | ||
@@ -95,6 +104,7 @@ | |||
95 | #include <asm/arch/svinto.h> | 104 | #include <asm/arch/svinto.h> |
96 | #include <asm/io.h> | 105 | #include <asm/io.h> |
97 | #include <asm/delay.h> | 106 | #include <asm/delay.h> |
107 | #include <asm/arch/io_interface_mux.h> | ||
98 | 108 | ||
99 | #include "i2c.h" | 109 | #include "i2c.h" |
100 | 110 | ||
@@ -184,6 +194,7 @@ static const char i2c_name[] = "i2c"; | |||
184 | 194 | ||
185 | #define i2c_delay(usecs) udelay(usecs) | 195 | #define i2c_delay(usecs) udelay(usecs) |
186 | 196 | ||
197 | static DEFINE_SPINLOCK(i2c_lock); /* Protect directions etc */ | ||
187 | 198 | ||
188 | /****************** FUNCTION DEFINITION SECTION *************************/ | 199 | /****************** FUNCTION DEFINITION SECTION *************************/ |
189 | 200 | ||
@@ -488,13 +499,14 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, | |||
488 | int error, cntr = 3; | 499 | int error, cntr = 3; |
489 | unsigned long flags; | 500 | unsigned long flags; |
490 | 501 | ||
502 | spin_lock(&i2c_lock); | ||
503 | |||
491 | do { | 504 | do { |
492 | error = 0; | 505 | error = 0; |
493 | /* | 506 | /* |
494 | * we don't like to be interrupted | 507 | * we don't like to be interrupted |
495 | */ | 508 | */ |
496 | local_irq_save(flags); | 509 | local_irq_save(flags); |
497 | local_irq_disable(); | ||
498 | 510 | ||
499 | i2c_start(); | 511 | i2c_start(); |
500 | /* | 512 | /* |
@@ -538,6 +550,8 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, | |||
538 | 550 | ||
539 | i2c_delay(CLOCK_LOW_TIME); | 551 | i2c_delay(CLOCK_LOW_TIME); |
540 | 552 | ||
553 | spin_unlock(&i2c_lock); | ||
554 | |||
541 | return -error; | 555 | return -error; |
542 | } | 556 | } |
543 | 557 | ||
@@ -555,13 +569,14 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) | |||
555 | int error, cntr = 3; | 569 | int error, cntr = 3; |
556 | unsigned long flags; | 570 | unsigned long flags; |
557 | 571 | ||
572 | spin_lock(&i2c_lock); | ||
573 | |||
558 | do { | 574 | do { |
559 | error = 0; | 575 | error = 0; |
560 | /* | 576 | /* |
561 | * we don't like to be interrupted | 577 | * we don't like to be interrupted |
562 | */ | 578 | */ |
563 | local_irq_save(flags); | 579 | local_irq_save(flags); |
564 | local_irq_disable(); | ||
565 | /* | 580 | /* |
566 | * generate start condition | 581 | * generate start condition |
567 | */ | 582 | */ |
@@ -620,6 +635,8 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) | |||
620 | 635 | ||
621 | } while(error && cntr--); | 636 | } while(error && cntr--); |
622 | 637 | ||
638 | spin_unlock(&i2c_lock); | ||
639 | |||
623 | return b; | 640 | return b; |
624 | } | 641 | } |
625 | 642 | ||
@@ -686,15 +703,26 @@ static struct file_operations i2c_fops = { | |||
686 | int __init | 703 | int __init |
687 | i2c_init(void) | 704 | i2c_init(void) |
688 | { | 705 | { |
706 | static int res = 0; | ||
707 | static int first = 1; | ||
708 | |||
709 | if (!first) { | ||
710 | return res; | ||
711 | } | ||
712 | |||
689 | /* Setup and enable the Port B I2C interface */ | 713 | /* Setup and enable the Port B I2C interface */ |
690 | 714 | ||
691 | #ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C | 715 | #ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C |
716 | if ((res = cris_request_io_interface(if_i2c, "I2C"))) { | ||
717 | printk(KERN_CRIT "i2c_init: Failed to get IO interface\n"); | ||
718 | return res; | ||
719 | } | ||
720 | |||
692 | *R_PORT_PB_I2C = port_pb_i2c_shadow |= | 721 | *R_PORT_PB_I2C = port_pb_i2c_shadow |= |
693 | IO_STATE(R_PORT_PB_I2C, i2c_en, on) | | 722 | IO_STATE(R_PORT_PB_I2C, i2c_en, on) | |
694 | IO_FIELD(R_PORT_PB_I2C, i2c_d, 1) | | 723 | IO_FIELD(R_PORT_PB_I2C, i2c_d, 1) | |
695 | IO_FIELD(R_PORT_PB_I2C, i2c_clk, 1) | | 724 | IO_FIELD(R_PORT_PB_I2C, i2c_clk, 1) | |
696 | IO_STATE(R_PORT_PB_I2C, i2c_oe_, enable); | 725 | IO_STATE(R_PORT_PB_I2C, i2c_oe_, enable); |
697 | #endif | ||
698 | 726 | ||
699 | port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir0); | 727 | port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir0); |
700 | port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir1); | 728 | port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir1); |
@@ -702,8 +730,26 @@ i2c_init(void) | |||
702 | *R_PORT_PB_DIR = (port_pb_dir_shadow |= | 730 | *R_PORT_PB_DIR = (port_pb_dir_shadow |= |
703 | IO_STATE(R_PORT_PB_DIR, dir0, input) | | 731 | IO_STATE(R_PORT_PB_DIR, dir0, input) | |
704 | IO_STATE(R_PORT_PB_DIR, dir1, output)); | 732 | IO_STATE(R_PORT_PB_DIR, dir1, output)); |
733 | #else | ||
734 | if ((res = cris_io_interface_allocate_pins(if_i2c, | ||
735 | 'b', | ||
736 | CONFIG_ETRAX_I2C_DATA_PORT, | ||
737 | CONFIG_ETRAX_I2C_DATA_PORT))) { | ||
738 | printk(KERN_WARNING "i2c_init: Failed to get IO pin for I2C data port\n"); | ||
739 | return res; | ||
740 | } else if ((res = cris_io_interface_allocate_pins(if_i2c, | ||
741 | 'b', | ||
742 | CONFIG_ETRAX_I2C_CLK_PORT, | ||
743 | CONFIG_ETRAX_I2C_CLK_PORT))) { | ||
744 | cris_io_interface_free_pins(if_i2c, | ||
745 | 'b', | ||
746 | CONFIG_ETRAX_I2C_DATA_PORT, | ||
747 | CONFIG_ETRAX_I2C_DATA_PORT); | ||
748 | printk(KERN_WARNING "i2c_init: Failed to get IO pin for I2C clk port\n"); | ||
749 | } | ||
750 | #endif | ||
705 | 751 | ||
706 | return 0; | 752 | return res; |
707 | } | 753 | } |
708 | 754 | ||
709 | static int __init | 755 | static int __init |
@@ -711,14 +757,16 @@ i2c_register(void) | |||
711 | { | 757 | { |
712 | int res; | 758 | int res; |
713 | 759 | ||
714 | i2c_init(); | 760 | res = i2c_init(); |
761 | if (res < 0) | ||
762 | return res; | ||
715 | res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops); | 763 | res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops); |
716 | if(res < 0) { | 764 | if(res < 0) { |
717 | printk(KERN_ERR "i2c: couldn't get a major number.\n"); | 765 | printk(KERN_ERR "i2c: couldn't get a major number.\n"); |
718 | return res; | 766 | return res; |
719 | } | 767 | } |
720 | 768 | ||
721 | printk(KERN_INFO "I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n"); | 769 | printk(KERN_INFO "I2C driver v2.2, (c) 1999-2004 Axis Communications AB\n"); |
722 | 770 | ||
723 | return 0; | 771 | return 0; |
724 | } | 772 | } |