in busses/i2c-npcm7xx.c [1038:1235]
static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus)
{
u8 val;
irqreturn_t ret = IRQ_NONE;
u8 i2cst = ioread8(bus->reg + NPCM_I2CST);
/* Slave: A NACK has occurred */
if (NPCM_I2CST_NEGACK & i2cst) {
bus->stop_ind = I2C_NACK_IND;
npcm_i2c_slave_wr_buf_sync(bus);
if (bus->fifo_use)
/* clear the FIFO */
iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO,
bus->reg + NPCM_I2CFIF_CTS);
/* In slave write, NACK is OK, otherwise it is a problem */
bus->stop_ind = I2C_NO_STATUS_IND;
bus->operation = I2C_NO_OPER;
bus->own_slave_addr = 0xFF;
/*
* Slave has to wait for STOP to decide this is the end
* of the transaction. tx is not yet considered as done
*/
iowrite8(NPCM_I2CST_NEGACK, bus->reg + NPCM_I2CST);
ret = IRQ_HANDLED;
}
/* Slave mode: a Bus Error (BER) has been identified */
if (NPCM_I2CST_BER & i2cst) {
/*
* Check whether bus arbitration or Start or Stop during data
* xfer bus arbitration problem should not result in recovery
*/
bus->stop_ind = I2C_BUS_ERR_IND;
/* wait for bus busy before clear fifo */
iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO, bus->reg + NPCM_I2CFIF_CTS);
bus->state = I2C_IDLE;
/*
* in BER case we might get 2 interrupts: one for slave one for
* master ( for a channel which is master\slave switching)
*/
if (completion_done(&bus->cmd_complete) == false) {
bus->cmd_err = -EIO;
complete(&bus->cmd_complete);
}
bus->own_slave_addr = 0xFF;
iowrite8(NPCM_I2CST_BER, bus->reg + NPCM_I2CST);
ret = IRQ_HANDLED;
}
/* A Slave Stop Condition has been identified */
if (NPCM_I2CST_SLVSTP & i2cst) {
u8 bytes_in_fifo = npcm_i2c_fifo_usage(bus);
bus->stop_ind = I2C_SLAVE_DONE_IND;
if (bus->operation == I2C_READ_OPER)
npcm_i2c_read_fifo_slave(bus, bytes_in_fifo);
/* if the buffer is empty nothing will be sent */
npcm_i2c_slave_send_rd_buf(bus);
/* Slave done transmitting or receiving */
bus->stop_ind = I2C_NO_STATUS_IND;
/*
* Note, just because we got here, it doesn't mean we through
* away the wr buffer.
* we keep it until the next received offset.
*/
bus->operation = I2C_NO_OPER;
bus->own_slave_addr = 0xFF;
i2c_slave_event(bus->slave, I2C_SLAVE_STOP, 0);
iowrite8(NPCM_I2CST_SLVSTP, bus->reg + NPCM_I2CST);
if (bus->fifo_use) {
npcm_i2c_clear_fifo_int(bus);
npcm_i2c_clear_rx_fifo(bus);
npcm_i2c_clear_tx_fifo(bus);
iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO,
bus->reg + NPCM_I2CFIF_CTS);
}
bus->state = I2C_IDLE;
ret = IRQ_HANDLED;
}
/* restart condition occurred and Rx-FIFO was not empty */
if (bus->fifo_use && FIELD_GET(NPCM_I2CFIF_CTS_SLVRSTR,
ioread8(bus->reg + NPCM_I2CFIF_CTS))) {
bus->stop_ind = I2C_SLAVE_RESTART_IND;
bus->master_or_slave = I2C_SLAVE;
if (bus->operation == I2C_READ_OPER)
npcm_i2c_read_fifo_slave(bus, npcm_i2c_fifo_usage(bus));
bus->operation = I2C_WRITE_OPER;
iowrite8(0, bus->reg + NPCM_I2CRXF_CTL);
val = NPCM_I2CFIF_CTS_CLR_FIFO | NPCM_I2CFIF_CTS_SLVRSTR |
NPCM_I2CFIF_CTS_RXF_TXE;
iowrite8(val, bus->reg + NPCM_I2CFIF_CTS);
npcm_i2c_slave_rd_wr(bus);
ret = IRQ_HANDLED;
}
/* A Slave Address Match has been identified */
if (NPCM_I2CST_NMATCH & i2cst) {
u8 info = 0;
/* Address match automatically implies slave mode */
bus->master_or_slave = I2C_SLAVE;
npcm_i2c_clear_fifo_int(bus);
npcm_i2c_clear_rx_fifo(bus);
npcm_i2c_clear_tx_fifo(bus);
iowrite8(0, bus->reg + NPCM_I2CTXF_CTL);
iowrite8(I2C_HW_FIFO_SIZE, bus->reg + NPCM_I2CRXF_CTL);
if (NPCM_I2CST_XMIT & i2cst) {
bus->operation = I2C_WRITE_OPER;
} else {
i2c_slave_event(bus->slave, I2C_SLAVE_WRITE_REQUESTED,
&info);
bus->operation = I2C_READ_OPER;
}
if (bus->own_slave_addr == 0xFF) {
/* Check which type of address match */
val = ioread8(bus->reg + NPCM_I2CCST);
if (NPCM_I2CCST_MATCH & val) {
u16 addr;
enum i2c_addr eaddr;
u8 i2ccst2;
u8 i2ccst3;
i2ccst3 = ioread8(bus->reg + NPCM_I2CCST3);
i2ccst2 = ioread8(bus->reg + NPCM_I2CCST2);
/*
* the i2c module can response to 10 own SA.
* check which one was addressed by the master.
* repond to the first one.
*/
addr = ((i2ccst3 & 0x07) << 7) |
(i2ccst2 & 0x7F);
info = ffs(addr);
eaddr = (enum i2c_addr)info;
addr = npcm_i2c_get_slave_addr(bus, eaddr);
addr &= 0x7F;
bus->own_slave_addr = addr;
if (bus->PEC_mask & BIT(info))
bus->PEC_use = true;
else
bus->PEC_use = false;
} else {
if (NPCM_I2CCST_GCMATCH & val)
bus->own_slave_addr = 0;
if (NPCM_I2CCST_ARPMATCH & val)
bus->own_slave_addr = 0x61;
}
} else {
/*
* Slave match can happen in two options:
* 1. Start, SA, read (slave read without further ado)
* 2. Start, SA, read, data, restart, SA, read, ...
* (slave read in fragmented mode)
* 3. Start, SA, write, data, restart, SA, read, ..
* (regular write-read mode)
*/
if ((bus->state == I2C_OPER_STARTED &&
bus->operation == I2C_READ_OPER &&
bus->stop_ind == I2C_SLAVE_XMIT_IND) ||
bus->stop_ind == I2C_SLAVE_RCV_IND) {
/* slave tx after slave rx w/o STOP */
bus->stop_ind = I2C_SLAVE_RESTART_IND;
}
}
if (NPCM_I2CST_XMIT & i2cst)
bus->stop_ind = I2C_SLAVE_XMIT_IND;
else
bus->stop_ind = I2C_SLAVE_RCV_IND;
bus->state = I2C_SLAVE_MATCH;
npcm_i2c_slave_rd_wr(bus);
iowrite8(NPCM_I2CST_NMATCH, bus->reg + NPCM_I2CST);
ret = IRQ_HANDLED;
}
/* Slave SDA status is set - tx or rx */
if ((NPCM_I2CST_SDAST & i2cst) ||
(bus->fifo_use &&
(npcm_i2c_tx_fifo_empty(bus) || npcm_i2c_rx_fifo_full(bus)))) {
npcm_i2c_slave_rd_wr(bus);
iowrite8(NPCM_I2CST_SDAST, bus->reg + NPCM_I2CST);
ret = IRQ_HANDLED;
} /* SDAST */
return ret;
}