/** * octeon_i2c_start - send START to the bus. * @i2c: The struct octeon_i2c. * * Returns 0 on success, otherwise a negative errno. */ static int octeon_i2c_start(struct octeon_i2c *i2c) { u8 data; int result; octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB | TWSI_CTL_STA); result = octeon_i2c_wait(i2c); if (result) { if (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT) == STAT_IDLE) { /* * Controller refused to send start flag May * be a client is holding SDA low - let's try * to free it. */ octeon_i2c_unblock(i2c); octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB | TWSI_CTL_STA); result = octeon_i2c_wait(i2c); } if (result) return result; } data = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT); if ((data != STAT_START) && (data != STAT_RSTART)) { dev_err(i2c->dev, "%s: bad status (0x%x)\n", __func__, data); return -EIO; } return 0; }
int i2c_master_write(int len, void *buf) { unsigned char data = 0; unsigned char status = 0; unsigned char *ptr = (unsigned char *) buf; int i =0; int ret = 0; int count = 0; twsi_core_write_reg(TWSI_CTL, TWSI_CORE_CTL_ENAB | TWSI_CORE_CTL_STA); // wait for status for( count=5000; !(twsi_core_read_reg(TWSI_CTL) & TWSI_CORE_CTL_IFLG); count-- ){ if( !count ){ if( getenv("ipmi_debug") ){ printf("%s: send start timeout \n",__FUNCTION__); } // controller may block when send STP // tyr to unlock it octeon_i2c_unblock(); return -1; } udelay(100); } // check status // 0x8: start transmitted // 0x10: repeated start transmitted status = twsi_core_read_reg(TWSI_STAT); if( status != 0x8 && status != 0x10 ){ if( getenv("ipmi_debug") ){ printf("%s: send start error 0x%02x\n",__FUNCTION__, status ); } if( status == 0x00 ) { // bus error twsi_core_write_reg(TWSI_CTL, TWSI_CORE_CTL_ENAB | TWSI_CORE_CTL_STP); udelay(2000); // clear iflag twsi_core_write_reg(TWSI_CTL, TWSI_CORE_CTL_ENAB); } else{ // stop this transaction twsi_core_write_reg(TWSI_CTL, TWSI_CORE_CTL_ENAB | TWSI_CORE_CTL_STP); udelay(2000); // clear iflag twsi_core_write_reg(TWSI_CTL, TWSI_CORE_CTL_ENAB); } return -1; } for( i=0; i<len; i++){ // write data twsi_core_write_reg(TWSI_DATA, ptr[i]); // start transmmit data twsi_core_write_reg(TWSI_CTL, TWSI_CORE_CTL_ENAB ); // wait for status for( count=500; !(twsi_core_read_reg(TWSI_CTL) & TWSI_CORE_CTL_IFLG); count-- ){ if( !count ){ if( getenv("ipmi_debug") ){ printf("%s: send data timeout \n",__FUNCTION__); } ret = -1; goto _exit; } udelay(100); } // check status status = twsi_core_read_reg(TWSI_STAT); switch( status){ case 0x28: case 0x18: continue; case 0x30: // nack case 0x20: // nack case 0x38: // arbitration lost udelay(2000); ret = -1; goto _exit; case 0x00: ret = -1; goto _exit; default: if( getenv("ipmi_debug") ){ printf("%s: send data error 0x%02x\n",__FUNCTION__, status ); } ret = -1; goto _exit; } } ret = i; _exit: // clear IFLG anyway //twsi_core_write_reg(TWSI_CTL, TWSI_CORE_CTL_ENAB ); //udelay(500); twsi_core_write_reg(TWSI_CTL, TWSI_CORE_CTL_ENAB | TWSI_CORE_CTL_STP); udelay(500); return ret; }