/* * External I2C Interface driver xfer indication values, which indicate status * of the bus.
*/ enum i2c_state_ind {
I2C_NO_STATUS_IND = 0,
I2C_SLAVE_RCV_IND,
I2C_SLAVE_XMIT_IND,
I2C_SLAVE_XMIT_MISSING_DATA_IND,
I2C_SLAVE_RESTART_IND,
I2C_SLAVE_DONE_IND,
I2C_MASTER_DONE_IND,
I2C_NACK_IND,
I2C_BUS_ERR_IND,
I2C_WAKE_UP_IND,
I2C_BLOCK_BYTES_ERR_IND,
I2C_SLAVE_RCV_MISSING_DATA_IND,
};
/* * Operation type values (used to define the operation currently running) * module is interrupt driven, on each interrupt the current operation is * checked to see if the module is currently reading or writing.
*/ enum i2c_oper {
I2C_NO_OPER = 0,
I2C_WRITE_OPER,
I2C_READ_OPER,
};
/* I2C Bank (module had 2 banks of registers) */ enum i2c_bank {
I2C_BANK_0 = 0,
I2C_BANK_1,
};
/* Internal I2C states values (for the I2C module state machine). */ enum i2c_state {
I2C_DISABLE = 0,
I2C_IDLE,
I2C_MASTER_START,
I2C_SLAVE_MATCH,
I2C_OPER_STARTED,
I2C_STOP_PENDING,
};
/* BANK 1 regs */ #define NPCM_I2CFIF_CTS 0x10 /* Both FIFOs Control and Status */ #define NPCM_I2CTXF_CTL 0x12 /* Tx-FIFO Control */ #define NPCM_I2CT_OUT 0x14 /* Bus T.O. */ #define NPCM_I2CPEC 0x16 /* PEC Data */ #define NPCM_I2CTXF_STS 0x1A /* Tx-FIFO Status */ #define NPCM_I2CRXF_STS 0x1C /* Rx-FIFO Status */ #define NPCM_I2CRXF_CTL 0x1E /* Rx-FIFO Control */
#if IS_ENABLED(CONFIG_I2C_SLAVE) /* * npcm_i2caddr array: * The module supports having multiple own slave addresses. * Since the addr regs are sprinkled all over the address space, * use this array to get the address or each register.
*/ #define I2C_NUM_OWN_ADDR 10 #define I2C_NUM_OWN_ADDR_SUPPORTED 2
/* enable\disable end of busy (EOB) interrupts */ staticinlinevoid npcm_i2c_eob_int(struct npcm_i2c *bus, bool enable)
{
u8 val;
/* Clear EO_BUSY pending bit: */
val = ioread8(bus->reg + NPCM_I2CCST3);
val = val | NPCM_I2CCST3_EO_BUSY;
iowrite8(val, bus->reg + NPCM_I2CCST3);
val = ioread8(bus->reg + NPCM_I2CCTL1);
val &= ~NPCM_I2CCTL1_RWS; if (enable)
val |= NPCM_I2CCTL1_EOBINTE; else
val &= ~NPCM_I2CCTL1_EOBINTE;
iowrite8(val, bus->reg + NPCM_I2CCTL1);
}
val = ioread8(bus->reg + NPCM_I2CCTL1);
val &= ~NPCM_I2CCTL1_RWS; if (enable)
val |= NPCM_I2CCTL1_INTEN; else
val &= ~NPCM_I2CCTL1_INTEN;
iowrite8(val, bus->reg + NPCM_I2CCTL1);
}
/* * override HW issue: I2C may fail to supply stop condition in Master * Write operation. * Need to delay at least 5 us from the last int, before issueing a stop
*/
udelay(10); /* function called from interrupt, can't sleep */
val = ioread8(bus->reg + NPCM_I2CCTL1);
val &= ~(NPCM_I2CCTL1_START | NPCM_I2CCTL1_ACK);
val |= NPCM_I2CCTL1_STOP;
iowrite8(val, bus->reg + NPCM_I2CCTL1);
val = ioread8(bus->reg + NPCM_I2CCTL1);
val &= ~NPCM_I2CCTL1_RWS; if (stall)
val |= NPCM_I2CCTL1_STASTRE; else
val &= ~NPCM_I2CCTL1_STASTRE;
iowrite8(val, bus->reg + NPCM_I2CCTL1);
}
sa_reg = (addr & 0x7F) | FIELD_PREP(NPCM_I2CADDR_SAEN, enable); if (addr_type == I2C_GC_ADDR) {
i2cctl1 = ioread8(bus->reg + NPCM_I2CCTL1); if (enable)
i2cctl1 |= NPCM_I2CCTL1_GCMEN; else
i2cctl1 &= ~NPCM_I2CCTL1_GCMEN;
iowrite8(i2cctl1, bus->reg + NPCM_I2CCTL1); return 0;
} elseif (addr_type == I2C_ARP_ADDR) {
i2cctl3 = ioread8(bus->reg + NPCM_I2CCTL3); if (enable)
i2cctl3 |= I2CCTL3_ARPMEN; else
i2cctl3 &= ~I2CCTL3_ARPMEN;
iowrite8(i2cctl3, bus->reg + NPCM_I2CCTL3); return 0;
} if (addr_type > I2C_SLAVE_ADDR2 && addr_type <= I2C_SLAVE_ADDR10)
dev_err(bus->dev, "try to enable more than 2 SA not supported\n");
if (addr_type >= I2C_ARP_ADDR) return -EFAULT;
/* Set and enable the address */
iowrite8(sa_reg, bus->reg + npcm_i2caddr[addr_type]);
npcm_i2c_slave_int_enable(bus, enable);
return 0;
} #endif
staticvoid npcm_i2c_reset(struct npcm_i2c *bus)
{ /* * Save I2CCTL1 relevant bits. It is being cleared when the module * is disabled.
*/
u8 i2cctl1; #if IS_ENABLED(CONFIG_I2C_SLAVE)
u8 addr; #endif
/* * Fill the FIFO, while the FIFO is not full and there are more bytes * to write
*/
size_free_fifo = bus->data->fifo_size - npcm_i2c_fifo_usage(bus); while (max_bytes-- && size_free_fifo) { if (bus->wr_ind < bus->wr_size)
npcm_i2c_wr_byte(bus, bus->wr_buf[bus->wr_ind++]); else
npcm_i2c_wr_byte(bus, 0xFF);
size_free_fifo = bus->data->fifo_size - npcm_i2c_fifo_usage(bus);
}
}
/* * npcm_i2c_set_fifo: * configure the FIFO before using it. If nread is -1 RX FIFO will not be * configured. same for nwrite
*/ staticvoid npcm_i2c_set_fifo(struct npcm_i2c *bus, int nread, int nwrite)
{
u8 rxf_ctl = 0;
if (!bus->fifo_use) return;
npcm_i2c_select_bank(bus, I2C_BANK_1);
npcm_i2c_clear_tx_fifo(bus);
npcm_i2c_clear_rx_fifo(bus);
/* set LAST bit. if LAST is set next FIFO packet is nacked */ if (nread <= bus->data->fifo_size)
rxf_ctl |= bus->data->rxf_ctl_last_pec;
/* * if we are about to read the first byte in blk rd mode, * don't NACK it. If slave returns zero size HW can't NACK * it immediately, it will read extra byte and then NACK.
*/ if (bus->rd_ind == 0 && bus->read_block_use) { /* set fifo to read one byte, no last: */
rxf_ctl = 1;
}
/* set fifo size: */
iowrite8(rxf_ctl, bus->reg + NPCM_I2CRXF_CTL);
}
/* configure TX FIFO */ if (nwrite > 0) { if (nwrite > bus->data->fifo_size) /* data to send is more then FIFO size. */
iowrite8(bus->data->fifo_size, bus->reg + NPCM_I2CTXF_CTL); else
iowrite8(nwrite, bus->reg + NPCM_I2CTXF_CTL);
while (bytes_in_fifo--) {
data = npcm_i2c_rd_byte(bus); if (bus->rd_ind < bus->rd_size)
bus->rd_buf[bus->rd_ind++] = data;
}
}
staticvoid npcm_i2c_master_abort(struct npcm_i2c *bus)
{ /* Only current master is allowed to issue a stop condition */ if (!npcm_i2c_is_master(bus)) return;
#if IS_ENABLED(CONFIG_I2C_SLAVE) static u8 npcm_i2c_get_slave_addr(struct npcm_i2c *bus, enum i2c_addr addr_type)
{ if (addr_type > I2C_SLAVE_ADDR2 && addr_type <= I2C_SLAVE_ADDR10)
dev_err(bus->dev, "get slave: try to use more than 2 SA not supported\n");
staticint npcm_i2c_remove_slave_addr(struct npcm_i2c *bus, u8 slave_add)
{ int i;
/* Set the enable bit */
slave_add |= 0x80;
for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR_SUPPORTED; i++) { if (ioread8(bus->reg + npcm_i2caddr[i]) == slave_add)
iowrite8(0, bus->reg + npcm_i2caddr[i]);
}
return 0;
}
staticvoid npcm_i2c_write_fifo_slave(struct npcm_i2c *bus, u16 max_bytes)
{ /* * Fill the FIFO, while the FIFO is not full and there are more bytes * to write
*/
npcm_i2c_clear_fifo_int(bus);
npcm_i2c_clear_tx_fifo(bus);
iowrite8(0, bus->reg + NPCM_I2CTXF_CTL); while (max_bytes-- && bus->data->fifo_size != npcm_i2c_fifo_usage(bus)) { if (bus->slv_wr_size <= 0) break;
bus->slv_wr_ind = bus->slv_wr_ind & (bus->data->fifo_size - 1);
npcm_i2c_wr_byte(bus, bus->slv_wr_buf[bus->slv_wr_ind]);
bus->slv_wr_ind++;
bus->slv_wr_ind = bus->slv_wr_ind & (bus->data->fifo_size - 1);
bus->slv_wr_size--;
}
}
/* 1st byte is length in block protocol: */ if (bus->slv_rd_ind == 1 && bus->read_block_use)
bus->slv_rd_size = data + bus->PEC_use + 1;
}
}
staticint npcm_i2c_slave_get_wr_buf(struct npcm_i2c *bus)
{ int i;
u8 value; int ind; int ret = bus->slv_wr_ind;
/* fill a cyclic buffer */ for (i = 0; i < bus->data->fifo_size; i++) { if (bus->slv_wr_size >= bus->data->fifo_size) break; if (bus->state == I2C_SLAVE_MATCH) {
i2c_slave_event(bus->slave, I2C_SLAVE_READ_REQUESTED, &value);
bus->state = I2C_OPER_STARTED;
} else {
i2c_slave_event(bus->slave, I2C_SLAVE_READ_PROCESSED, &value);
}
ind = (bus->slv_wr_ind + bus->slv_wr_size) & (bus->data->fifo_size - 1);
bus->slv_wr_buf[ind] = value;
bus->slv_wr_size++;
} return bus->data->fifo_size - ret;
}
staticvoid npcm_i2c_slave_send_rd_buf(struct npcm_i2c *bus)
{ int i;
for (i = 0; i < bus->slv_rd_ind; i++)
i2c_slave_event(bus->slave, I2C_SLAVE_WRITE_RECEIVED,
&bus->slv_rd_buf[i]); /* * once we send bytes up, need to reset the counter of the wr buf * got data from master (new offset in device), ignore wr fifo:
*/ if (bus->slv_rd_ind) {
bus->slv_wr_size = 0;
bus->slv_wr_ind = 0;
}
/* get the next buffer */
npcm_i2c_slave_get_wr_buf(bus);
npcm_i2c_write_fifo_slave(bus, nwrite);
}
/* * npcm_i2c_slave_wr_buf_sync: * currently slave IF only supports single byte operations. * in order to utilize the npcm HW FIFO, the driver will ask for 16 bytes * at a time, pack them in buffer, and then transmit them all together * to the FIFO and onward to the bus. * NACK on read will be once reached to bus->adap->quirks->max_read_len. * sending a NACK wherever the backend requests for it is not supported. * the next two functions allow reading to local buffer before writing it all * to the HW FIFO.
*/ staticvoid npcm_i2c_slave_wr_buf_sync(struct npcm_i2c *bus)
{ int left_in_fifo;
/* update the wr fifo index back to the untransmitted bytes: */
bus->slv_wr_ind = bus->slv_wr_ind - left_in_fifo;
bus->slv_wr_size = bus->slv_wr_size + left_in_fifo;
if (bus->slv_wr_ind < 0)
bus->slv_wr_ind += bus->data->fifo_size;
}
staticvoid npcm_i2c_slave_rd_wr(struct npcm_i2c *bus)
{ if (NPCM_I2CST_XMIT & ioread8(bus->reg + NPCM_I2CST)) { /* * Slave got an address match with direction bit 1 so it should * transmit data. Write till the master will NACK
*/
bus->operation = I2C_WRITE_OPER;
npcm_i2c_slave_xmit(bus, bus->adap.quirks->max_write_len,
bus->slv_wr_buf);
} else { /* * Slave got an address match with direction bit 0 so it should * receive data. * this module does not support saying no to bytes. * it will always ACK.
*/
bus->operation = I2C_READ_OPER;
npcm_i2c_read_fifo_slave(bus, npcm_i2c_fifo_usage(bus));
bus->stop_ind = I2C_SLAVE_RCV_IND;
npcm_i2c_slave_send_rd_buf(bus);
npcm_i2c_slave_receive(bus, bus->adap.quirks->max_read_len,
bus->slv_rd_buf);
}
}
/* 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);
/* 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 */
/* * If irq is not one of the above, make sure EOB is disabled and all * status bits are cleared.
*/ if (ret == IRQ_NONE) {
npcm_i2c_eob_int(bus, false);
npcm_i2c_clear_master_status(bus);
}
/* * In order not to change the RX_TRH during transaction (we found that * this might be problematic if it takes too much time to read the FIFO) * we read the data in the following way. If the number of bytes to * read == FIFO Size + C (where C < FIFO Size)then first read C bytes * and in the next int we read rest of the data.
*/ if (rcount < (2 * bus->data->fifo_size) && rcount > bus->data->fifo_size)
fifo_bytes = rcount - bus->data->fifo_size;
if (rcount <= fifo_bytes) { /* last bytes are about to be read - end of tx */
bus->state = I2C_STOP_PENDING;
bus->stop_ind = ind;
npcm_i2c_eob_int(bus, true); /* Stop should be set before reading last byte. */
npcm_i2c_master_stop(bus);
npcm_i2c_read_fifo(bus, fifo_bytes);
} else {
npcm_i2c_read_fifo(bus, fifo_bytes);
rcount = bus->rd_size - bus->rd_ind;
npcm_i2c_set_fifo(bus, rcount, -1);
}
}
if (bus->fifo_use)
npcm_i2c_clear_tx_fifo(bus); /* clear the TX fifo status bit */
/* Master write operation - last byte handling */ if (bus->wr_ind == bus->wr_size) { if (bus->fifo_use && npcm_i2c_fifo_usage(bus) > 0) /* * No more bytes to send (to add to the FIFO), * however the FIFO is not empty yet. It is * still in the middle of tx. Currently there's nothing * to do except for waiting to the end of the tx * We will get an int when the FIFO will get empty.
*/ return;
if (bus->rd_size == 0) { /* all bytes have been written, in wr only operation */
npcm_i2c_eob_int(bus, true);
bus->state = I2C_STOP_PENDING;
bus->stop_ind = I2C_MASTER_DONE_IND;
npcm_i2c_master_stop(bus); /* Clear SDA Status bit (by writing dummy byte) */
npcm_i2c_wr_byte(bus, 0xFF);
} else { /* last write-byte written on previous int - restart */
npcm_i2c_set_fifo(bus, bus->rd_size, -1); /* Generate repeated start upon next write to SDA */
npcm_i2c_master_start(bus);
/* * Receiving one byte only - stall after successful * completion of send address byte. If we NACK here, and * slave doesn't ACK the address, we might * unintentionally NACK the next multi-byte read.
*/ if (bus->rd_size == 1)
npcm_i2c_stall_after_start(bus, true);
/* Next int will occur on read */
bus->operation = I2C_READ_OPER; /* send the slave address in read direction */
npcm_i2c_wr_byte(bus, bus->dest_addr | 0x1);
}
} else { /* write next byte not last byte and not slave address */ if (!bus->fifo_use || bus->wr_size == 1) {
npcm_i2c_wr_byte(bus, bus->wr_buf[bus->wr_ind++]);
} else {
wcount = bus->wr_size - bus->wr_ind;
npcm_i2c_set_fifo(bus, -1, wcount); if (wcount)
npcm_i2c_write_to_fifo_master(bus, wcount);
}
}
}
/* added bytes to the packet: */
block_extra_bytes_size = bus->read_block_use + bus->PEC_use;
/* * Perform master read, distinguishing between last byte and the rest of * the bytes. The last byte should be read when the clock is stopped
*/ if (bus->rd_ind == 0) { /* first byte handling: */ if (bus->read_block_use) { /* first byte in block protocol is the size: */
data = npcm_i2c_rd_byte(bus);
data = clamp_val(data, 1, I2C_SMBUS_BLOCK_MAX);
bus->rd_size = data + block_extra_bytes_size;
bus->rd_buf[bus->rd_ind++] = data;
/* clear RX FIFO interrupt status: */ if (bus->fifo_use) {
data = ioread8(bus->reg + NPCM_I2CFIF_CTS);
data = data | NPCM_I2CFIF_CTS_RXF_TXE;
iowrite8(data, bus->reg + NPCM_I2CFIF_CTS);
}
/* A NACK has occurred */ staticvoid npcm_i2c_irq_handle_nack(struct npcm_i2c *bus)
{
u8 val;
if (bus->nack_cnt < ULLONG_MAX)
bus->nack_cnt++;
if (bus->fifo_use) { /* * if there are still untransmitted bytes in TX FIFO * reduce them from wr_ind
*/ if (bus->operation == I2C_WRITE_OPER)
bus->wr_ind -= npcm_i2c_fifo_usage(bus);
/* clear the FIFO */
iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO, bus->reg + NPCM_I2CFIF_CTS);
}
/* In master write operation, got unexpected NACK */
bus->stop_ind = I2C_NACK_IND; /* Only current master is allowed to issue Stop Condition */ if (npcm_i2c_is_master(bus)) { /* stopping in the middle */
npcm_i2c_eob_int(bus, false);
npcm_i2c_master_stop(bus);
/* Clear SDA Status bit (by reading dummy byte) */
npcm_i2c_rd_byte(bus);
/* * The bus is released from stall only after the SW clears * NEGACK bit. Then a Stop condition is sent.
*/
npcm_i2c_clear_master_status(bus);
readx_poll_timeout_atomic(ioread8, bus->reg + NPCM_I2CCST, val,
!(val & NPCM_I2CCST_BUSY), 10, 200); /* Verify no status bits are still set after bus is released */
npcm_i2c_clear_master_status(bus);
}
bus->state = I2C_IDLE;
/* * In Master mode, NACK should be cleared only after STOP. * In such case, the bus is released from stall only after the * software clears NACK bit. Then a Stop condition is sent.
*/
npcm_i2c_callback(bus, bus->stop_ind, bus->wr_ind);
}
/* Master mode: a Bus Error has been identified */ staticvoid npcm_i2c_irq_handle_ber(struct npcm_i2c *bus)
{ if (bus->ber_cnt < ULLONG_MAX)
bus->ber_cnt++;
bus->stop_ind = I2C_BUS_ERR_IND; if (npcm_i2c_is_master(bus)) {
npcm_i2c_master_abort(bus);
} else {
bus->ber_state = true;
npcm_i2c_clear_master_status(bus);
/* Clear stall only after setting STOP */
iowrite8(NPCM_I2CST_STASTR, bus->reg + NPCM_I2CST);
}
/* SDA status is set - TX or RX, master */ staticvoid npcm_i2c_irq_handle_sda(struct npcm_i2c *bus, u8 i2cst)
{
u8 fif_cts;
if (!npcm_i2c_is_master(bus)) return;
if (bus->state == I2C_IDLE) {
bus->stop_ind = I2C_WAKE_UP_IND;
if (npcm_i2c_is_quick(bus) || bus->read_block_use) /* * Need to stall after successful * completion of sending address byte
*/
npcm_i2c_stall_after_start(bus, true); else
npcm_i2c_stall_after_start(bus, false);
/* * Receiving one byte only - stall after successful completion * of sending address byte If we NACK here, and slave doesn't * ACK the address, we might unintentionally NACK the next * multi-byte read
*/ if (bus->wr_size == 0 && bus->rd_size == 1)
npcm_i2c_stall_after_start(bus, true);
/* Initiate I2C master tx */
/* select bank 1 for FIFO regs */
npcm_i2c_select_bank(bus, I2C_BANK_1);
/* * Configure the FIFO threshold: * according to the needed # of bytes to read. * Note: due to HW limitation can't config the rx fifo before it * got and ACK on the restart. LAST bit will not be reset unless * RX completed. It will stay set on the next tx.
*/ if (bus->wr_size)
npcm_i2c_set_fifo(bus, -1, bus->wr_size); else
npcm_i2c_set_fifo(bus, bus->rd_size, -1);
staticint npcm_i2c_int_master_handler(struct npcm_i2c *bus)
{
u8 i2cst; int ret = -EIO;
i2cst = ioread8(bus->reg + NPCM_I2CST);
if (FIELD_GET(NPCM_I2CST_NMATCH, i2cst)) {
npcm_i2c_irq_handle_nmatch(bus); return 0;
} /* A NACK has occurred */ if (FIELD_GET(NPCM_I2CST_NEGACK, i2cst)) {
npcm_i2c_irq_handle_nack(bus); return 0;
}
/* Master mode: a Bus Error has been identified */ if (FIELD_GET(NPCM_I2CST_BER, i2cst)) {
npcm_i2c_irq_handle_ber(bus); return 0;
}
/* EOB: a master End Of Busy (meaning STOP completed) */ if ((FIELD_GET(NPCM_I2CCTL1_EOBINTE,
ioread8(bus->reg + NPCM_I2CCTL1)) == 1) &&
(FIELD_GET(NPCM_I2CCST3_EO_BUSY,
ioread8(bus->reg + NPCM_I2CCST3)))) {
npcm_i2c_irq_handle_eob(bus); #if IS_ENABLED(CONFIG_I2C_SLAVE) /* reenable slave if it was enabled */ if (bus->slave)
iowrite8(bus->slave->addr | NPCM_I2CADDR_SAEN,
bus->reg + NPCM_I2CADDR1); #endif return 0;
}
/* Address sent and requested stall occurred (Master mode) */ if (FIELD_GET(NPCM_I2CST_STASTR, i2cst)) {
npcm_i2c_irq_handle_stall_after_start(bus);
ret = 0;
}
/* SDA status is set - TX or RX, master */ if (FIELD_GET(NPCM_I2CST_SDAST, i2cst) ||
(bus->fifo_use &&
(npcm_i2c_tx_fifo_empty(bus) || npcm_i2c_rx_fifo_full(bus)))) {
npcm_i2c_irq_handle_sda(bus, i2cst);
ret = 0;
}
return ret;
}
/* recovery using TGCLK functionality of the module */ staticint npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap)
{
u8 val;
u8 fif_cts; bool done = false; int status = -ENOTRECOVERABLE; struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap); /* Allow 3 bytes (27 toggles) to be read from the slave: */ int iter = 27;
if ((npcm_i2c_get_SDA(_adap) == 1) && (npcm_i2c_get_SCL(_adap) == 1)) {
dev_dbg(bus->dev, "bus%d-0x%x recovery skipped, bus not stuck",
bus->num, bus->dest_addr);
npcm_i2c_reset(bus);
bus->ber_state = false; return 0;
}
/* Repeat the following sequence until SDA is released */ do { /* Issue a single SCL toggle */
iowrite8(NPCM_I2CCST_TGSCL, bus->reg + NPCM_I2CCST);
usleep_range(20, 30); /* If SDA line is inactive (high), stop */ if (npcm_i2c_get_SDA(_adap)) {
done = true;
status = 0;
}
} while (!done && iter--);
/* If SDA line is released: send start-addr-stop, to re-sync. */ if (npcm_i2c_get_SDA(_adap)) { /* Send an address byte in write direction: */
npcm_i2c_wr_byte(bus, bus->dest_addr);
npcm_i2c_master_start(bus); /* Wait until START condition is sent */
status = readx_poll_timeout(npcm_i2c_get_SCL, _adap, val, !val,
20, 200); /* If START condition was sent */ if (npcm_i2c_is_master(bus) > 0) {
usleep_range(20, 30);
npcm_i2c_master_stop(bus);
usleep_range(200, 500);
}
}
npcm_i2c_reset(bus);
npcm_i2c_int_enable(bus, true);
if ((npcm_i2c_get_SDA(_adap) == 1) && (npcm_i2c_get_SCL(_adap) == 1))
status = 0; else
status = -ENOTRECOVERABLE; if (status) { if (bus->rec_fail_cnt < ULLONG_MAX)
bus->rec_fail_cnt++;
} else { if (bus->rec_succ_cnt < ULLONG_MAX)
bus->rec_succ_cnt++;
}
bus->ber_state = false; return status;
}
/* recovery using bit banging functionality of the module */ staticvoid npcm_i2c_recovery_init(struct i2c_adapter *_adap)
{ struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap); struct i2c_bus_recovery_info *rinfo = &bus->rinfo;
rinfo->recover_bus = npcm_i2c_recovery_tgclk;
/* * npcm i2c HW allows direct reading of SCL and SDA. * However, it does not support setting SCL and SDA directly. * The recovery function can toggle SCL when SDA is low (but not set) * Getter functions used internally, and can be used externally.
*/
rinfo->get_scl = npcm_i2c_get_SCL;
rinfo->get_sda = npcm_i2c_get_SDA;
_adap->bus_recovery_info = rinfo;
}
time_left = jiffies + bus->adap.timeout / bus->adap.retries + 1; do { /* * we must clear slave address immediately when the bus is not * busy, so we spinlock it, but we don't keep the lock for the * entire while since it is too long.
*/
spin_lock_irqsave(&bus->lock, flags);
bus_busy = ioread8(bus->reg + NPCM_I2CCST) & NPCM_I2CCST_BB; #if IS_ENABLED(CONFIG_I2C_SLAVE) if (!bus_busy && bus->slave)
iowrite8((bus->slave->addr & 0x7F),
bus->reg + NPCM_I2CADDR1); #endif
spin_unlock_irqrestore(&bus->lock, flags);
} while (time_is_after_jiffies(time_left) && bus_busy);
/* * Store the address early in a global position to ensure it is * accessible for a potential call to i2c_recover_bus(). * * Since the transfer might be a read operation, remove the I2C_M_RD flag * from the bus->dest_addr for the i2c_recover_bus() call later. * * The i2c_recover_bus() uses the address in a write direction to recover * the i2c bus if some error condition occurs. * * Remove the I2C_M_RD flag from the address since npcm_i2c_master_start_xmit() * handles the read/write operation internally.
*/
bus->dest_addr = i2c_8bit_addr_from_msg(msg0) & ~I2C_M_RD;
/* * Check the BER (bus error) state, when ber_state is true, it means that the module * detects the bus error which is caused by some factor like that the electricity * noise occurs on the bus. Under this condition, the module is reset and the bus * gets recovered. * * While ber_state is false, the module reset and bus recovery also get done as the * bus is busy.
*/ if (bus_busy || bus->ber_state) {
iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST);
npcm_i2c_reset(bus);
i2c_recover_bus(adap); return -EAGAIN;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.