diff options
author | Mulin Chao <mlchao@nuvoton.com> | 2017-01-17 10:00:03 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-01-18 22:51:06 -0800 |
commit | da2e9e86f7ac1f98b1f918a918c4cc54fc15e8fc (patch) | |
tree | 470b342d0ec15524dc03f44c0c58a69729426fcd | |
parent | 6de8d02fa82d8de86f10c61ca1def9b7dab0561b (diff) | |
download | chrome-ec-da2e9e86f7ac1f98b1f918a918c4cc54fc15e8fc.tar.gz |
npcx: i2c: handle BER & SDAST in SMBST occur at the same time.
In rare case, if a bus error indicates a conflict on the data
line (SDA) is detected during transmission of the byte. (i.e.,
SDA is toggling during holding data period.) and SDAST are
set at the same time, the i2c driver is not good enough to handle
it. Ec will get stuck in i2c ISR forever since SDAST util
watchdog reset occurs.
This CL includes:
1. Do a dummy read to make sure i2c slave doesn't hold i2c bus.
It makes sure i2c master can generate STOP successfully.
2. Disable smb's interrupts in "A Bus Error has been identified".
Once bus error occurred, it's better to forbid ec to enter
ISR again. Let i2c_recovery() disable the module and reset
hardware state machine to the default.
BRANCH=none
BUG=chrome-os-partner:59294
TEST=test i2c console commands on wheatley for hours.
Change-Id: Iecadcd866e115e31b18dfd68359a018867cac40e
Signed-off-by: Mulin Chao <mlchao@nuvoton.com>
Reviewed-on: https://chromium-review.googlesource.com/428482
Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r-- | chip/npcx/i2c.c | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/chip/npcx/i2c.c b/chip/npcx/i2c.c index 60cf59b1d5..2a394c7cfb 100644 --- a/chip/npcx/i2c.c +++ b/chip/npcx/i2c.c @@ -500,19 +500,33 @@ static void i2c_handle_sda_irq(int controller) void i2c_master_int_handler (int controller) { volatile struct i2c_status *p_status = i2c_stsobjs + controller; + /* Condition 1 : A Bus Error has been identified */ if (IS_BIT_SET(NPCX_SMBST(controller), NPCX_SMBST_BER)) { + uint8_t __attribute__((unused)) data; /* Generate a STOP condition */ I2C_STOP(controller); CPUTS("-SP"); /* Clear BER Bit */ SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_BER); + /* Mask sure slave doesn't hold bus by dummy reading */ + I2C_READ_BYTE(controller, data); + /* Set error code */ p_status->err_code = SMB_BUS_ERROR; /* Notify upper layer */ p_status->oper_state = SMB_IDLE; task_set_event(p_status->task_waiting, TASK_EVENT_I2C_IDLE, 0); CPUTS("-BER"); + + /* + * Disable smb's interrupts to forbid ec to enter ISR again + * before executing error recovery. + */ + task_disable_irq(i2c_irqs[controller]); + + /* return for executing error recovery immediately */ + return; } /* Condition 2: A negative acknowledge has occurred */ |