Skip to content

Commit e5222d4

Browse files
TaliPerrywsakernel
authored andcommitted
i2c: npcm: Handle spurious interrupts
On some platforms in rare cases (1 to 100,000 transactions), the i2c gets a spurious interrupt which means that we enter an interrupt but in the interrupt handler we don't find any status bit that points to the reason we got this interrupt. This may be a case of a rare HW issue or signal integrity issue that is still under investigation. In order to overcome this we are doing the following: 1. Disable incoming interrupts in master mode only when slave mode is not enabled. 2. Clear end of busy (EOB) after every interrupt. 3. Clear other status bits (just in case since we found them cleared) 4. Return correct status during the interrupt that will finish the transaction. On next xmit transaction if the bus is still busy the master will issue a recovery process before issuing the new transaction. Fixes: 56a1485 ("i2c: npcm7xx: Add Nuvoton NPCM I2C controller driver") Signed-off-by: Tali Perry <[email protected]> Signed-off-by: Tyrone Ting <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent ea9f842 commit e5222d4

File tree

1 file changed

+62
-29
lines changed

1 file changed

+62
-29
lines changed

drivers/i2c/busses/i2c-npcm7xx.c

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,15 @@ static inline void npcm_i2c_nack(struct npcm_i2c *bus)
564564
iowrite8(val, bus->reg + NPCM_I2CCTL1);
565565
}
566566

567+
static inline void npcm_i2c_clear_master_status(struct npcm_i2c *bus)
568+
{
569+
u8 val;
570+
571+
/* Clear NEGACK, STASTR and BER bits */
572+
val = NPCM_I2CST_BER | NPCM_I2CST_NEGACK | NPCM_I2CST_STASTR;
573+
iowrite8(val, bus->reg + NPCM_I2CST);
574+
}
575+
567576
#if IS_ENABLED(CONFIG_I2C_SLAVE)
568577
static void npcm_i2c_slave_int_enable(struct npcm_i2c *bus, bool enable)
569578
{
@@ -643,8 +652,8 @@ static void npcm_i2c_reset(struct npcm_i2c *bus)
643652
iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST);
644653
iowrite8(0xFF, bus->reg + NPCM_I2CST);
645654

646-
/* Clear EOB bit */
647-
iowrite8(NPCM_I2CCST3_EO_BUSY, bus->reg + NPCM_I2CCST3);
655+
/* Clear and disable EOB */
656+
npcm_i2c_eob_int(bus, false);
648657

649658
/* Clear all fifo bits: */
650659
iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO, bus->reg + NPCM_I2CFIF_CTS);
@@ -656,6 +665,9 @@ static void npcm_i2c_reset(struct npcm_i2c *bus)
656665
}
657666
#endif
658667

668+
/* clear status bits for spurious interrupts */
669+
npcm_i2c_clear_master_status(bus);
670+
659671
bus->state = I2C_IDLE;
660672
}
661673

@@ -818,15 +830,6 @@ static void npcm_i2c_read_fifo(struct npcm_i2c *bus, u8 bytes_in_fifo)
818830
}
819831
}
820832

821-
static inline void npcm_i2c_clear_master_status(struct npcm_i2c *bus)
822-
{
823-
u8 val;
824-
825-
/* Clear NEGACK, STASTR and BER bits */
826-
val = NPCM_I2CST_BER | NPCM_I2CST_NEGACK | NPCM_I2CST_STASTR;
827-
iowrite8(val, bus->reg + NPCM_I2CST);
828-
}
829-
830833
static void npcm_i2c_master_abort(struct npcm_i2c *bus)
831834
{
832835
/* Only current master is allowed to issue a stop condition */
@@ -1234,7 +1237,16 @@ static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus)
12341237
ret = IRQ_HANDLED;
12351238
} /* SDAST */
12361239

1237-
return ret;
1240+
/*
1241+
* if irq is not one of the above, make sure EOB is disabled and all
1242+
* status bits are cleared.
1243+
*/
1244+
if (ret == IRQ_NONE) {
1245+
npcm_i2c_eob_int(bus, false);
1246+
npcm_i2c_clear_master_status(bus);
1247+
}
1248+
1249+
return IRQ_HANDLED;
12381250
}
12391251

12401252
static int npcm_i2c_reg_slave(struct i2c_client *client)
@@ -1470,13 +1482,18 @@ static void npcm_i2c_irq_handle_nack(struct npcm_i2c *bus)
14701482
npcm_i2c_eob_int(bus, false);
14711483
npcm_i2c_master_stop(bus);
14721484

1485+
/* Clear SDA Status bit (by reading dummy byte) */
1486+
npcm_i2c_rd_byte(bus);
1487+
14731488
/*
14741489
* The bus is released from stall only after the SW clears
14751490
* NEGACK bit. Then a Stop condition is sent.
14761491
*/
14771492
npcm_i2c_clear_master_status(bus);
14781493
readx_poll_timeout_atomic(ioread8, bus->reg + NPCM_I2CCST, val,
14791494
!(val & NPCM_I2CCST_BUSY), 10, 200);
1495+
/* verify no status bits are still set after bus is released */
1496+
npcm_i2c_clear_master_status(bus);
14801497
}
14811498
bus->state = I2C_IDLE;
14821499

@@ -1675,10 +1692,10 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap)
16751692
int iter = 27;
16761693

16771694
if ((npcm_i2c_get_SDA(_adap) == 1) && (npcm_i2c_get_SCL(_adap) == 1)) {
1678-
dev_dbg(bus->dev, "bus%d recovery skipped, bus not stuck",
1679-
bus->num);
1695+
dev_dbg(bus->dev, "bus%d-0x%x recovery skipped, bus not stuck",
1696+
bus->num, bus->dest_addr);
16801697
npcm_i2c_reset(bus);
1681-
return status;
1698+
return 0;
16821699
}
16831700

16841701
npcm_i2c_int_enable(bus, false);
@@ -1912,6 +1929,7 @@ static int npcm_i2c_init_module(struct npcm_i2c *bus, enum i2c_mode mode,
19121929
bus_freq_hz < I2C_FREQ_MIN_HZ || bus_freq_hz > I2C_FREQ_MAX_HZ)
19131930
return -EINVAL;
19141931

1932+
npcm_i2c_int_enable(bus, false);
19151933
npcm_i2c_disable(bus);
19161934

19171935
/* Configure FIFO mode : */
@@ -1940,10 +1958,17 @@ static int npcm_i2c_init_module(struct npcm_i2c *bus, enum i2c_mode mode,
19401958
val = (val | NPCM_I2CCTL1_NMINTE) & ~NPCM_I2CCTL1_RWS;
19411959
iowrite8(val, bus->reg + NPCM_I2CCTL1);
19421960

1943-
npcm_i2c_int_enable(bus, true);
1944-
19451961
npcm_i2c_reset(bus);
19461962

1963+
/* check HW is OK: SDA and SCL should be high at this point. */
1964+
if ((npcm_i2c_get_SDA(&bus->adap) == 0) || (npcm_i2c_get_SCL(&bus->adap) == 0)) {
1965+
dev_err(bus->dev, "I2C%d init fail: lines are low\n", bus->num);
1966+
dev_err(bus->dev, "SDA=%d SCL=%d\n", npcm_i2c_get_SDA(&bus->adap),
1967+
npcm_i2c_get_SCL(&bus->adap));
1968+
return -ENXIO;
1969+
}
1970+
1971+
npcm_i2c_int_enable(bus, true);
19471972
return 0;
19481973
}
19491974

@@ -1991,10 +2016,14 @@ static irqreturn_t npcm_i2c_bus_irq(int irq, void *dev_id)
19912016
#if IS_ENABLED(CONFIG_I2C_SLAVE)
19922017
if (bus->slave) {
19932018
bus->master_or_slave = I2C_SLAVE;
1994-
return npcm_i2c_int_slave_handler(bus);
2019+
if (npcm_i2c_int_slave_handler(bus))
2020+
return IRQ_HANDLED;
19952021
}
19962022
#endif
1997-
return IRQ_NONE;
2023+
/* clear status bits for spurious interrupts */
2024+
npcm_i2c_clear_master_status(bus);
2025+
2026+
return IRQ_HANDLED;
19982027
}
19992028

20002029
static bool npcm_i2c_master_start_xmit(struct npcm_i2c *bus,
@@ -2051,7 +2080,6 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
20512080
u8 *write_data, *read_data;
20522081
u8 slave_addr;
20532082
unsigned long timeout;
2054-
int ret = 0;
20552083
bool read_block = false;
20562084
bool read_PEC = false;
20572085
u8 bus_busy;
@@ -2141,12 +2169,12 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
21412169
bus->read_block_use = read_block;
21422170

21432171
reinit_completion(&bus->cmd_complete);
2144-
if (!npcm_i2c_master_start_xmit(bus, slave_addr, nwrite, nread,
2145-
write_data, read_data, read_PEC,
2146-
read_block))
2147-
ret = -EBUSY;
21482172

2149-
if (ret != -EBUSY) {
2173+
npcm_i2c_int_enable(bus, true);
2174+
2175+
if (npcm_i2c_master_start_xmit(bus, slave_addr, nwrite, nread,
2176+
write_data, read_data, read_PEC,
2177+
read_block)) {
21502178
time_left = wait_for_completion_timeout(&bus->cmd_complete,
21512179
timeout);
21522180

@@ -2160,26 +2188,31 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
21602188
}
21612189
}
21622190
}
2163-
ret = bus->cmd_err;
21642191

21652192
/* if there was BER, check if need to recover the bus: */
21662193
if (bus->cmd_err == -EAGAIN)
2167-
ret = i2c_recover_bus(adap);
2194+
bus->cmd_err = i2c_recover_bus(adap);
21682195

21692196
/*
21702197
* After any type of error, check if LAST bit is still set,
21712198
* due to a HW issue.
21722199
* It cannot be cleared without resetting the module.
21732200
*/
2174-
if (bus->cmd_err &&
2175-
(NPCM_I2CRXF_CTL_LAST_PEC & ioread8(bus->reg + NPCM_I2CRXF_CTL)))
2201+
else if (bus->cmd_err &&
2202+
(NPCM_I2CRXF_CTL_LAST_PEC & ioread8(bus->reg + NPCM_I2CRXF_CTL)))
21762203
npcm_i2c_reset(bus);
21772204

2205+
/* after any xfer, successful or not, stall and EOB must be disabled */
2206+
npcm_i2c_stall_after_start(bus, false);
2207+
npcm_i2c_eob_int(bus, false);
2208+
21782209
#if IS_ENABLED(CONFIG_I2C_SLAVE)
21792210
/* reenable slave if it was enabled */
21802211
if (bus->slave)
21812212
iowrite8((bus->slave->addr & 0x7F) | NPCM_I2CADDR_SAEN,
21822213
bus->reg + NPCM_I2CADDR1);
2214+
#else
2215+
npcm_i2c_int_enable(bus, false);
21832216
#endif
21842217
return bus->cmd_err;
21852218
}

0 commit comments

Comments
 (0)