summaryrefslogtreecommitdiff
path: root/util/ectool.c
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-04-30 12:16:39 -0700
committerChromeBot <chrome-bot@google.com>2013-05-09 16:36:53 -0700
commit1e4b0b6194b3ff16233e824daa4bab18a8dcce0f (patch)
treede57b1a8f1bbda6be2f515ae2a59882ef6365e23 /util/ectool.c
parentd2ca284bc6da637aabb0dbfd4a4d67451646f23a (diff)
downloadchrome-ec-1e4b0b6194b3ff16233e824daa4bab18a8dcce0f.tar.gz
Implement I2C passthru command
This is a revised version of passthru which more closely resembles the kernel interface. It allows multiple read/write messages in a single transaction, and sends back one accumulated result. BUG=chrome-os-partner:18778 BRANCH=none TEST=On link, from root shell: ectool i2cxfer 0 0xb 6 0x21 Read bytes: 0x05 0x41 0x52 0x52 0x4f 0x57 (I did not actually run this with the updated code) On pit, in U-Boot: Read i2c values: Peach # crosec i2c md 48 0 0000: 00 00 3e 00 12 20 4b bf ff ff 20 00 1e 1e 1e 1f ..>.. K... ..... Peach # crosec i2c md 48 0 20 0000: 00 00 3e 00 12 20 4b bf ff ff 20 00 1e 1e 1e 1f ..>.. K... ..... 0010: 1f 1f 1f 1f 1f 1f 20 00 00 07 00 00 00 00 00 00 ...... ......... Update value at offset 10: Peach # crosec i2c mw 48 10 4 Peach # crosec i2c md 48 0 20 0000: 00 00 3e 00 12 00 0b 1f 1f ff 20 00 1e 1e 1e 1f ..>....... ..... 0010: 04 1f 1f 1f 1f 1f 20 00 00 07 00 00 00 00 00 00 ...... ......... Peach # On pit, in kernel: localhost ~ # i2cdetect -y -a -r 20 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- localhost ~ # i2cdump -f -y 20 0x48 No size specified (using byte-data access) 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 00 00 3e 00 12 00 0b 1f 1f ff 20 00 1e 1e 1e 1f ..>.?.???. .???? 10: 1f 1f 0e 1f 1f 0e 20 00 00 07 00 00 00 00 00 00 ?????? ..?...... 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ localhost ~ # i2cset -f -y 20 0x48 0x10 0 localhost ~ # i2cdump -f -y 20 0x48 No size specified (using byte-data access) 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 00 00 3e 00 12 00 0b 1f 1f ff 20 00 1e 1e 1e 1f ..>.?.???. .???? 10: 00 1f 0e 1f 1f 0e 20 00 00 07 00 00 00 00 00 00 .????? ..?...... 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ localhost ~ # i2cset -f -y 20 0x48 0x10 0x1f localhost ~ # i2cdump -f -y 20 0x48 No size specified (using byte-data access) 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef 00: 00 00 3e 00 12 00 0b 1f 1f ff 20 00 1e 1e 1e 1f ..>.?.???. .???? 10: 1f 1f 0e 1f 1f 0e 20 00 00 07 00 00 00 00 00 00 ?????? ..?...... Change-Id: I14d47e1712828f726ac5caddc4beede251570ad3 Signed-off-by: Randall Spangler <rspangler@chromium.org> Updated to simplify protocol: Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/49958 Commit-Queue: Doug Anderson <dianders@chromium.org> Reviewed-by: Doug Anderson <dianders@chromium.org> Tested-by: Doug Anderson <dianders@chromium.org>
Diffstat (limited to 'util/ectool.c')
-rw-r--r--util/ectool.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/util/ectool.c b/util/ectool.c
index 0315b6dbb1..52b4df94d1 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -94,6 +94,8 @@ const char help_str[] =
" Read I2C bus\n"
" i2cwrite\n"
" Write I2C bus\n"
+ " i2cxfer <port> <slave_addr> <read_count> [write bytes...]\n"
+ " Perform I2C transfer on EC's I2C bus\n"
" keyscan <beat_us> <filename>\n"
" Test low-level key scanning\n"
" lightbar [CMDS]\n"
@@ -1933,6 +1935,10 @@ int cmd_i2c_read(int argc, char *argv[])
return -1;
}
+ /*
+ * TODO: use I2C_XFER command if supported, then fall back to I2C_READ
+ */
+
rv = ec_command(EC_CMD_I2C_READ, 0, &p, sizeof(p), &r, sizeof(r));
if (rv < 0)
@@ -1987,6 +1993,10 @@ int cmd_i2c_write(int argc, char *argv[])
return -1;
}
+ /*
+ * TODO: use I2C_XFER command if supported, then fall back to I2C_WRITE
+ */
+
rv = ec_command(EC_CMD_I2C_WRITE, 0, &p, sizeof(p), NULL, 0);
if (rv < 0)
@@ -1998,6 +2008,116 @@ int cmd_i2c_write(int argc, char *argv[])
}
+int cmd_i2c_xfer(int argc, char *argv[])
+{
+ union {
+ struct ec_params_i2c_passthru p;
+ uint8_t outbuf[EC_HOST_PARAM_SIZE];
+ } params;
+ union {
+ struct ec_response_i2c_passthru r;
+ uint8_t inbuf[EC_HOST_PARAM_SIZE];
+ } response;
+ struct ec_params_i2c_passthru *p = &params.p;
+ struct ec_response_i2c_passthru *r = &response.r;
+ struct ec_params_i2c_passthru_msg *msg = p->msg;
+ unsigned int addr;
+ uint8_t *pdata;
+ char *e;
+ int read_len, write_len;
+ int size;
+ int rv, i;
+
+ if (argc < 4) {
+ fprintf(stderr,
+ "Usage: %s <port> <slave_addr> <read_count> "
+ "[write bytes...]\n", argv[0]);
+ return -1;
+ }
+
+ p->port = strtol(argv[1], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad port.\n");
+ return -1;
+ }
+
+ addr = strtol(argv[2], &e, 0) & 0x7f;
+ if (e && *e) {
+ fprintf(stderr, "Bad slave address.\n");
+ return -1;
+ }
+
+ read_len = strtol(argv[3], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad read length.\n");
+ return -1;
+ }
+
+ /* Skip over params to bytes to write */
+ argc -= 4;
+ argv += 4;
+ write_len = argc;
+ p->num_msgs = (read_len != 0) + (write_len != 0);
+
+ size = sizeof(*p) + p->num_msgs * sizeof(*msg);
+ if (size + write_len > sizeof(params)) {
+ fprintf(stderr, "Params too large for buffer\n");
+ return -1;
+ }
+ if (sizeof(*r) + read_len > sizeof(response)) {
+ fprintf(stderr, "Read length too big for buffer\n");
+ return -1;
+ }
+
+ pdata = (uint8_t *)p + size;
+ if (write_len) {
+ msg->addr_flags = addr;
+ msg->len = write_len;
+
+ for (i = 0; i < write_len; i++) {
+ pdata[i] = strtol(argv[i], &e, 0);
+ if (e && *e) {
+ fprintf(stderr, "Bad write byte %d\n", i);
+ return -1;
+ }
+ }
+ msg++;
+ }
+
+ if (read_len) {
+ msg->addr_flags = addr | EC_I2C_FLAG_READ;
+ msg->len = read_len;
+ }
+
+ rv = ec_command(EC_CMD_I2C_PASSTHRU, 0, p, size + write_len,
+ r, sizeof(*r) + read_len);
+ if (rv < 0)
+ return rv;
+
+ /* Parse response */
+ if (r->i2c_status & (EC_I2C_STATUS_NAK | EC_I2C_STATUS_TIMEOUT)) {
+ fprintf(stderr, "Transfer failed with status=0x%x\n",
+ r->i2c_status);
+ return -1;
+ }
+
+ if (rv < sizeof(*r) + read_len) {
+ fprintf(stderr, "Truncated read response\n");
+ return -1;
+ }
+
+ if (read_len) {
+ printf("Read bytes:");
+ for (i = 0; i < read_len; i++)
+ printf(" %#02x", r->data[i]);
+ printf("\n");
+ } else {
+ printf("Write successful.\n");
+ }
+
+ return 0;
+}
+
int cmd_lcd_backlight(int argc, char *argv[])
{
struct ec_params_switch_enable_backlight p;
@@ -2787,6 +2907,7 @@ const struct command commands[] = {
{"kbpress", cmd_kbpress},
{"i2cread", cmd_i2c_read},
{"i2cwrite", cmd_i2c_write},
+ {"i2cxfer", cmd_i2c_xfer},
{"lightbar", cmd_lightbar},
{"keyconfig", cmd_keyconfig},
{"keyscan", cmd_keyscan},