summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTony Zou <zoutao@huaqin.corp-partner.google.com>2019-01-29 15:29:31 +0800
committerchrome-bot <chrome-bot@chromium.org>2019-02-19 12:46:01 -0800
commitab40ba67c55799594ef8482b16a30373bf9da53c (patch)
tree274632a553a45a958a571132ff340a21813c48c6
parentd9a3b7c58a441cfcfb32b05fe3bd112c9caf78d6 (diff)
downloadchrome-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.c121
-rw-r--r--include/i2c.h29
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);