fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / cris / arch-v10 / drivers / i2c.c
index 52a299d..092c724 100644 (file)
 *!                                 don't use PB_I2C if DS1302 uses same bits,
 *!                                 use PB.
 *! $Log: i2c.c,v $
+*! Revision 1.13  2005/03/07 13:13:07  starvik
+*! Added spinlocks to protect states etc
+*!
+*! Revision 1.12  2005/01/05 06:11:22  starvik
+*! No need to do local_irq_disable after local_irq_save.
+*!
+*! Revision 1.11  2004/12/13 12:21:52  starvik
+*! Added I/O and DMA allocators from Linux 2.4
+*!
+*! Revision 1.9  2004/08/24 06:49:14  starvik
+*! Whitespace cleanup
+*!
+*! Revision 1.8  2004/06/08 08:48:26  starvik
+*! Removed unused code
+*!
 *! Revision 1.7  2004/05/28 09:26:59  starvik
 *! Modified I2C initialization to work in 2.6.
 *!
@@ -32,7 +47,7 @@
 *! Update Port B register and shadow even when running with hardware support
 *!   to avoid glitches when reading bits
 *! Never set direction to out in i2c_inbyte
-*! Removed incorrect clock togling at end of i2c_inbyte
+*! Removed incorrect clock toggling at end of i2c_inbyte
 *!
 *! Revision 1.8  2002/08/13 06:31:53  starvik
 *! Made SDA and SCL line configurable
@@ -69,7 +84,7 @@
 *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
 *!
 *!***************************************************************************/
-/* $Id: i2c.c,v 1.7 2004/05/28 09:26:59 starvik Exp $ */
+/* $Id: i2c.c,v 1.13 2005/03/07 13:13:07 starvik Exp $ */
 
 /****************** INCLUDE FILES SECTION ***********************************/
 
@@ -81,7 +96,6 @@
 #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/init.h>
-#include <linux/config.h>
 
 #include <asm/etraxi2c.h>
 
 #include <asm/arch/svinto.h>
 #include <asm/io.h>
 #include <asm/delay.h>
+#include <asm/arch/io_interface_mux.h>
 
 #include "i2c.h"
 
@@ -110,14 +125,6 @@ static const char i2c_name[] = "i2c";
 #define I2C_DATA_HIGH 1
 #define I2C_DATA_LOW 0
 
-#if 0
-/* TODO: fix this so the CONFIG_ETRAX_I2C_USES... is set in Config.in instead */
-#if defined(CONFIG_DS1302) && (CONFIG_DS1302_SDABIT==0) && \
-           (CONFIG_DS1302_SCLBIT == 1)
-#define CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
-#endif
-#endif
-
 #ifdef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
 /* Use PB and not PB_I2C */
 #ifndef CONFIG_ETRAX_I2C_DATA_PORT
@@ -186,6 +193,7 @@ static const char i2c_name[] = "i2c";
 
 #define i2c_delay(usecs) udelay(usecs)
 
+static DEFINE_SPINLOCK(i2c_lock); /* Protect directions etc */
 
 /****************** FUNCTION DEFINITION SECTION *************************/
 
@@ -441,7 +449,7 @@ i2c_sendack(void)
         */
        i2c_data(I2C_DATA_HIGH);
        i2c_delay(CLOCK_LOW_TIME);
-       
+
        i2c_dir_in();
 }
 
@@ -490,13 +498,14 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg,
        int error, cntr = 3;
        unsigned long flags;
 
+       spin_lock(&i2c_lock);
+
        do {
                error = 0;
                /*
                 * we don't like to be interrupted
                 */
                local_irq_save(flags);
-               local_irq_disable();
 
                i2c_start();
                /*
@@ -540,6 +549,8 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg,
 
        i2c_delay(CLOCK_LOW_TIME);
 
+       spin_unlock(&i2c_lock);
+
        return -error;
 }
 
@@ -557,13 +568,14 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
        int error, cntr = 3;
        unsigned long flags;
 
+       spin_lock(&i2c_lock);
+
        do {
                error = 0;
                /*
                 * we don't like to be interrupted
                 */
                local_irq_save(flags);
-               local_irq_disable();
                /*
                 * generate start condition
                 */
@@ -622,6 +634,8 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
                
        } while(error && cntr--);
 
+       spin_unlock(&i2c_lock);
+
        return b;
 }
 
@@ -688,15 +702,26 @@ static struct file_operations i2c_fops = {
 int __init
 i2c_init(void)
 {
+       static int res = 0;
+       static int first = 1;
+
+       if (!first) {
+               return res;
+       }
+
        /* Setup and enable the Port B I2C interface */
 
 #ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
+       if ((res = cris_request_io_interface(if_i2c, "I2C"))) {
+               printk(KERN_CRIT "i2c_init: Failed to get IO interface\n");
+               return res;
+       }
+
        *R_PORT_PB_I2C = port_pb_i2c_shadow |= 
                IO_STATE(R_PORT_PB_I2C, i2c_en,  on) |
                IO_FIELD(R_PORT_PB_I2C, i2c_d,   1)  |
                IO_FIELD(R_PORT_PB_I2C, i2c_clk, 1)  |
                IO_STATE(R_PORT_PB_I2C, i2c_oe_, enable);
-#endif
 
        port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir0);
        port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir1);
@@ -704,8 +729,26 @@ i2c_init(void)
        *R_PORT_PB_DIR = (port_pb_dir_shadow |=
                          IO_STATE(R_PORT_PB_DIR, dir0, input)  |
                          IO_STATE(R_PORT_PB_DIR, dir1, output));
+#else
+        if ((res = cris_io_interface_allocate_pins(if_i2c,
+                                                  'b',
+                                                   CONFIG_ETRAX_I2C_DATA_PORT,
+                                                  CONFIG_ETRAX_I2C_DATA_PORT))) {
+               printk(KERN_WARNING "i2c_init: Failed to get IO pin for I2C data port\n");
+               return res;
+       } else if ((res = cris_io_interface_allocate_pins(if_i2c,
+                                                         'b',
+                                                         CONFIG_ETRAX_I2C_CLK_PORT,
+                                                         CONFIG_ETRAX_I2C_CLK_PORT))) {
+               cris_io_interface_free_pins(if_i2c,
+                                           'b',
+                                           CONFIG_ETRAX_I2C_DATA_PORT,
+                                           CONFIG_ETRAX_I2C_DATA_PORT);
+               printk(KERN_WARNING "i2c_init: Failed to get IO pin for I2C clk port\n");
+       }
+#endif
 
-       return 0;
+       return res;
 }
 
 static int __init
@@ -713,14 +756,16 @@ i2c_register(void)
 {
        int res;
 
-       i2c_init();
+       res = i2c_init();
+       if (res < 0)
+               return res;
        res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops);
        if(res < 0) {
                printk(KERN_ERR "i2c: couldn't get a major number.\n");
                return res;
        }
 
-       printk(KERN_INFO "I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n");
+       printk(KERN_INFO "I2C driver v2.2, (c) 1999-2004 Axis Communications AB\n");
        
        return 0;
 }