in platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switchboard.c [1188:1443]
static int smbus_access(struct i2c_adapter *adapter, u16 addr,
unsigned short flags, char rw, u8 cmd,
int size, union i2c_smbus_data *data)
{
int error = 0;
int cnt = 0;
int bid = 0;
struct i2c_dev_data *dev_data;
void __iomem *pci_bar;
unsigned int portid, master_bus;
unsigned int REG_FDR0;
unsigned int REG_CR0;
unsigned int REG_SR0;
unsigned int REG_DR0;
unsigned int REG_ID0;
/* Write the command register */
dev_data = i2c_get_adapdata(adapter);
portid = dev_data->portid;
pci_bar = fpga_dev.data_base_addr;
master_bus = dev_data->pca9548.master_bus;
REG_FDR0 = I2C_MASTER_FREQ_1 + (master_bus - 1) * 0x0100;
REG_CR0 = I2C_MASTER_CTRL_1 + (master_bus - 1) * 0x0100;
REG_SR0 = I2C_MASTER_STATUS_1 + (master_bus - 1) * 0x0100;
REG_DR0 = I2C_MASTER_DATA_1 + (master_bus - 1) * 0x0100;
REG_ID0 = I2C_MASTER_PORT_ID_1 + (master_bus - 1) * 0x0100;
if (master_bus < I2C_MASTER_CH_1 || master_bus > I2C_MASTER_CH_TOTAL) {
error = -EINVAL;
goto Done;
}
#ifdef DEBUG_KERN
printk(KERN_INFO "portid %2d|@ 0x%2.2X|f 0x%4.4X|(%d)%-5s| (%d)%-10s|CMD %2.2X "
, 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);
#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;
}
iowrite8(portid, pci_bar + REG_ID0);
////[S][ADDR/R]
//Clear status register
iowrite8(0, pci_bar + REG_SR0);
iowrite8(1 << I2C_CR_BIT_MIEN | 1 << I2C_CR_BIT_MTX | 1 << I2C_CR_BIT_MSTA , pci_bar + REG_CR0);
SET_REG_BIT_H(pci_bar + 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
iowrite8(addr << 1 | 0x01, pci_bar + REG_DR0);
} else {
// sent device address with Write mode
iowrite8(addr << 1 | 0x00, pci_bar + REG_DR0);
}
info( "MS Start");
//// Wait {A}
error = i2c_wait_ack(adapter, 12, 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
iowrite8(cmd, pci_bar + REG_DR0);
info( "MS Send CMD 0x%2.2X", cmd);
// Wait {A}
error = i2c_wait_ack(adapter, 12, 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) {
iowrite8(cnt, pci_bar + REG_DR0);
info( "MS Send CNT 0x%2.2X", cnt);
// Wait {A}
error = i2c_wait_ack(adapter, 12, 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++) {
iowrite8(data->block[bid], pci_bar + REG_DR0);
info( " Data > %2.2X", data->block[bid]);
// Wait {A}
error = i2c_wait_ack(adapter, 12, 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(pci_bar + REG_CR0, I2C_CR_BIT_MEN);
iowrite8(1 << I2C_CR_BIT_MIEN |
1 << I2C_CR_BIT_MTX |
1 << I2C_CR_BIT_MSTA |
1 << I2C_CR_BIT_RSTA , pci_bar + REG_CR0);
SET_REG_BIT_H(pci_bar + REG_CR0, I2C_CR_BIT_MEN);
// sent Address with Read mode
iowrite8( addr << 1 | 0x1 , pci_bar + REG_DR0);
// Wait {A}
error = i2c_wait_ack(adapter, 12, 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;
}
info( "MS Receive");
//set to Receive mode
iowrite8(1 << I2C_CR_BIT_MEN |
1 << I2C_CR_BIT_MIEN |
1 << I2C_CR_BIT_MSTA , pci_bar + REG_CR0);
for (bid = -1; bid < cnt; bid++) {
// Wait {A}
error = i2c_wait_ack(adapter, 12, 0);
if (error < 0) {
goto Done;
}
if (bid == cnt - 2) {
info( "SET NAK");
SET_REG_BIT_H(pci_bar + REG_CR0, I2C_CR_BIT_TXAK);
}
if (bid < 0) {
ioread8(pci_bar + REG_DR0);
info( "READ Dummy Byte" );
} else {
if (bid == cnt - 1) {
info ( "SET STOP in read loop");
SET_REG_BIT_L(pci_bar + REG_CR0, I2C_CR_BIT_MSTA);
}
data->block[bid] = ioread8(pci_bar + 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;
}
}
}
}
//[P]
SET_REG_BIT_L(pci_bar + REG_CR0, I2C_CR_BIT_MSTA);
i2c_wait_ack(adapter, 12, 0);
info( "MS STOP");
Done:
iowrite8(1 << I2C_CR_BIT_MEN, pci_bar + REG_CR0);
check(pci_bar + REG_CR0);
check(pci_bar + REG_SR0);
#ifdef DEBUG_KERN
printk(KERN_INFO "END --- Error code %d", error);
#endif
return error;
}