| From b0118105725eb30a96102d135dafcb94956b05bf Mon Sep 17 00:00:00 2001 |
| From: Tyrone Ting <kfting@nuvoton.com> |
| Date: Tue, 1 Oct 2024 14:28:51 +0800 |
| Subject: [PATCH 2/6] i2c: npcm: use a software flag to indicate a BER |
| condition |
| |
| If not clearing the BB (bus busy) condition in the BER (bus error) |
| interrupt, the driver causes a timeout and hence the i2c core |
| doesn't do the i2c transfer retry but returns the driver's return |
| value to the upper layer instead. |
| |
| Clear the BB condition in the BER interrupt and a software flag is |
| used. The driver does an i2c recovery without causing the timeout |
| if the flag is set. |
| |
| Upstream-Status: Accepted |
| Signed-off-by: Tyrone Ting <kfting@nuvoton.com> |
| Reviewed-by: Tali Perry <tali.perry1@gmail.com> |
| Signed-off-by: Andi Shyti <andi.shyti@kernel.org> |
| --- |
| drivers/i2c/busses/i2c-npcm7xx.c | 15 ++++++++++++++- |
| 1 file changed, 14 insertions(+), 1 deletion(-) |
| |
| 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); |
| -- |
| 2.48.1.502.g6dc24dfdaf-goog |
| |