static int smbus_access()

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;
}