summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMulin Chao <mlchao@nuvoton.com>2017-01-17 10:00:03 +0800
committerchrome-bot <chrome-bot@chromium.org>2017-01-18 22:51:06 -0800
commitda2e9e86f7ac1f98b1f918a918c4cc54fc15e8fc (patch)
tree470b342d0ec15524dc03f44c0c58a69729426fcd
parent6de8d02fa82d8de86f10c61ca1def9b7dab0561b (diff)
downloadchrome-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.c14
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 */