summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/lm4/i2c.c30
-rw-r--r--chip/lm4/registers.h1
2 files changed, 22 insertions, 9 deletions
diff --git a/chip/lm4/i2c.c b/chip/lm4/i2c.c
index 4a978e4a39..4a47011c15 100644
--- a/chip/lm4/i2c.c
+++ b/chip/lm4/i2c.c
@@ -92,7 +92,7 @@ static int wait_idle(int port)
task_set_event(task_get_current(), event, 0);
/* Check for errors */
- if (i & LM4_I2C_MCS_ERROR)
+ if (i & (LM4_I2C_MCS_CLKTO | LM4_I2C_MCS_ARBLST | LM4_I2C_MCS_ERROR))
return EC_ERROR_UNKNOWN;
return EC_SUCCESS;
@@ -121,15 +121,27 @@ 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))) {
+ reg_mcs = LM4_I2C_MCS(port);
+ if (!started && (reg_mcs & (LM4_I2C_MCS_CLKTO | LM4_I2C_MCS_ARBLST))) {
+ uint32_t tpr = LM4_I2C_MTPR(port);
+
+ CPRINTF("[%T I2C%d bad status 0x%02x]\n", port, reg_mcs);
+
+ /* Clock timeout or arbitration lost. Reset port to clear. */
+ LM4_SYSTEM_SRI2C |= (1 << port);
+ clock_wait_cycles(3);
+ LM4_SYSTEM_SRI2C &= ~(1 << port);
+ clock_wait_cycles(3);
+
+ /* Restore settings */
+ LM4_I2C_MCR(port) = 0x10;
+ LM4_I2C_MTPR(port) = tpr;
+
/*
- * Previous clock timeout or bus-busy. Bounce the master to
- * clear these error states.
+ * We don't know what edges the slave saw, so sleep long enough
+ * that the slave will see the new start condition below.
*/
- LM4_I2C_MCR(port) = 0;
- usleep(100000);
- LM4_I2C_MCR(port) = 0x10;
+ usleep(1000);
}
if (out) {
@@ -198,7 +210,7 @@ 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 |
+ if (LM4_I2C_MCS(port) & (LM4_I2C_MCS_CLKTO | LM4_I2C_MCS_ARBLST |
LM4_I2C_MCS_ERROR))
return EC_ERROR_UNKNOWN;
diff --git a/chip/lm4/registers.h b/chip/lm4/registers.h
index f351bb2814..1818c73a1d 100644
--- a/chip/lm4/registers.h
+++ b/chip/lm4/registers.h
@@ -254,6 +254,7 @@ static inline int lm4_fan_addr(int ch, int offset)
/* Note: USER_REG3 is used to hold pre-programming process data and should not
* be modified by EC code. See crosbug.com/p/8889. */
#define LM4_SYSTEM_USER_REG3 LM4REG(0x400fe1ec)
+#define LM4_SYSTEM_SRI2C LM4REG(0x400fe520)
#define LM4_SYSTEM_SREEPROM LM4REG(0x400fe558)
#define LM4_SYSTEM_RCGCWD LM4REG(0x400fe600)
#define LM4_SYSTEM_RCGCTIMER LM4REG(0x400fe604)