From ab40ba67c55799594ef8482b16a30373bf9da53c Mon Sep 17 00:00:00 2001 From: Tony Zou Date: Tue, 29 Jan 2019 15:29:31 +0800 Subject: i2c: Support 16-bit address register read & write wireless receiver charger IDT P9221 I2C reg addr is 16bit. command i2cxfer r/r16/w/w16 port offset [value] When offset is 4 digit (e.g. 0x00ab), it reads/writes 16 bit offset registers. Otherwise, it reads/writes 8-bit offset registers. BRANCH=none BUG=b:123504007 TEST=1:) Build flapjack EC and flash to DUT , EC can read/write P9221 register. 2:) Build kukui EC , build pass. TEST=buildall Change-Id: If0df532f5ca136bf1312a1857b13e8455e897943 Reviewed-on: https://chromium-review.googlesource.com/1445133 Commit-Ready: Tony Zou Tested-by: Daisuke Nojiri Reviewed-by: Daisuke Nojiri --- common/i2c_master.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 113 insertions(+), 8 deletions(-) (limited to 'common') diff --git a/common/i2c_master.c b/common/i2c_master.c index c2cc22f06c..5f84cc8e9f 100644 --- a/common/i2c_master.c +++ b/common/i2c_master.c @@ -304,6 +304,98 @@ int i2c_write8(int port, int slave_addr, int offset, int data) return i2c_xfer(port, slave_addr, buf, 2, 0, 0); } +int i2c_read_offset16(int port, int slave_addr, uint16_t offset, + int *data, int len) +{ + int rv; + uint8_t buf[sizeof(uint16_t)], addr[sizeof(uint16_t)]; + + if (len < 0 || len > 2) + return EC_ERROR_INVAL; + + addr[0] = (offset >> 8) & 0xff; + addr[1] = offset & 0xff; + + /* I2C read 16-bit word: transmit 16-bit offset, and read buffer */ + rv = i2c_xfer(port, slave_addr, addr, 2, buf, len); + + if (rv) + return rv; + + if (len == 1) { + *data = buf[0]; + } else { + if (slave_addr & I2C_FLAG_BIG_ENDIAN) + *data = ((int)buf[0] << 8) | buf[1]; + else + *data = ((int)buf[1] << 8) | buf[0]; + } + + return EC_SUCCESS; +} + +int i2c_write_offset16(int port, int slave_addr, uint16_t offset, + int data, int len) +{ + uint8_t buf[2 + sizeof(uint16_t)]; + + if (len < 0 || len > 2) + return EC_ERROR_INVAL; + + + buf[0] = (offset >> 8) & 0xff; + buf[1] = offset & 0xff; + + if (len == 1) { + buf[2] = data & 0xff; + } else { + if (slave_addr & I2C_FLAG_BIG_ENDIAN) { + buf[2] = (data >> 8) & 0xff; + buf[3] = data & 0xff; + } else { + buf[2] = data & 0xff; + buf[3] = (data >> 8) & 0xff; + } + } + + return i2c_xfer(port, slave_addr, buf, 2 + len, NULL, 0); +} + +int i2c_read_offset16_block(int port, int slave_addr, uint16_t offset, + uint8_t *data, int len) +{ + uint8_t addr[sizeof(uint16_t)]; + + addr[0] = (offset >> 8) & 0xff; + addr[1] = offset & 0xff; + + return i2c_xfer(port, slave_addr, addr, 2, data, len); +} + +int i2c_write_offset16_block(int port, int slave_addr, uint16_t offset, + const uint8_t *data, int len) +{ + int rv; + uint8_t addr[sizeof(uint16_t)]; + + addr[0] = (offset >> 8) & 0xff; + addr[1] = offset & 0xff; + + /* + * Split into two transactions to avoid the stack space consumption of + * appending the destination address with the data array. + */ + i2c_lock(port, 1); + rv = i2c_xfer_unlocked(port, slave_addr, addr, 2, NULL, 0, + I2C_XFER_START); + if (!rv) + rv = i2c_xfer_unlocked(port, slave_addr, data, len, NULL, 0, + I2C_XFER_STOP); + i2c_lock(port, 0); + + return rv; +} + int i2c_read_string(int port, int slave_addr, int offset, uint8_t *data, int len) { @@ -910,7 +1002,8 @@ DECLARE_CONSOLE_COMMAND(i2cscan, command_scan, static int command_i2cxfer(int argc, char **argv) { int port, slave_addr; - uint8_t offset; + uint16_t offset = 0; + uint8_t offset_size = 0; int v = 0; uint8_t data[32]; char *e; @@ -931,6 +1024,8 @@ static int command_i2cxfer(int argc, char **argv) if (*e) return EC_ERROR_PARAM4; + offset_size = (strlen(argv[4]) == 6) ? 2 : 1; + if (argc >= 6) { v = strtoi(argv[5], &e, 0); if (*e) @@ -939,13 +1034,19 @@ static int command_i2cxfer(int argc, char **argv) if (strcasecmp(argv[1], "r") == 0) { /* 8-bit read */ - rv = i2c_read8(port, slave_addr, offset, &v); + if(offset_size == 2) + rv = i2c_read_offset16(port, slave_addr, offset, &v, 1); + else + rv = i2c_read8(port, slave_addr, offset, &v); if (!rv) ccprintf("0x%02x [%d]\n", v, v); } else if (strcasecmp(argv[1], "r16") == 0) { /* 16-bit read */ - rv = i2c_read16(port, slave_addr, offset, &v); + if(offset_size == 2) + rv = i2c_read_offset16(port, slave_addr, offset, &v, 2); + else + rv = i2c_read16(port, slave_addr, offset, &v); if (!rv) ccprintf("0x%04x [%d]\n", v, v); @@ -954,7 +1055,7 @@ static int command_i2cxfer(int argc, char **argv) if (argc < 6 || v < 0 || v > sizeof(data)) return EC_ERROR_PARAM5; - rv = i2c_xfer(port, slave_addr, &offset, 1, data, v); + rv = i2c_xfer(port, slave_addr, (uint8_t*)&offset, 1, data, v); if (!rv) ccprintf("Data: %.*h\n", v, data); @@ -963,15 +1064,19 @@ static int command_i2cxfer(int argc, char **argv) /* 8-bit write */ if (argc < 6) return EC_ERROR_PARAM5; - - rv = i2c_write8(port, slave_addr, offset, v); + if(offset_size == 2) + rv = i2c_write8(port, slave_addr, offset, v); + else + rv = i2c_write_offset16(port, slave_addr, offset, v, 1); } else if (strcasecmp(argv[1], "w16") == 0) { /* 16-bit write */ if (argc < 6) return EC_ERROR_PARAM5; - - rv = i2c_write16(port, slave_addr, offset, v); + if(offset_size == 2) + rv = i2c_write16(port, slave_addr, offset, v); + else + rv = i2c_write_offset16(port, slave_addr, offset, v, 2); } else { return EC_ERROR_PARAM1; -- cgit v1.2.1