From 1e4b0b6194b3ff16233e824daa4bab18a8dcce0f Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Tue, 30 Apr 2013 12:16:39 -0700 Subject: 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 Updated to simplify protocol: Signed-off-by: Simon Glass Reviewed-on: https://gerrit.chromium.org/gerrit/49958 Commit-Queue: Doug Anderson Reviewed-by: Doug Anderson Tested-by: Doug Anderson --- util/ectool.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) (limited to 'util') 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 [write bytes...]\n" + " Perform I2C transfer on EC's I2C bus\n" " keyscan \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 = ¶ms.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 " + "[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}, -- cgit v1.2.1