mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-11 18:35:28 +00:00
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>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user