in platform/innovium/sonic-platform-modules-cel/midstone-200i/modules/200i_cpld.c [453:710]
static int ms200i_i2c_access(struct i2c_adapter *a, u16 addr,
unsigned short flags, char rw, u8 cmd,
int size, union i2c_smbus_data *data)
{
int error = 0;
struct ms200i_i2c_data *new_data;
mutex_lock(&cpld_data->cpld_lock);
/* Write the command register */
new_data = i2c_get_adapdata(a);
unsigned int portid = new_data->portid;
#ifdef DEBUG_KERN
printk(KERN_INFO "portid %2d|@ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-10s|CMD %2.2X |DAT %4.4X"
,portid,addr,flags,rw,rw == 1 ? "READ ":"WRITE"
,size, size == 0 ? "QUICK" :
size == 1 ? "BYTE" :
size == 2 ? "BYTE_DATA" :
size == 3 ? "WORD_DATA" :
size == 4 ? "PROC_CALL" :
size == 5 ? "BLOCK_DATA" : "ERROR"
,cmd,data->word);
#endif
/* Map the size to what the chip understands */
switch (size) {
case I2C_SMBUS_QUICK:
case I2C_SMBUS_BYTE:
case I2C_SMBUS_BYTE_DATA:
case I2C_SMBUS_WORD_DATA:
case I2C_SMBUS_BLOCK_DATA:
break;
default:
printk(KERN_INFO "Unsupported transaction %d\n", size);
error = -EOPNOTSUPP;
goto Done;
}
unsigned int REG_FDR0;
unsigned int REG_CR0;
unsigned int REG_SR0;
unsigned int REG_DR0;
unsigned int REG_ID0;
REG_FDR0 = new_data->REG_FDR0;
REG_CR0 = new_data->REG_CR0;
REG_SR0 = new_data->REG_SR0;
REG_DR0 = new_data->REG_DR0;
REG_ID0 = new_data->REG_ID0;
outb(portid,REG_ID0);
int timeout=0;
int cnt=0;
////[S][ADDR/R]
//Clear status register
outb( 0 , REG_SR0);
outb( 1 << I2C_CR_BIT_MIEN | 1 << I2C_CR_BIT_MTX | 1 << I2C_CR_BIT_MSTA ,REG_CR0);
SET_REG_BIT_H(REG_CR0,I2C_CR_BIT_MEN);
if(rw == I2C_SMBUS_READ &&
(size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)){
// sent device address with Read mode
outb(addr << 1 | 0x01,REG_DR0);
}else{
// sent device address with Write mode
outb(addr << 1 | 0x00,REG_DR0);
}
info( "MS Start");
//// Wait {A}
error = i2c_wait_ack(a,50000,1);
if(error<0){
info( "get error %d",error);
goto Done;
}
//// [CMD]{A}
if(size == I2C_SMBUS_BYTE_DATA ||
size == I2C_SMBUS_WORD_DATA ||
size == I2C_SMBUS_BLOCK_DATA ||
(size == I2C_SMBUS_BYTE && rw == I2C_SMBUS_WRITE)){
//sent command code to data register
outb(cmd,REG_DR0);
info( "MS Send CMD 0x%2.2X",cmd);
// Wait {A}
error = i2c_wait_ack(a,50000,1);
if(error<0){
info( "get error %d",error);
goto Done;
}
}
switch(size){
case I2C_SMBUS_BYTE_DATA:
cnt = 1; break;
case I2C_SMBUS_WORD_DATA:
cnt = 2; break;
case I2C_SMBUS_BLOCK_DATA:
// in block data mode keep number of byte in block[0]
cnt = data->block[0];
break;
default:
cnt = 0; break;
}
// [CNT] used only bloack data write
if(size == I2C_SMBUS_BLOCK_DATA && rw == I2C_SMBUS_WRITE){
outb(cnt,REG_DR0);
info( "MS Send CNT 0x%2.2X",cnt);
// Wait {A}
error = i2c_wait_ack(a,50000,1);
if(error<0){
info( "get error %d",error);
goto Done;
}
}
// [DATA]{A}
if( rw == I2C_SMBUS_WRITE && (
size == I2C_SMBUS_BYTE ||
size == I2C_SMBUS_BYTE_DATA ||
size == I2C_SMBUS_WORD_DATA ||
size == I2C_SMBUS_BLOCK_DATA
)){
int bid=0;
info( "MS prepare to sent [%d bytes]",cnt);
if(size == I2C_SMBUS_BLOCK_DATA ){
bid=1; // block[0] is cnt;
cnt+=1; // offset from block[0]
}
for(;bid<cnt;bid++){
outb(data->block[bid],REG_DR0);
info( " Data > %2.2X",data->block[bid]);
// Wait {A}
error = i2c_wait_ack(a,50000,1);
if(error<0){
goto Done;
}
}
}
//REPEATE START
if( rw == I2C_SMBUS_READ && (
size == I2C_SMBUS_BYTE_DATA ||
size == I2C_SMBUS_WORD_DATA ||
size == I2C_SMBUS_BLOCK_DATA
)){
info( "MS Repeated Start");
SET_REG_BIT_L(REG_CR0,I2C_CR_BIT_MEN);
outb(1 << I2C_CR_BIT_MIEN |
1 << I2C_CR_BIT_MTX |
1 << I2C_CR_BIT_MSTA |
1 << I2C_CR_BIT_RSTA ,REG_CR0);
SET_REG_BIT_H(REG_CR0,I2C_CR_BIT_MEN);
// sent Address with Read mode
outb( addr<<1 | 0x1 ,REG_DR0);
// Wait {A}
error = i2c_wait_ack(a,50000,1);
if(error<0){
goto Done;
}
}
if( rw == I2C_SMBUS_READ && (
size == I2C_SMBUS_BYTE ||
size == I2C_SMBUS_BYTE_DATA ||
size == I2C_SMBUS_WORD_DATA ||
size == I2C_SMBUS_BLOCK_DATA
)){
switch(size){
case I2C_SMBUS_BYTE:
case I2C_SMBUS_BYTE_DATA:
cnt = 1; break;
case I2C_SMBUS_WORD_DATA:
cnt = 2; break;
case I2C_SMBUS_BLOCK_DATA:
//will be changed after recived first data
cnt = 3; break;
default:
cnt = 0; break;
}
int bid = 0;
info( "MS Receive");
//set to Receive mode
outb(1 << I2C_CR_BIT_MEN |
1 << I2C_CR_BIT_MIEN |
1 << I2C_CR_BIT_MSTA , REG_CR0);
for(bid=-1;bid<cnt;bid++){
// Wait {A}
error = i2c_wait_ack(a,50000,0);
if(error<0){
goto Done;
}
if(bid == cnt-2){
info( "SET NAK");
SET_REG_BIT_H(REG_CR0,I2C_CR_BIT_TXAK);
}
if(bid<0){
inb(REG_DR0);
info( "READ Dummy Byte" );
}else{
if(bid==cnt-1){
info ( "SET STOP in read loop");
SET_REG_BIT_L(REG_CR0,I2C_CR_BIT_MSTA);
}
data->block[bid] = inb(REG_DR0);
info( "DATA IN [%d] %2.2X",bid,data->block[bid]);
if(size==I2C_SMBUS_BLOCK_DATA && bid == 0){
cnt = data->block[0] + 1;
}
}
}
}
Stop:
//[P]
SET_REG_BIT_L(REG_CR0,I2C_CR_BIT_MSTA);
info( "MS STOP");
Done:
outb(1<<I2C_CR_BIT_MEN,REG_CR0);
check(REG_CR0);
check(REG_SR0);
#ifdef DEBUG_KERN
printk(KERN_INFO "END --- Error code %d",error);
#endif
mutex_unlock(&cpld_data->cpld_lock);
return error;
}