From 0a807638423e72032e0e4e21f0dfa0059a9e94a6 Mon Sep 17 00:00:00 2001 From: Caveh Jalali Date: Tue, 21 Sep 2021 17:14:46 -0700 Subject: ectool: Implement I2C speed control command This adds the new "i2cspeed" command. The command takes an I2C port (bus) number as an argument. Without a 2nd argument, the current I2C speed is reported. If a 2nd argument is given, the I2C bus speed accordingly, the unit is assumed to be Kbps. In practice, only 3 speeds are supported: 100, 400, 1000 kHz. BRANCH=none BUG=b:201039003 TEST=with follow-on patches, switched I2C bus speed between 400 kHz and 1 MHz using ectool. Change-Id: I80cd436c85c368f13357a4a80c3179e1fb483cb1 Signed-off-by: Caveh Jalali Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3181508 Reviewed-by: Daisuke Nojiri Reviewed-by: Boris Mittelberg --- util/ectool.c | 3 ++ util/ectool.h | 1 + util/ectool_i2c.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/util/ectool.c b/util/ectool.c index 8d338c04ff..01d3605afd 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -184,6 +184,8 @@ const char help_str[] = " Protect EC's I2C bus\n" " i2cread\n" " Read I2C bus\n" + " i2cspeed [speed]\n" + " Get or set EC's I2C bus speed\n" " i2cwrite\n" " Write I2C bus\n" " i2cxfer [write bytes...]\n" @@ -10444,6 +10446,7 @@ const struct command commands[] = { {"locatechip", cmd_locate_chip}, {"i2cprotect", cmd_i2c_protect}, {"i2cread", cmd_i2c_read}, + {"i2cspeed", cmd_i2c_speed}, {"i2cwrite", cmd_i2c_write}, {"i2cxfer", cmd_i2c_xfer}, {"infopddev", cmd_pd_device_info}, diff --git a/util/ectool.h b/util/ectool.h index a0cc0c72a0..c76e1652cc 100644 --- a/util/ectool.h +++ b/util/ectool.h @@ -46,5 +46,6 @@ extern int ascii_mode; int cmd_i2c_protect(int argc, char *argv[]); int cmd_i2c_read(int argc, char *argv[]); +int cmd_i2c_speed(int argc, char *argv[]); int cmd_i2c_write(int argc, char *argv[]); int cmd_i2c_xfer(int argc, char *argv[]); diff --git a/util/ectool_i2c.c b/util/ectool_i2c.c index cf016d44a8..97e47e6e85 100644 --- a/util/ectool_i2c.c +++ b/util/ectool_i2c.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -122,6 +123,7 @@ static void cmd_i2c_help(void) { fprintf(stderr, " Usage: i2cread <8 | 16> \n" + " Usage: i2cspeed [speed in kHz]\n" " Usage: i2cwrite <8 | 16> \n" " Usage: i2cxfer [bytes...]\n" " i2c port number\n" @@ -319,3 +321,91 @@ int cmd_i2c_xfer(int argc, char *argv[]) return 0; } + +static int i2c_get(int port) +{ + struct ec_params_i2c_control p; + struct ec_response_i2c_control r; + uint16_t speed_khz; + int rv; + + memset(&p, 0, sizeof(p)); + p.port = port; + p.cmd = EC_I2C_CONTROL_GET_SPEED; + + rv = ec_command(EC_CMD_I2C_CONTROL, 0, &p, sizeof(p), &r, sizeof(r)); + if (rv < 0) + return rv; + + speed_khz = r.cmd_response.speed_khz; + if (speed_khz == EC_I2C_CONTROL_SPEED_UNKNOWN) + printf("I2C port %d: speed: unknown\n", port); + else + printf("I2C port %d: speed: %u kHz\n", port, speed_khz); + + return 0; +} + +static int i2c_set(int port, int new_speed_khz) +{ + struct ec_params_i2c_control p; + struct ec_response_i2c_control r; + uint16_t old_speed_khz; + int rv; + + if ((new_speed_khz == EC_I2C_CONTROL_SPEED_UNKNOWN) || + (new_speed_khz < 0 || new_speed_khz > UINT16_MAX)) { + fprintf(stderr, "I2C speed %d kHz is not supported\n", + new_speed_khz); + return -1; + } + + memset(&p, 0, sizeof(p)); + p.port = port; + p.cmd = EC_I2C_CONTROL_SET_SPEED; + p.cmd_params.speed_khz = new_speed_khz; + + rv = ec_command(EC_CMD_I2C_CONTROL, 0, &p, sizeof(p), &r, sizeof(r)); + if (rv < 0) + return rv; + + old_speed_khz = r.cmd_response.speed_khz; + if (old_speed_khz == EC_I2C_CONTROL_SPEED_UNKNOWN) { + printf("Port %d speed set to %d kHz\n", port, new_speed_khz); + } else { + printf("Port %d speed changed from %u kHz to %d kHz\n", port, + old_speed_khz, + new_speed_khz); + } + + return 0; +} + +int cmd_i2c_speed(int argc, char *argv[]) +{ + unsigned int port, speed; + char *e; + + if (argc < 2 || argc > 3) { + cmd_i2c_help(); + return -1; + } + + port = strtol(argv[1], &e, 0); + if (e && *e) { + fprintf(stderr, "Bad port.\n"); + return -1; + } + + if (argc == 2) + return i2c_get(port); + + speed = strtol(argv[2], &e, 0); + if (e && *e) { + fprintf(stderr, "Bad speed. " + "Typical speeds are one of {100,400,1000}.\n"); + return -1; + } + + return i2c_set(port, speed); +} -- cgit v1.2.1