diff options
-rw-r--r-- | chip/lm4/i2c.c | 31 | ||||
-rw-r--r-- | common/tmp006.c | 17 |
2 files changed, 43 insertions, 5 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; } diff --git a/common/tmp006.c b/common/tmp006.c index b4a1a8b967..3cda55ac1a 100644 --- a/common/tmp006.c +++ b/common/tmp006.c @@ -169,7 +169,10 @@ static int tmp006_poll_sensor(int sensor_id) */ if (tdata->fail && (FAIL_POWER | FAIL_INIT)) { rv = i2c_read16(TMP006_PORT(addr), TMP006_REG(addr), 0x02, &v); - if (!(v & 0x80)) { + if (rv) { + tdata->fail |= FAIL_I2C; + return EC_ERROR_UNKNOWN; + } else if (!(v & 0x80)) { tdata->fail |= FAIL_NOT_READY; return EC_ERROR_UNKNOWN; } @@ -222,8 +225,16 @@ int tmp006_get_val(int idx, int *temp_ptr) int tidx = idx >> 1; const struct tmp006_data_t *tdata = tmp006_data + tidx; - if (tdata->fail & FAIL_POWER) - return EC_ERROR_NOT_POWERED; + if (tdata->fail & FAIL_POWER) { + /* + * Sensor isn't powered, or hasn't successfully provided data + * since being powered. Keep reporting not-powered until + * we get good data (which will clear FAIL_POWER) or there is + * an I2C error. + */ + return (tdata->fail & FAIL_I2C) ? EC_ERROR_UNKNOWN : + EC_ERROR_NOT_POWERED; + } /* Check the low bit to determine which temperature to read. */ if ((idx & 0x1) == 0) |