Add arbitrary-length read support to i2cxfer

Previously, it could only read 8 or 16 bit values

BUG=chrome-os-partner:26191
BRANCH=rambi
TEST=manual

  Counted string for battery manufacturer name:
  > i2cxfer rlen 0 0x16 0x20 16
  Data: 0653696d706c6fe1e1e1e1e1e1e1e1e1

  Read lifetime data block 1 (also tests 16-bit writes)
  > i2cxfer w16 0 0x16 0 0x60
  > i2cxfer rlen 0 0x16 0x23 32
  Data: 20d2d2d2d2948700000d0a0a060a000000020000000000000000000000000000

  Read lifetime data block 2
  > i2cxfer w16 0 0x16 0 0x61
  > i2cxfer rlen 0 0x16 0x23 27
  Data: 1b0000000000010200010c02000201000100000300002008082009

  8 and 16 bit reads still work
  > i2cxfer r 0 0x16 0x23
  0x1b [27]
  > i2cxfer r16 0 0x16 0x23
  0x001b [27]

Change-Id: Ibba5aced60c0b2de04c3f86cf5fd2ab3db1b6308
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/188379
Reviewed-by: Alec Berg <alecaberg@chromium.org>
This commit is contained in:
Randall Spangler
2014-02-28 12:39:43 -08:00
committed by chrome-internal-fetch
parent 832a0c7988
commit a35bfd69e9

View File

@@ -396,95 +396,82 @@ DECLARE_CONSOLE_COMMAND(i2cscan, command_scan,
"Scan I2C ports for devices",
NULL);
static int command_i2cxfer(int argc, char **argv)
{
int rw = 0;
int port, slave_addr, offset;
int value = 0;
int port, slave_addr;
uint8_t offset;
int v = 0;
uint8_t data[32];
char *e;
int rv = 0;
if (argc < 5) {
ccputs("Usage: i2cxfer r/r16/w/w16 port addr offset [value]\n");
return EC_ERROR_UNKNOWN;
if (argc < 5)
return EC_ERROR_PARAM_COUNT;
port = strtoi(argv[2], &e, 0);
if (*e)
return EC_ERROR_PARAM2;
slave_addr = strtoi(argv[3], &e, 0);
if (*e)
return EC_ERROR_PARAM3;
offset = strtoi(argv[4], &e, 0);
if (*e)
return EC_ERROR_PARAM4;
if (argc >= 5) {
v = strtoi(argv[5], &e, 0);
if (*e)
return EC_ERROR_PARAM5;
}
if (strcasecmp(argv[1], "r") == 0) {
rw = 0;
/* 8-bit read */
rv = i2c_read8(port, slave_addr, offset, &v);
if (!rv)
ccprintf("0x%02x [%d]\n", v);
} else if (strcasecmp(argv[1], "r16") == 0) {
rw = 1;
/* 16-bit read */
rv = i2c_read16(port, slave_addr, offset, &v);
if (!rv)
ccprintf("0x%04x [%d]\n", v);
} else if (strcasecmp(argv[1], "rlen") == 0) {
/* Arbitrary length read; param5 = len */
if (argc < 6 || v < 0 || v > sizeof(data))
return EC_ERROR_PARAM5;
i2c_lock(port, 1);
rv = i2c_xfer(port, slave_addr,
&offset, 1, data, v, I2C_XFER_SINGLE);
i2c_lock(port, 0);
if (!rv)
ccprintf("Data: %.*h\n", v, data);
} else if (strcasecmp(argv[1], "w") == 0) {
rw = 2;
/* 8-bit write */
if (argc < 6)
return EC_ERROR_PARAM5;
rv = i2c_write8(port, slave_addr, offset, v);
} else if (strcasecmp(argv[1], "w16") == 0) {
rw = 3;
/* 16-bit write */
if (argc < 6)
return EC_ERROR_PARAM5;
rv = i2c_write16(port, slave_addr, offset, v);
} else {
ccputs("Invalid rw mode : r / w / r16 / w16\n");
return EC_ERROR_INVAL;
return EC_ERROR_PARAM1;
}
port = strtoi(argv[2], &e, 0);
if (*e) {
ccputs("Invalid port\n");
return EC_ERROR_INVAL;
}
slave_addr = strtoi(argv[3], &e, 0);
if (*e) {
ccputs("Invalid slave_addr\n");
return EC_ERROR_INVAL;
}
offset = strtoi(argv[4], &e, 0);
if (*e) {
ccputs("Invalid addr\n");
return EC_ERROR_INVAL;
}
if (rw > 1) {
if (argc < 6) {
ccputs("No write value\n");
return EC_ERROR_INVAL;
}
value = strtoi(argv[5], &e, 0);
if (*e) {
ccputs("Invalid write value\n");
return EC_ERROR_INVAL;
}
}
switch (rw) {
case 0:
rv = i2c_read8(port, slave_addr, offset, &value);
break;
case 1:
rv = i2c_read16(port, slave_addr, offset, &value);
break;
case 2:
rv = i2c_write8(port, slave_addr, offset, value);
break;
case 3:
rv = i2c_write16(port, slave_addr, offset, value);
break;
}
if (rv) {
ccprintf("i2c command failed\n", rv);
return rv;
}
if (rw == 0)
ccprintf("0x%02x [%d]\n", value);
else if (rw == 1)
ccprintf("0x%04x [%d]\n", value);
ccputs("ok\n");
return EC_SUCCESS;
return rv;
}
DECLARE_CONSOLE_COMMAND(i2cxfer, command_i2cxfer,
"r/r16/w/w16 port addr offset [value]",
"r/r16/rlen/w/w16 port addr offset [value | len]",
"Read write I2C",
NULL);