예제 #1
0
파일: i2c-octeon.c 프로젝트: xtra72/s805
/**
 * 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;
}
예제 #2
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;
}