summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Mooney <charliemooney@chromium.org>2012-09-05 13:58:08 -0700
committerCharlie Mooney <charliemooney@chromium.org>2012-09-05 19:23:54 -0700
commitbdd70ed2dada48d47a9e4d024708c11c75e2dda7 (patch)
tree05e47b12e9ac6e9b8749c7caf96e3fffa719ad36
parent6515d550791a246fe0ba884687b6a361b915b7d3 (diff)
downloadchrome-ec-bdd70ed2dada48d47a9e4d024708c11c75e2dda7.tar.gz
Snow:Recover from stray pulses on i2c battery line
The I2C peripheral on the EC can get confused if there is a very specific kind of noise introduced to the line. This can be manifested by jiggling the battery jack. It gets the I2C into a state where everything seems fine outwardly, but the device refuses to even transmit START bits on the line. It appears that one of the stray pulses on the i2c bus gets the device off set from the actual bytes, leaving it misinterpreting everything and waiting forever. In this case, there is only one way to recover (as you can't directly access these aspects of the internal state) and that is to do a software reset of the i2c peripheral. Here I add some code to check for the condition where the EC was unable to even send a START bit, and do a software reset of the i2c to recover. BUG=chrome-os-partner:13161 TEST=With a faulty-battery-jack-board: Boot board, test that i2c works by running "pmu" on the EC console. Jiggle battery jack repeatedly until errors are displayed on console. Try to run pmu again. Make sure that it recovers gracefully, and do this many times. BRANCH=snow Original-Change-Id: I91b8ef0c6f6079bc63f4a6a1bc91f67d19db9fc0 Signed-off-by: Charlie Mooney <charliemooney@chromium.org> (cherry picked from commit 063ea689b976506b2371b14d4a96822838b4a781) Change-Id: I309ac545d0c3a86792eea6962a3ca46cad10b2a6 Signed-off-by: Charlie Mooney <charliemooney@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/32319 Reviewed-by: David Hendricks <dhendrix@chromium.org> Reviewed-by: Che-Liang Chiou <clchiou@chromium.org>
-rw-r--r--chip/stm32/i2c.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c
index d2e1fceff4..36d0273d02 100644
--- a/chip/stm32/i2c.c
+++ b/chip/stm32/i2c.c
@@ -656,12 +656,24 @@ static void handle_i2c_error(int port, int rv)
/* Clear busy state */
t1 = get_time();
- /**
- * If the BUSY bit is faulty, send a stop bit just to be sure. It
- * seems that this can be happen very briefly while sending a 1.
- * We've not actually seen this happen, but we just want to be safe.
- */
- if (rv == EC_ERROR_TIMEOUT && !(r & 2)) {
+ if (rv == EC_ERROR_TIMEOUT && (STM32_I2C_CR1(port) & (1 << 8))) {
+ /*
+ * If it failed while just trying to send the start bit then
+ * something is wrong with the internal state of the i2c,
+ * (Probably a stray pulse on the line got it out of sync with
+ * the actual bytes) so reset it.
+ */
+ CPRINTF("Unable to send START, resetting i2c.\n");
+ STM32_I2C_CR1(I2C2) = 0x8000;
+ STM32_I2C_CR1(I2C2) = 0x0000;
+ i2c_init2();
+ goto cr_cleanup;
+ } else if (rv == EC_ERROR_TIMEOUT && !(r & 2)) {
+ /*
+ * If the BUSY bit is faulty, send a stop bit just to be sure.
+ * It seems that this can be happen very briefly while sending
+ * a 1. We've not actually seen this, but just to be safe.
+ */
CPRINTF("Bad BUSY bit detected.\n");
master_stop(port);
}