/* i2c_write_byte Write a byte to I2C bus => byte = data to write out <= return 0 if acknowleged by the slave */ unsigned char i2c_write_byte(unsigned char byte) { unsigned char loop, ack, original_byte = byte; /* send data, msb first */ for(loop = 0; loop < 8; loop++) { if(byte & 0x80) i2c_set_sda(); else i2c_clear_sda(); i2c_set_scl(); i2c_delay(); i2c_clear_scl(); byte = byte << 1; } /* read ack bit from slave */ i2c_set_sda(); i2c_set_scl(); i2c_delay(); ack = i2c_read_sda(); i2c_clear_scl(); return ack; }
/*#--------------------------------------------------------------------------- *# *# FUNCTION NAME: i2c_start *# *# DESCRIPTION : generate i2c start condition *# *# PARAMETERS : none *# *# RETURN : EI2CNOERRORS if OK, EI2CSTRTCOND otherwise *# *#--------------------------------------------------------------------------- */ int i2c_start( void ) { /* Set SCL=1, SDA=1 */ i2c_sda_dir_out(); i2c_set_sda( SDA_HIGH ); i2c_delay( WAITONEUS ); i2c_set_scl( SCL_HIGH ); i2c_delay( WAITONEUS ); /* Set SCL=1, SDA=0 */ i2c_set_sda( SDA_LOW ); i2c_delay( THDSTA ); /* Set SCL=0, SDA=0 */ i2c_set_scl( SCL_LOW ); /* We can take 1 us less than defined in spec (5 us), since the next action * will be to set the dataline high or low and this action is 1 us * before the clock is put high, so that makes our 5 us. */ i2c_delay( TLOW - WAITONEUS ); if ( i2c_sda_is_high() || i2c_scl_is_high() ) { printk( KERN_DEBUG "I2C: EI2CSTRTCOND\n" ); return ( EI2CSTRTCOND ); } return ( EI2CNOERRORS ); } /* i2c_start */
/* i2c_read_byte Read a byte from I2C bus => ack = acknowlege bit to send after read <= returns data read from the bus */ unsigned char i2c_read_byte(unsigned char ack) { unsigned char loop, byte; i2c_set_sda(); /* read data msb first */ for(loop = 0; loop < 8; loop++) { byte = byte << 1; i2c_set_scl(); i2c_delay(); if(i2c_read_sda()) byte = byte | 1; i2c_clear_scl(); } /* send ack bit */ if(ack) i2c_set_sda(); else i2c_clear_sda(); i2c_set_scl(); i2c_delay(); i2c_clear_scl(); i2c_set_sda(); return byte; }
/*#--------------------------------------------------------------------------- *# *# FUNCTION NAME: i2c_inbyte *# *# DESCRIPTION : read a byte from the i2c interface *# *# PARAMETERS : none *# *# RETURN : returns the byte read from the I2C device *# *#--------------------------------------------------------------------------- */ unsigned char i2c_inbyte( void ) { #ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY int n=MAXSCLRETRIES; #endif unsigned char aBitByte = 0; unsigned char Mask = 0x80; /* !!! ATTENTION: do NOT use 'char', otherwise shifting is wrong!!! */ /* Must be UNSIGNED, not SIGNED! */ /* Switch off I2C to get bit */ i2c_disable(); i2c_sda_dir_in(); while ( Mask != 0 ) { #ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY i2c_scl_dir_in(); for( ; n>0; n-- ) { if( i2c_scl_is_high() ) break; i2c_delay( THIGH ); } i2c_set_scl( SCL_HIGH ); i2c_scl_dir_out(); #else i2c_set_scl( SCL_HIGH ); #endif i2c_delay( THIGH ); if ( i2c_sda_is_high() ) { aBitByte |= Mask; } i2c_set_scl( SCL_LOW ); Mask >>= 1; i2c_delay( TLOW ); } /* * we leave the clock low, getbyte is usually followed * by sendack/nack, they assume the clock to be low */ return ( aBitByte ); } /* i2c_inbyte */
/*#--------------------------------------------------------------------------- *# *# FUNCTION NAME: i2c_sendnack *# *# DESCRIPTION : sends NACK on received data *# *# PARAMETERS : none *# *# RETURN : none *# *#--------------------------------------------------------------------------- */ void i2c_sendnack( void ) { #ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY int n=MAXSCLRETRIES; #endif /* make sure the SDA line is set high prior to activation of the output. * this way, you avoid an unnecessary peak to ground when a NACK has to * be created. */ /* set data high */ i2c_set_sda( SDA_HIGH ); /* enable output */ i2c_sda_dir_out(); /* generate clock pulse */ i2c_delay( TSUDAT ); #ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY i2c_scl_dir_in(); /* wait for clock to rise (n=MAXSCLRETRIES) */ for( ; n>0; n-- ) { if( i2c_scl_is_high() ) break; i2c_delay( THIGH ); } i2c_set_scl( SCL_HIGH ); i2c_scl_dir_out(); i2c_delay( THIGH ); #else i2c_set_scl( SCL_HIGH ); i2c_delay( THIGH ); #endif i2c_set_scl( SCL_LOW ); i2c_delay( TSUDAT ); i2c_set_sda( SDA_LOW ); i2c_delay( TLOW - TSUDAT ); /* There's no need to change the direction of SDA to "in" again, * since a NACK is always followed by a stop condition. * A STOP condition will put the direction of SDA back to "out" * resulting in a useless SDA "dip" on the line... */ /* i2c_sda_dir_in(); */ } /* i2c_sendnack */
/*#--------------------------------------------------------------------------- *# *# FUNCTION NAME: i2c_bus_free_check *# *# DESCRIPTION : checks if the I2C bus is free before starting *# an I2C communication *# *# PARAMETERS : maxretries, the number of times we will try to release *# the I2C bus *# *# RETURN : I2cStatus_I2cBusNotFreeError in case the bus is not free, *# I2cStatus_I2cNoError otherwise *# *#--------------------------------------------------------------------------- */ static int i2c_bus_free_check( unsigned char maxretries ) { i2c_sda_dir_in(); /* Release SDA line */ i2c_set_scl( SCL_HIGH ); /* put SCL line high */ i2c_delay( WAITONEUS ); while ( ( !i2c_sda_is_high() || !i2c_scl_is_high() ) &&( maxretries-- ) ) { /* Try to release I2C bus by generating STOP conditions */ i2c_stop(); } if ( 0 == maxretries ) { printk( KERN_DEBUG "I2C: EI2CBUSNFREE\n" ); return ( EI2CBUSNFREE ); } else { return ( EI2CNOERRORS ); } } /* i2c_bus_free_check */
int i2c_wait_nack() { i2c_clr_scl(); i2c_set_sda(); i2c_set_scl(); while(i2c_get_scl() == 0); /* wait for scl = 1 (clock stretching) */ return (i2c_get_sda() == 1); }
/*#--------------------------------------------------------------------------- *# *# FUNCTION NAME: i2c_stop *# *# DESCRIPTION : generate i2c stop condition *# *# PARAMETERS : none *# *# RETURN : none *# *#--------------------------------------------------------------------------- */ int i2c_stop( void ) { #ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY int n=MAXSCLRETRIES; #endif i2c_sda_dir_out(); /* Set SCL=0, SDA=0 */ /* Don't change order, otherwise you might generate a start condition! */ i2c_set_scl( SCL_LOW ); i2c_delay( WAITONEUS ); i2c_set_sda( SDA_LOW ); i2c_delay( WAITONEUS ); /* Set SCL=1, SDA=0 */ #ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY i2c_set_scl( SCL_HIGH ); i2c_scl_dir_in(); for( ; n>0; n-- ) { if( i2c_scl_is_high() ) break; i2c_delay( TSUSTO ); } i2c_scl_dir_out(); #else i2c_set_scl( SCL_HIGH ); #endif i2c_delay( TSUSTO ); /* Set SCL=1, SDA=1 */ i2c_set_sda( SDA_HIGH ); i2c_delay( TBUF ); i2c_sda_dir_in(); if ( !i2c_sda_is_high() || !i2c_scl_is_high() ) { return ( EI2CSTOPCOND ); } return ( EI2CNOERRORS ); } /* i2c_stop */
void i2c_stop_condition() { i2c_clr_scl(); i2c_clr_sda(); while(i2c_get_sda() == 1); /* wait for SDA = 0 */ i2c_set_scl(); while(i2c_get_scl() == 0); /* wait for SCL = 1 */ i2c_set_sda(); while(i2c_get_sda() == 0); /* wait for SDA = 1 */ }
/*#--------------------------------------------------------------------------- *# *# FUNCTION NAME: i2c_outbyte *# *# DESCRIPTION : write a byte to the i2c interface *# *# PARAMETERS : x: byte to be sent on the I2C bus *# *# RETURN : none *# *#--------------------------------------------------------------------------- */ int i2c_outbyte( unsigned char x ) { int i; i2c_sda_dir_out(); for ( i = 0; i < 8; i++ ) { if ( x & 0x80 ) { i2c_set_sda( SDA_HIGH ); } else { i2c_set_sda( SDA_LOW ); } i2c_delay( TSUDAT ); i2c_set_scl( SCL_HIGH ); i2c_delay( THIGH ); i2c_set_scl( SCL_LOW ); i2c_delay( TSUDAT ); i2c_set_sda( SDA_LOW ); /* There should be only 5 us between falling edge and new rising * edge of clock pulse. * Since we spend already 1 us since clock edge was low, there are * only ( TLOW - TSUDAT ) us left. * Next to this, since the data line will be set up 1 us before the * clock line is set up, we can reduce the delay with another us. */ i2c_delay( TLOW - TSUDAT - WAITONEUS ); x <<= 1; } /* enable input */ i2c_sda_dir_in(); if ( !i2c_getack() ) { return( EI2CNOACKNLD ); } return ( EI2CNOERRORS ); } /* i2c_outbyte */
/*#--------------------------------------------------------------------------- *# *# FUNCTION NAME: i2c_sendack *# *# DESCRIPTION : sends ACK on received data *# *# PARAMETERS : none *# *# RETURN : none *# *#--------------------------------------------------------------------------- */ void i2c_sendack( void ) { #ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY int n=MAXSCLRETRIES; #endif /* enable output */ /* Clock has been set to TLOW already at end of i2c_inbyte() * and i2c_outbyte(), so no need to do it again. */ i2c_sda_dir_out(); /* set ack pulse low */ i2c_set_sda( SDA_LOW ); /* generate clock pulse */ i2c_delay( TSUDAT ); #ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY i2c_scl_dir_in(); /* wait for clock to rise (n=MAXSCLRETRIES) */ for( ; n>0; n-- ) { if( i2c_scl_is_high() ) break; i2c_delay( THIGH ); } i2c_set_scl( SCL_HIGH ); i2c_scl_dir_out(); i2c_delay( THIGH ); #else i2c_set_scl( SCL_HIGH ); i2c_delay( THIGH ); #endif i2c_set_scl( SCL_LOW ); i2c_delay( THDDAT ); /* reset data out */ i2c_set_sda( SDA_HIGH ); /* Subtract time spend already when waited to put SDA high */ i2c_delay( TLOW - THDDAT ); /* release the SDA line */ i2c_sda_dir_in(); } /* i2c_sendack */
void i2c_send_char(unsigned char data) { unsigned char mask = 0x80; int i, x; for(i=0;i<8;++i) { x = (data & mask); i2c_clr_scl(); if(x) i2c_set_sda(); else i2c_clr_sda(); i2c_set_scl(); mask >>= 1; } }
char i2c_read_char() { int i; char acc = 0; i2c_clr_scl(); i2c_set_sda(); for(i=0;i<8;++i) { i2c_clr_scl(); i2c_set_scl(); acc = (acc << 1) | i2c_get_sda(); } return acc; }
void i2c_send_stop(void) { /* set SDA to 0 */ i2c_clear_sda(); i2c_delay(); /* bring the clock line high */ i2c_set_scl(); i2c_delay(); /* and set SDA back to 1 */ i2c_set_sda(); i2c_delay(); }
void i2c_send_start(void) { /* take data and clock high, then toggle */ i2c_set_sda(); i2c_delay(); i2c_set_scl(); i2c_delay(); i2c_clear_sda(); i2c_delay(); i2c_clear_scl(); i2c_delay(); }
void s_transstart(void) //---------------------------------------------------------------------------------- // generates a transmission start // _____ ________ // I2CDAT: |_______| // ___ ___ // I2C_SCL : ___| |___| |______ { i2c_set_sda(1); i2c_set_scl(1); i2c_set_sda(0); i2c_set_scl(0); i2c_set_scl(0); i2c_set_scl(1); i2c_set_sda(1); i2c_set_scl(0); i2c_set_scl(0); if(i2c_test_sda() == 0) hmioerr++; }
/*#--------------------------------------------------------------------------- *# *# FUNCTION NAME: i2c_getack *# *# DESCRIPTION : checks if ack was received from ic2 *# *# PARAMETERS : none *# *# RETURN : returns the ack state of the I2C device *# *#--------------------------------------------------------------------------- */ int i2c_getack( void ) { int ack = 1; #ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY int n=MAXSCLRETRIES; #endif /* generate ACK clock pulse */ i2c_set_scl( SCL_HIGH ); /* switch off I2C */ i2c_disable(); #ifdef CONFIG_ETRAX_I2C_SLAVE_DELAY /* set clock low */ i2c_set_scl( SCL_LOW ); /* now wait for ack */ i2c_delay( THIGH ); /* set clock as input */ i2c_scl_dir_in(); /* wait for clock to rise (n=MAXSCLRETRIES) */ for( ; n>0; n-- ) { if( i2c_scl_is_high() ) break; i2c_delay( THIGH ); } i2c_set_scl( SCL_HIGH ); i2c_scl_dir_out(); i2c_delay( THIGH ); #else /* now wait for ack */ i2c_delay( THIGH ); #endif /* check for ack: if SDA is high, then NACK, else ACK */ if ( i2c_sda_is_high() ) { ack = 0; } else { ack = 1; } /* end clock pulse */ i2c_enable(); i2c_set_scl( SCL_LOW ); i2c_sda_dir_out(); i2c_set_sda( SDA_LOW ); /* Since we "lost" already THDDAT time, we can subtract it here... */ i2c_delay( TLOW - THDDAT ); return ( ack ); } /* i2c_getack */
void i2c_send_nack() { i2c_clr_scl(); i2c_set_sda(); i2c_set_scl(); }