summaryrefslogtreecommitdiff
path: root/drivers/power/supply
diff options
context:
space:
mode:
authorSebastian Reichel <sebastian.reichel@collabora.com>2020-06-06 02:06:24 +0300
committerSebastian Reichel <sre@kernel.org>2020-06-19 19:38:39 +0300
commit05e0430971543e6aeb328df1226dc52930171445 (patch)
tree03123901ff5a391756d82bf3c64f8cbd07a37987 /drivers/power/supply
parent1d85f6d1b0c11f15ec2b1a9719da8118f3f94e64 (diff)
downloadlinux-05e0430971543e6aeb328df1226dc52930171445.tar.xz
power: supply: sbs-battery: use i2c_smbus_read_block_data()
The SBS battery implements SMBus block reads. Currently the driver "emulates" this by doing an I2C byte read for the length followed by an I2C block read. The I2C subsystem actually provides a proper API for doing SMBus block reads, which can and should be used instead. The current implementation does not properly handle packet error checking (PEC). Not all upstream systems using sbs-battery have I2C bus drivers supporting I2C_M_RECV_LEN, so old implementation is kept as fallback to keep things working. But this prints a warning, which hopefully results in people implementing support for it. Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Diffstat (limited to 'drivers/power/supply')
-rw-r--r--drivers/power/supply/sbs-battery.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c
index 83b9924033bd..74221b9279a9 100644
--- a/drivers/power/supply/sbs-battery.c
+++ b/drivers/power/supply/sbs-battery.c
@@ -263,8 +263,7 @@ static int sbs_read_word_data(struct i2c_client *client, u8 address)
return ret;
}
-static int sbs_read_string_data(struct i2c_client *client, u8 address,
- char *values)
+static int sbs_read_string_data_fallback(struct i2c_client *client, u8 address, char *values)
{
struct sbs_info *chip = i2c_get_clientdata(client);
s32 ret = 0, block_length = 0;
@@ -274,6 +273,8 @@ static int sbs_read_string_data(struct i2c_client *client, u8 address,
retries_length = chip->i2c_retry_count;
retries_block = chip->i2c_retry_count;
+ dev_warn_once(&client->dev, "I2C adapter does not support I2C_FUNC_SMBUS_READ_BLOCK_DATA.\n");
+
/* Adapter needs to support these two functions */
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA |
@@ -329,6 +330,32 @@ static int sbs_read_string_data(struct i2c_client *client, u8 address,
return ret;
}
+static int sbs_read_string_data(struct i2c_client *client, u8 address, char *values)
+{
+ struct sbs_info *chip = i2c_get_clientdata(client);
+ int retries = chip->i2c_retry_count;
+ int ret = 0;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BLOCK_DATA))
+ return sbs_read_string_data_fallback(client, address, values);
+
+ while (retries > 0) {
+ ret = i2c_smbus_read_block_data(client, address, values);
+ if (ret >= 0)
+ break;
+ retries--;
+ }
+
+ if (ret < 0) {
+ dev_dbg(&client->dev, "failed to read block 0x%x: %d\n", address, ret);
+ return ret;
+ }
+
+ /* add string termination */
+ values[ret] = '\0';
+ return ret;
+}
+
static int sbs_write_word_data(struct i2c_client *client, u8 address,
u16 value)
{