summaryrefslogtreecommitdiff
path: root/driver
diff options
context:
space:
mode:
authorTing Shen <phoenixshen@google.com>2019-10-03 15:12:53 +0800
committerCommit Bot <commit-bot@chromium.org>2019-10-28 04:23:54 +0000
commitdaccb3adea9394116d7ab2c807e4a360cb5a93a1 (patch)
tree1ab613b22a459607ce71546827a8a4c4ffa7a4ae /driver
parent6841c7835416d03aefb939ff94b3e9221e81c355 (diff)
downloadchrome-ec-daccb3adea9394116d7ab2c807e4a360cb5a93a1.tar.gz
smart_battery: add smbus error checking support
Jacuzzi/Kodama has a unstable software controlled i2c bus, its data transmission may be interrupted by other higher priority tasks and causes device timeout. If timeout happens when ec is reading data, it has no knowledge about what's happening on slave, and keep receiving bad data (0xFF's) until end. The standard i2c/smbus error handling mechanism can not handle this case, so we need the error checking feature from smbus 1.1 to ensure our received data is correct. This CL adds the error checking (PEC) functions to i2c and smart battery module. BUG=b:138415463 TEST=On kodama, enable CONFIG_CMD_I2C_STRESS_TEST, no failure after 100k read/writes. test code at CL:1865054 BRANCH=master Change-Id: Ibb9ad3aa03d7690a08f59c617c2cd9c1b9cb0ff3 Signed-off-by: Ting Shen <phoenixshen@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1827138 Reviewed-by: Denis Brockus <dbrockus@chromium.org> Tested-by: Ting Shen <phoenixshen@chromium.org> Commit-Queue: Ting Shen <phoenixshen@chromium.org>
Diffstat (limited to 'driver')
-rw-r--r--driver/battery/smart.c51
1 files changed, 43 insertions, 8 deletions
diff --git a/driver/battery/smart.c b/driver/battery/smart.c
index 89a99623af..0d3d377ff8 100644
--- a/driver/battery/smart.c
+++ b/driver/battery/smart.c
@@ -21,8 +21,32 @@
static int fake_state_of_charge = -1;
+static int battery_supports_pec(void)
+{
+ static int supports_pec = -1;
+
+ if (!IS_ENABLED(CONFIG_SMBUS_PEC))
+ return 0;
+
+ if (supports_pec < 0) {
+ int spec_info;
+ int rv = i2c_read16(I2C_PORT_BATTERY, BATTERY_ADDR_FLAGS,
+ SB_SPECIFICATION_INFO, &spec_info);
+ /* failed, assuming not support and try again later */
+ if (rv)
+ return 0;
+
+ supports_pec = (BATTERY_SPEC_VERSION(spec_info) ==
+ BATTERY_SPEC_VER_1_1_WITH_PEC);
+ CPRINTS("battery supports pec: %d", supports_pec);
+ }
+ return supports_pec;
+}
+
test_mockable int sb_read(int cmd, int *param)
{
+ uint16_t addr_flags = BATTERY_ADDR_FLAGS;
+
#ifdef CONFIG_BATTERY_CUT_OFF
/*
* Some batteries would wake up after cut-off if we talk to it.
@@ -30,13 +54,16 @@ test_mockable int sb_read(int cmd, int *param)
if (battery_is_cut_off())
return EC_RES_ACCESS_DENIED;
#endif
+ if (battery_supports_pec())
+ addr_flags |= I2C_FLAG_PEC;
- return i2c_read16(I2C_PORT_BATTERY, BATTERY_ADDR_FLAGS,
- cmd, param);
+ return i2c_read16(I2C_PORT_BATTERY, addr_flags, cmd, param);
}
test_mockable int sb_write(int cmd, int param)
{
+ uint16_t addr_flags = BATTERY_ADDR_FLAGS;
+
#ifdef CONFIG_BATTERY_CUT_OFF
/*
* Some batteries would wake up after cut-off if we talk to it.
@@ -44,13 +71,16 @@ test_mockable int sb_write(int cmd, int param)
if (battery_is_cut_off())
return EC_RES_ACCESS_DENIED;
#endif
+ if (battery_supports_pec())
+ addr_flags |= I2C_FLAG_PEC;
- return i2c_write16(I2C_PORT_BATTERY, BATTERY_ADDR_FLAGS,
- cmd, param);
+ return i2c_write16(I2C_PORT_BATTERY, addr_flags, cmd, param);
}
int sb_read_string(int offset, uint8_t *data, int len)
{
+ uint16_t addr_flags = BATTERY_ADDR_FLAGS;
+
#ifdef CONFIG_BATTERY_CUT_OFF
/*
* Some batteries would wake up after cut-off if we talk to it.
@@ -58,9 +88,10 @@ int sb_read_string(int offset, uint8_t *data, int len)
if (battery_is_cut_off())
return EC_RES_ACCESS_DENIED;
#endif
+ if (battery_supports_pec())
+ addr_flags |= I2C_FLAG_PEC;
- return i2c_read_string(I2C_PORT_BATTERY, BATTERY_ADDR_FLAGS,
- offset, data, len);
+ return i2c_read_string(I2C_PORT_BATTERY, addr_flags, offset, data, len);
}
int sb_read_mfgacc(int cmd, int block, uint8_t *data, int len)
@@ -95,6 +126,8 @@ int sb_read_mfgacc(int cmd, int block, uint8_t *data, int len)
int sb_write_block(int reg, const uint8_t *val, int len)
{
+ uint16_t addr_flags = BATTERY_ADDR_FLAGS;
+
#ifdef CONFIG_BATTERY_CUT_OFF
/*
* Some batteries would wake up after cut-off if we talk to it.
@@ -103,9 +136,11 @@ int sb_write_block(int reg, const uint8_t *val, int len)
return EC_RES_ACCESS_DENIED;
#endif
+ if (battery_supports_pec())
+ addr_flags |= I2C_FLAG_PEC;
+
/* TODO: implement smbus_write_block. */
- return i2c_write_block(I2C_PORT_BATTERY, BATTERY_ADDR_FLAGS,
- reg, val, len);
+ return i2c_write_block(I2C_PORT_BATTERY, addr_flags, reg, val, len);
}
int battery_get_mode(int *mode)