diff options
author | Tony Zou <zoutao@huaqin.corp-partner.google.com> | 2019-01-29 15:29:31 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-02-19 12:46:01 -0800 |
commit | ab40ba67c55799594ef8482b16a30373bf9da53c (patch) | |
tree | 274632a553a45a958a571132ff340a21813c48c6 | |
parent | d9a3b7c58a441cfcfb32b05fe3bd112c9caf78d6 (diff) | |
download | chrome-ec-ab40ba67c55799594ef8482b16a30373bf9da53c.tar.gz |
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 <zoutao@huaqin.corp-partner.google.com>
Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
-rw-r--r-- | common/i2c_master.c | 121 | ||||
-rw-r--r-- | include/i2c.h | 29 |
2 files changed, 142 insertions, 8 deletions
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; diff --git a/include/i2c.h b/include/i2c.h index bb7f28000d..b749d04b08 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -265,6 +265,35 @@ int i2c_read8(int port, int slave_addr, int offset, int *data); int i2c_write8(int port, int slave_addr, int offset, int data); /** + * Read one or two bytes data from the slave at 8-bit slave address + * * <slaveaddr>, at 16-bit <offset> in the slave's address space. + */ +int i2c_read_offset16(int port, int slave_addr, uint16_t offset, + int *data, int len); + +/** + * Write one or two bytes data to the slave at 8-bit slave address + * <slaveaddr>, at 16-bit <offset> in the slave's address space. + */ +int i2c_write_offset16(int port, int slave_addr, uint16_t offset, + int data, int len); + +/** + * Read <len> bytes block data from the slave at 8-bit slave address + * * <slaveaddr>, at 16-bit <offset> in the slave's address space. + */ +int i2c_read_offset16_block(int port, int slave_addr, uint16_t offset, + uint8_t *data, int len); + +/** + * Write <len> bytes block data to the slave at 8-bit slave address + * <slaveaddr>, at 16-bit <offset> in the slave's address space. + */ +int i2c_write_offset16_block(int port, int slave_addr, uint16_t offset, + const uint8_t *data, int len); + + +/** * @return non-zero if i2c bus is busy */ int i2c_is_busy(int port); |