Loading arch/cris/arch-v32/drivers/i2c.c +185 −14 Original line number Diff line number Diff line Loading @@ -19,10 +19,10 @@ *! *! --------------------------------------------------------------------------- *! *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN *! (C) Copyright 1999-2007 Axis Communications AB, LUND, SWEDEN *! *!***************************************************************************/ /* $Id: i2c.c,v 1.2 2005/05/09 15:29:49 starvik Exp $ */ /****************** INCLUDE FILES SECTION ***********************************/ #include <linux/module.h> Loading Loading @@ -79,6 +79,8 @@ static const char i2c_name[] = "i2c"; #define i2c_delay(usecs) udelay(usecs) static DEFINE_SPINLOCK(i2c_lock); /* Protect directions etc */ /****************** VARIABLE SECTION ************************************/ static struct crisv32_iopin cris_i2c_clk; Loading Loading @@ -252,6 +254,7 @@ i2c_getack(void) * generate ACK clock pulse */ i2c_clk(I2C_CLOCK_HIGH); #if 0 /* * Use PORT PB instead of I2C * for input. (I2C not working) Loading @@ -264,6 +267,8 @@ i2c_getack(void) i2c_data(1); i2c_disable(); i2c_dir_in(); #endif /* * now wait for ack */ Loading @@ -275,7 +280,7 @@ i2c_getack(void) ack = 0; i2c_delay(CLOCK_HIGH_TIME/2); if (!ack) { if(!i2c_getbit()) /* receiver pulled SDA low */ if (!i2c_getbit()) /* receiver pulld SDA low */ ack = 1; i2c_delay(CLOCK_HIGH_TIME/2); } Loading @@ -285,6 +290,7 @@ i2c_getack(void) * before we enable our output. If we keep data high * and enable output, we would generate a stop condition. */ #if 0 i2c_data(I2C_DATA_LOW); /* Loading @@ -292,6 +298,7 @@ i2c_getack(void) */ i2c_enable(); i2c_dir_out(); #endif i2c_clk(I2C_CLOCK_LOW); i2c_delay(CLOCK_HIGH_TIME/4); /* Loading Loading @@ -373,6 +380,137 @@ i2c_sendnack(void) i2c_dir_in(); } /*#--------------------------------------------------------------------------- *# *# FUNCTION NAME: i2c_write *# *# DESCRIPTION : Writes a value to an I2C device *# *#--------------------------------------------------------------------------*/ int i2c_write(unsigned char theSlave, void *data, size_t nbytes) { int error, cntr = 3; unsigned char bytes_wrote = 0; unsigned char value; unsigned long flags; spin_lock(&i2c_lock); do { error = 0; /* * we don't like to be interrupted */ local_irq_save(flags); i2c_start(); /* * send slave address */ i2c_outbyte((theSlave & 0xfe)); /* * wait for ack */ if (!i2c_getack()) error = 1; /* * send data */ for (bytes_wrote = 0; bytes_wrote < nbytes; bytes_wrote++) { memcpy(&value, data + bytes_wrote, sizeof value); i2c_outbyte(value); /* * now it's time to wait for ack */ if (!i2c_getack()) error |= 4; } /* * end byte stream */ i2c_stop(); /* * enable interrupt again */ local_irq_restore(flags); } while (error && cntr--); i2c_delay(CLOCK_LOW_TIME); spin_unlock(&i2c_lock); return -error; } /*#--------------------------------------------------------------------------- *# *# FUNCTION NAME: i2c_read *# *# DESCRIPTION : Reads a value from an I2C device *# *#--------------------------------------------------------------------------*/ int i2c_read(unsigned char theSlave, void *data, size_t nbytes) { unsigned char b = 0; unsigned char bytes_read = 0; int error, cntr = 3; unsigned long flags; spin_lock(&i2c_lock); do { error = 0; memset(data, 0, nbytes); /* * we don't like to be interrupted */ local_irq_save(flags); /* * generate start condition */ i2c_start(); /* * send slave address */ i2c_outbyte((theSlave | 0x01)); /* * wait for ack */ if (!i2c_getack()) error = 1; /* * fetch data */ for (bytes_read = 0; bytes_read < nbytes; bytes_read++) { b = i2c_inbyte(); memcpy(data + bytes_read, &b, sizeof b); if (bytes_read < (nbytes - 1)) i2c_sendack(); } /* * last received byte needs to be nacked * instead of acked */ i2c_sendnack(); /* * end sequence */ i2c_stop(); /* * enable interrupt again */ local_irq_restore(flags); } while (error && cntr--); spin_unlock(&i2c_lock); return -error; } /*#--------------------------------------------------------------------------- *# *# FUNCTION NAME: i2c_writereg Loading @@ -387,6 +525,8 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, int error, cntr = 3; unsigned long flags; spin_lock(&i2c_lock); do { error = 0; /* Loading Loading @@ -431,11 +571,12 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, * enable interrupt again */ local_irq_restore(flags); } while(error && cntr--); i2c_delay(CLOCK_LOW_TIME); spin_unlock(&i2c_lock); return -error; } Loading @@ -453,6 +594,8 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) int error, cntr = 3; unsigned long flags; spin_lock(&i2c_lock); do { error = 0; /* Loading Loading @@ -482,7 +625,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) * now it's time to wait for ack */ if(!i2c_getack()) error = 1; error |= 2; /* * repeat start condition */ Loading @@ -496,7 +639,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) * wait for ack */ if(!i2c_getack()) error = 1; error |= 4; /* * fetch register */ Loading @@ -517,6 +660,8 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) } while(error && cntr--); spin_unlock(&i2c_lock); return b; } Loading Loading @@ -583,12 +728,37 @@ static const struct file_operations i2c_fops = { int __init i2c_init(void) { int res; static int res; static int first = 1; if (!first) return res; /* Setup and enable the Port B I2C interface */ first = 0; crisv32_io_get_name(&cris_i2c_data, CONFIG_ETRAX_I2C_DATA_PORT); crisv32_io_get_name(&cris_i2c_clk, CONFIG_ETRAX_I2C_CLK_PORT); /* Setup and enable the DATA and CLK pins */ res = crisv32_io_get_name(&cris_i2c_data, CONFIG_ETRAX_V32_I2C_DATA_PORT); if (res < 0) return res; res = crisv32_io_get_name(&cris_i2c_clk, CONFIG_ETRAX_V32_I2C_CLK_PORT); crisv32_io_set_dir(&cris_i2c_clk, crisv32_io_dir_out); return res; } int __init i2c_register(void) { int res; res = i2c_init(); if (res < 0) return res; /* register char device */ Loading @@ -598,13 +768,14 @@ i2c_init(void) 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-2007 Axis Communications AB\n"); return 0; } /* this makes sure that i2c_init is called during boot */ module_init(i2c_init); module_init(i2c_register); /****************** END OF FILE i2c.c ********************************/ arch/cris/arch-v32/drivers/i2c.h +2 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,8 @@ /* High level I2C actions */ int __init i2c_init(void); int i2c_write(unsigned char theSlave, void *data, size_t nbytes); int i2c_read(unsigned char theSlave, void *data, size_t nbytes); int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg); Loading Loading
arch/cris/arch-v32/drivers/i2c.c +185 −14 Original line number Diff line number Diff line Loading @@ -19,10 +19,10 @@ *! *! --------------------------------------------------------------------------- *! *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN *! (C) Copyright 1999-2007 Axis Communications AB, LUND, SWEDEN *! *!***************************************************************************/ /* $Id: i2c.c,v 1.2 2005/05/09 15:29:49 starvik Exp $ */ /****************** INCLUDE FILES SECTION ***********************************/ #include <linux/module.h> Loading Loading @@ -79,6 +79,8 @@ static const char i2c_name[] = "i2c"; #define i2c_delay(usecs) udelay(usecs) static DEFINE_SPINLOCK(i2c_lock); /* Protect directions etc */ /****************** VARIABLE SECTION ************************************/ static struct crisv32_iopin cris_i2c_clk; Loading Loading @@ -252,6 +254,7 @@ i2c_getack(void) * generate ACK clock pulse */ i2c_clk(I2C_CLOCK_HIGH); #if 0 /* * Use PORT PB instead of I2C * for input. (I2C not working) Loading @@ -264,6 +267,8 @@ i2c_getack(void) i2c_data(1); i2c_disable(); i2c_dir_in(); #endif /* * now wait for ack */ Loading @@ -275,7 +280,7 @@ i2c_getack(void) ack = 0; i2c_delay(CLOCK_HIGH_TIME/2); if (!ack) { if(!i2c_getbit()) /* receiver pulled SDA low */ if (!i2c_getbit()) /* receiver pulld SDA low */ ack = 1; i2c_delay(CLOCK_HIGH_TIME/2); } Loading @@ -285,6 +290,7 @@ i2c_getack(void) * before we enable our output. If we keep data high * and enable output, we would generate a stop condition. */ #if 0 i2c_data(I2C_DATA_LOW); /* Loading @@ -292,6 +298,7 @@ i2c_getack(void) */ i2c_enable(); i2c_dir_out(); #endif i2c_clk(I2C_CLOCK_LOW); i2c_delay(CLOCK_HIGH_TIME/4); /* Loading Loading @@ -373,6 +380,137 @@ i2c_sendnack(void) i2c_dir_in(); } /*#--------------------------------------------------------------------------- *# *# FUNCTION NAME: i2c_write *# *# DESCRIPTION : Writes a value to an I2C device *# *#--------------------------------------------------------------------------*/ int i2c_write(unsigned char theSlave, void *data, size_t nbytes) { int error, cntr = 3; unsigned char bytes_wrote = 0; unsigned char value; unsigned long flags; spin_lock(&i2c_lock); do { error = 0; /* * we don't like to be interrupted */ local_irq_save(flags); i2c_start(); /* * send slave address */ i2c_outbyte((theSlave & 0xfe)); /* * wait for ack */ if (!i2c_getack()) error = 1; /* * send data */ for (bytes_wrote = 0; bytes_wrote < nbytes; bytes_wrote++) { memcpy(&value, data + bytes_wrote, sizeof value); i2c_outbyte(value); /* * now it's time to wait for ack */ if (!i2c_getack()) error |= 4; } /* * end byte stream */ i2c_stop(); /* * enable interrupt again */ local_irq_restore(flags); } while (error && cntr--); i2c_delay(CLOCK_LOW_TIME); spin_unlock(&i2c_lock); return -error; } /*#--------------------------------------------------------------------------- *# *# FUNCTION NAME: i2c_read *# *# DESCRIPTION : Reads a value from an I2C device *# *#--------------------------------------------------------------------------*/ int i2c_read(unsigned char theSlave, void *data, size_t nbytes) { unsigned char b = 0; unsigned char bytes_read = 0; int error, cntr = 3; unsigned long flags; spin_lock(&i2c_lock); do { error = 0; memset(data, 0, nbytes); /* * we don't like to be interrupted */ local_irq_save(flags); /* * generate start condition */ i2c_start(); /* * send slave address */ i2c_outbyte((theSlave | 0x01)); /* * wait for ack */ if (!i2c_getack()) error = 1; /* * fetch data */ for (bytes_read = 0; bytes_read < nbytes; bytes_read++) { b = i2c_inbyte(); memcpy(data + bytes_read, &b, sizeof b); if (bytes_read < (nbytes - 1)) i2c_sendack(); } /* * last received byte needs to be nacked * instead of acked */ i2c_sendnack(); /* * end sequence */ i2c_stop(); /* * enable interrupt again */ local_irq_restore(flags); } while (error && cntr--); spin_unlock(&i2c_lock); return -error; } /*#--------------------------------------------------------------------------- *# *# FUNCTION NAME: i2c_writereg Loading @@ -387,6 +525,8 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, int error, cntr = 3; unsigned long flags; spin_lock(&i2c_lock); do { error = 0; /* Loading Loading @@ -431,11 +571,12 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, * enable interrupt again */ local_irq_restore(flags); } while(error && cntr--); i2c_delay(CLOCK_LOW_TIME); spin_unlock(&i2c_lock); return -error; } Loading @@ -453,6 +594,8 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) int error, cntr = 3; unsigned long flags; spin_lock(&i2c_lock); do { error = 0; /* Loading Loading @@ -482,7 +625,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) * now it's time to wait for ack */ if(!i2c_getack()) error = 1; error |= 2; /* * repeat start condition */ Loading @@ -496,7 +639,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) * wait for ack */ if(!i2c_getack()) error = 1; error |= 4; /* * fetch register */ Loading @@ -517,6 +660,8 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) } while(error && cntr--); spin_unlock(&i2c_lock); return b; } Loading Loading @@ -583,12 +728,37 @@ static const struct file_operations i2c_fops = { int __init i2c_init(void) { int res; static int res; static int first = 1; if (!first) return res; /* Setup and enable the Port B I2C interface */ first = 0; crisv32_io_get_name(&cris_i2c_data, CONFIG_ETRAX_I2C_DATA_PORT); crisv32_io_get_name(&cris_i2c_clk, CONFIG_ETRAX_I2C_CLK_PORT); /* Setup and enable the DATA and CLK pins */ res = crisv32_io_get_name(&cris_i2c_data, CONFIG_ETRAX_V32_I2C_DATA_PORT); if (res < 0) return res; res = crisv32_io_get_name(&cris_i2c_clk, CONFIG_ETRAX_V32_I2C_CLK_PORT); crisv32_io_set_dir(&cris_i2c_clk, crisv32_io_dir_out); return res; } int __init i2c_register(void) { int res; res = i2c_init(); if (res < 0) return res; /* register char device */ Loading @@ -598,13 +768,14 @@ i2c_init(void) 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-2007 Axis Communications AB\n"); return 0; } /* this makes sure that i2c_init is called during boot */ module_init(i2c_init); module_init(i2c_register); /****************** END OF FILE i2c.c ********************************/
arch/cris/arch-v32/drivers/i2c.h +2 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,8 @@ /* High level I2C actions */ int __init i2c_init(void); int i2c_write(unsigned char theSlave, void *data, size_t nbytes); int i2c_read(unsigned char theSlave, void *data, size_t nbytes); int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg); Loading