diff options
author | Simon Glass <sjg@chromium.org> | 2020-12-23 12:25:50 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-12-24 17:37:04 +0000 |
commit | ee2b0bcd66589e9d72eed553274f8da3d737c76c (patch) | |
tree | cb3de8dfee8e84281516444630de8f30216e721b /common/i2c_controller.c | |
parent | 817cb64cfd2623ac233b953f7bcca5e85c2f2409 (diff) | |
download | chrome-ec-ee2b0bcd66589e9d72eed553274f8da3d737c76c.tar.gz |
zephyr: Support multi-step I2C transactions
At present the Zephyr implementation of i2c_xfer_unlocked() assumes
this is the only call for the whole transaction. However in some cases
the function is called several times, e.g. to write a register number,
read a length, then read that number of bytes).
Add support for this, so i2c_read_string() works, for example.
BUG=b:176189170
TEST=build and boot on volteer, with Nuvoton's I2C fix
See that LION is shown as such, and not LIO
> battery
Status: 0x0080 INIT
Param flags:00000003
Temp: 0x0bb7 = %.1d K (%.1d C)
V: 0x31f6 = 12790 mV
V-desired: 0x3390 = 13200 mV
I: 0x00ac = 172 mA(CHG)
I-desired: 0x0a19 = 2585 mA
Charging: Allowed
Charge: 92 %
Manuf: LGC
Device: AC17A8M
Chem: LION
Serial: 0xb754
V-design: 0x2d1e = 11550 mV
Mode: 0x6001
Abs charge:87 %
Remaining: 4648 mAh
Cap-full: 5040 mAh (4939 mAh with 98 % compensation)
Display: 96.9 %
Design: 5360 mAh
Time-full: 2h:47
Empty: 0h:0
Signed-off-by: Simon Glass <sjg@chromium.org>
Change-Id: I1fe08c0c919a98fa66510048d4c05ae6e10072d9
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2600933
Reviewed-by: Mulin Chao <mlchao@nuvoton.com>
Reviewed-by: Paul Fagerburg <pfagerburg@chromium.org>
Diffstat (limited to 'common/i2c_controller.c')
-rw-r--r-- | common/i2c_controller.c | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/common/i2c_controller.c b/common/i2c_controller.c index 49a6cf0458..a76c58691a 100644 --- a/common/i2c_controller.c +++ b/common/i2c_controller.c @@ -201,8 +201,45 @@ int i2c_xfer_unlocked(const int port, for (i = 0; i <= CONFIG_I2C_NACK_RETRY_COUNT; i++) { #ifdef CONFIG_ZEPHYR - ret = i2c_write_read(i2c_get_device_for_port(port), no_pec_af, - out, out_size, in, in_size); + struct i2c_msg msg[2]; + int num_msgs = 0; + + /* Be careful to respect the flags passed in */ + if (out_size) { + unsigned int wflags = I2C_MSG_WRITE; + + msg[num_msgs].buf = (uint8_t *)out; + msg[num_msgs].len = out_size; + + /* If this is the last write, add a stop */ + if (!in_size && (flags & I2C_XFER_STOP)) + wflags |= I2C_MSG_STOP; + msg[num_msgs].flags = wflags; + num_msgs++; + } + if (in_size) { + unsigned int rflags = I2C_MSG_READ; + + msg[num_msgs].buf = (uint8_t *)in; + msg[num_msgs].len = in_size; + rflags = I2C_MSG_READ; + + /* If a stop is requested, add it */ + if (flags & I2C_XFER_STOP) + rflags |= I2C_MSG_STOP; + + /* + * If this read follows a write (above) then we need a + * restart + */ + if (num_msgs) + rflags |= I2C_MSG_RESTART; + msg[num_msgs].flags = rflags; + num_msgs++; + } + + return i2c_transfer(i2c_get_device_for_port(port), msg, + num_msgs, no_pec_af); #elif defined(CONFIG_I2C_XFER_LARGE_TRANSFER) ret = i2c_xfer_no_retry(port, no_pec_af, out, out_size, in, |