diff options
author | Randall Spangler <rspangler@chromium.org> | 2012-11-20 18:31:54 -0800 |
---|---|---|
committer | Gerrit <chrome-bot@google.com> | 2012-11-26 14:49:49 -0800 |
commit | e2f84669979f63df4a11d78caee9abf3e9b1724a (patch) | |
tree | 421b42c02cd9b30eb69db6feb9070dfae21e6e29 /chip | |
parent | 3c575ccb02ff58eaae3e7c3dd8e2e86ad25ac106 (diff) | |
download | chrome-ec-e2f84669979f63df4a11d78caee9abf3e9b1724a.tar.gz |
Handle bus errors on thermal I2C bus
1) Properly report I2C errors on TMP006 as error, not device-not-powered.
2) Treat clock timeout and bus-busy I2C status as error (previously ignored).
3) If clock timeout or bus-busy, reset I2C master for that bus to clear the
error.
These should help with systems where the thermal I2C bus gets into a
weird state on suspend/resume.
BUG=chrome-os-partner:16262
BRANCH=link
TEST=boot system; 'battery' and 'temps' should give good info
Then run snanda's suspend_stress_test for a while and repeat.
Change-Id: I534be8236a4d6de82575fe6d33a68502ce0a3a95
Original-Change-Id: Iec5d6bbd357d2e5eb3dc3d361c829f353e996ab6
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/38444
Reviewed-on: https://gerrit.chromium.org/gerrit/38659
Reviewed-by: Yung-Chieh Lo <yjlou@chromium.org>
Diffstat (limited to 'chip')
-rw-r--r-- | chip/lm4/i2c.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/chip/lm4/i2c.c b/chip/lm4/i2c.c index 7f0fa19c95..4a978e4a39 100644 --- a/chip/lm4/i2c.c +++ b/chip/lm4/i2c.c @@ -21,6 +21,7 @@ #define NUM_PORTS 6 /* Number of physical ports */ +/* Flags for writes to MCS */ #define LM4_I2C_MCS_RUN (1 << 0) #define LM4_I2C_MCS_START (1 << 1) #define LM4_I2C_MCS_STOP (1 << 2) @@ -28,6 +29,16 @@ #define LM4_I2C_MCS_HS (1 << 4) #define LM4_I2C_MCS_QCMD (1 << 5) +/* Flags for reads from MCS */ +#define LM4_I2C_MCS_BUSY (1 << 0) +#define LM4_I2C_MCS_ERROR (1 << 1) +#define LM4_I2C_MCS_ADRACK (1 << 2) +#define LM4_I2C_MCS_DATACK (1 << 3) +#define LM4_I2C_MCS_ARBLST (1 << 4) +#define LM4_I2C_MCS_IDLE (1 << 5) +#define LM4_I2C_MCS_BUSBSY (1 << 6) +#define LM4_I2C_MCS_CLKTO (1 << 7) + #define START 1 #define STOP 1 #define NO_START 0 @@ -49,7 +60,7 @@ static int wait_idle(int port) int event = 0; i = LM4_I2C_MCS(port); - while (i & 0x01) { + while (i & LM4_I2C_MCS_BUSY) { /* Port is busy, so wait for the interrupt */ task_waiting_on_port[port] = task_get_current(); LM4_I2C_MIMR(port) = 0x03; @@ -81,7 +92,7 @@ static int wait_idle(int port) task_set_event(task_get_current(), event, 0); /* Check for errors */ - if (i & 0x02) + if (i & LM4_I2C_MCS_ERROR) return EC_ERROR_UNKNOWN; return EC_SUCCESS; @@ -110,6 +121,17 @@ static int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size, if (out_size == 0 && in_size == 0) return EC_SUCCESS; + if (!started && (LM4_I2C_MCS(port) & + (LM4_I2C_MCS_CLKTO | LM4_I2C_MCS_BUSBSY))) { + /* + * Previous clock timeout or bus-busy. Bounce the master to + * clear these error states. + */ + LM4_I2C_MCR(port) = 0; + usleep(100000); + LM4_I2C_MCR(port) = 0x10; + } + if (out) { LM4_I2C_MSA(port) = slave_addr & 0xff; for (i = 0; i < out_size; i++) { @@ -175,6 +197,11 @@ static int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size, } } + /* Check for error conditions */ + if (LM4_I2C_MCS(port) & (LM4_I2C_MCS_CLKTO | LM4_I2C_MCS_BUSBSY | + LM4_I2C_MCS_ERROR)) + return EC_ERROR_UNKNOWN; + return EC_SUCCESS; } |