diff options
-rw-r--r-- | drivers/i2c/busses/i2c-npcm7xx.c | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c index 2b76dbfba438..7620bdcdc235 100644 --- a/drivers/i2c/busses/i2c-npcm7xx.c +++ b/drivers/i2c/busses/i2c-npcm7xx.c @@ -334,6 +334,7 @@ struct npcm_i2c { u64 nack_cnt; u64 timeout_cnt; u64 tx_complete_cnt; + bool ber_state; /* Indicate the bus error state */ }; static inline void npcm_i2c_select_bank(struct npcm_i2c *bus, @@ -1521,6 +1522,7 @@ static void npcm_i2c_irq_handle_ber(struct npcm_i2c *bus) if (npcm_i2c_is_master(bus)) { npcm_i2c_master_abort(bus); } else { + bus->ber_state = true; npcm_i2c_clear_master_status(bus); /* Clear BB (BUS BUSY) bit */ @@ -1699,6 +1701,7 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap) 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; } @@ -1763,6 +1766,7 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap) if (bus->rec_succ_cnt < ULLONG_MAX) bus->rec_succ_cnt++; } + bus->ber_state = false; return status; } @@ -2158,7 +2162,16 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } while (time_is_after_jiffies(time_left) && bus_busy); - if (bus_busy) { + /* + * 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); |