util/comm-i2c: Add switch to specify I2C bus

Currently, devices running CrOS EC that aren't actually the embedded
controller (such as touchpad or fingerprint MCUs) can only be contacted
over I2C if they are in the device tree. To avoid having to recompile
the Kernel, Coreboot, or `ectool`, the `--i2c_bus` switch allows
`ectool` to be used for testing as-is.

BRANCH=none
BUG=none
TEST=Checked various commands (hello, version, inventory...) with
     `--i2c_bus=7`, connecting to a MAX32660. Verified that a
     contradictory `--interface` switch is rejected. Checked that
     invalid bus numbers (≥32) are rejected.

Change-Id: I92f3307bbbdf88978b9f8271610a3ae222279767
Signed-off-by: Harry Cutts <hcutts@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1828064
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
This commit is contained in:
Harry Cutts 2019-09-25 11:20:20 -07:00 committed by Commit Bot
parent 2ee2d6fe87
commit 5f7e4c337d
4 changed files with 74 additions and 35 deletions

View File

@ -4,6 +4,7 @@
*/
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@ -31,7 +32,7 @@ static int command_offset;
int comm_init_dev(const char *device_name) __attribute__((weak));
int comm_init_lpc(void) __attribute__((weak));
int comm_init_i2c(void) __attribute__((weak));
int comm_init_i2c(int i2c_bus) __attribute__((weak));
int comm_init_servo_spi(const char *device_name) __attribute__((weak));
static int fake_readmem(int offset, int bytes, void *dest)
@ -82,8 +83,10 @@ int ec_command(int command, int version,
indata, insize);
}
int comm_init_alt(int interfaces, const char *device_name)
int comm_init_alt(int interfaces, const char *device_name, int i2c_bus)
{
bool dev_is_cros_ec;
/* Default memmap access */
ec_readmem = fake_readmem;
@ -93,17 +96,17 @@ int comm_init_alt(int interfaces, const char *device_name)
/* Do not fallback to other communication methods if target is not a
* cros_ec device */
if (!strcmp(CROS_EC_DEV_NAME, device_name)) {
/* Fallback to direct LPC on x86 */
if ((interfaces & COMM_LPC) &&
comm_init_lpc && !comm_init_lpc())
return 0;
dev_is_cros_ec = !strcmp(CROS_EC_DEV_NAME, device_name);
/* Fallback to direct i2c on ARM */
if ((interfaces & COMM_I2C) &&
comm_init_i2c && !comm_init_i2c())
return 0;
}
/* Fallback to direct LPC on x86 */
if (dev_is_cros_ec && (interfaces & COMM_LPC) &&
comm_init_lpc && !comm_init_lpc())
return 0;
/* Fallback to direct I2C */
if ((dev_is_cros_ec || i2c_bus != -1) && (interfaces & COMM_I2C) &&
comm_init_i2c && !comm_init_i2c(i2c_bus))
return 0;
/* Give up */
fprintf(stderr, "Unable to establish host communication\n");

View File

@ -39,9 +39,10 @@ enum comm_interface {
*
* @param interfaces Interfaces to try; use COMM_ALL to try all of them.
* @param device_name For DEV option, the device file to use.
* @param i2c_bus For I2C option, the bus number to use (or -1 to autodetect).
* @return 0 in case of success, or error code.
*/
int comm_init_alt(int interfaces, const char *device_name);
int comm_init_alt(int interfaces, const char *device_name, int i2c_bus);
/**
* Initialize dev interface

View File

@ -196,33 +196,44 @@ done:
return ret;
}
int comm_init_i2c(void)
int comm_init_i2c(int i2c_bus)
{
char *file_path;
char buffer[64];
int i;
/* find the device number based on the adapter name */
for (i = 0; i < I2C_MAX_ADAPTER; i++) {
FILE *f;
if (asprintf(&file_path, I2C_ADAPTER_NODE,
i, i, EC_I2C_ADDR) < 0)
if (i2c_bus != -1) {
i = i2c_bus;
if (i >= I2C_MAX_ADAPTER) {
fprintf(stderr, "Invalid I2C bus number %d. (The highest possible bus number is %d.)\n",
i, I2C_MAX_ADAPTER);
return -1;
}
} else {
/* find the device number based on the adapter name */
for (i = 0; i < I2C_MAX_ADAPTER; i++) {
FILE *f;
if (asprintf(&file_path, I2C_ADAPTER_NODE,
i, i, EC_I2C_ADDR) < 0)
return -1;
f = fopen(file_path, "r");
if (f) {
if (fgets(buffer, sizeof(buffer), f) &&
!strncmp(buffer, I2C_ADAPTER_NAME, 6)) {
free(file_path);
fclose(f);
break;
}
fclose(f);
}
free(file_path);
}
if (i == I2C_MAX_ADAPTER) {
fprintf(stderr, "Cannot find I2C adapter\n");
return -1;
f = fopen(file_path, "r");
if (f) {
if (fgets(buffer, sizeof(buffer), f) &&
!strncmp(buffer, I2C_ADAPTER_NAME, 6)) {
free(file_path);
fclose(f);
break;
}
fclose(f);
}
free(file_path);
}
if (i == I2C_MAX_ADAPTER) {
fprintf(stderr, "Cannot find I2C adapter\n");
return -1;
}
if (asprintf(&file_path, I2C_NODE, i) < 0)

View File

@ -48,6 +48,7 @@ enum {
OPT_INTERFACE,
OPT_NAME,
OPT_ASCII,
OPT_I2C_BUS,
};
static struct option long_opts[] = {
@ -55,6 +56,7 @@ static struct option long_opts[] = {
{"interface", 1, 0, OPT_INTERFACE},
{"name", 1, 0, OPT_NAME},
{"ascii", 0, 0, OPT_ASCII},
{"i2c_bus", 1, 0, OPT_I2C_BUS},
{NULL, 0, 0, 0}
};
@ -352,9 +354,13 @@ int parse_bool(const char *s, int *dest)
void print_help(const char *prog, int print_cmds)
{
printf("Usage: %s [--dev=n] [--interface=dev|i2c|lpc] ", prog);
printf("Usage: %s [--dev=n] [--interface=dev|i2c|lpc] [--i2c_bus=n]",
prog);
printf("[--name=cros_ec|cros_fp|cros_pd|cros_scp|cros_ish] [--ascii] ");
printf("<command> [params]\n\n");
printf(" --i2c_bus=n Specifies the number of an I2C bus to use. For\n"
" example, to use /dev/i2c-7, pass --i2c_bus=7.\n"
" Implies --interface=i2c.\n\n");
if (print_cmds)
puts(help_str);
else
@ -9156,6 +9162,7 @@ int main(int argc, char *argv[])
const struct command *cmd;
int dev = 0;
int interfaces = COMM_ALL;
int i2c_bus = -1;
char device_name[41] = CROS_EC_DEV_NAME;
int rv = 1;
int parse_error = 0;
@ -9197,12 +9204,29 @@ int main(int argc, char *argv[])
strncpy(device_name, optarg, 40);
device_name[40] = '\0';
break;
case OPT_I2C_BUS:
i2c_bus = strtoul(optarg, &e, 0);
if (*optarg == '\0' || (e && *e != '\0')
|| i2c_bus < 0) {
fprintf(stderr, "Invalid --i2c_bus\n");
parse_error = 1;
}
break;
case OPT_ASCII:
ascii_mode = 1;
break;
}
}
if (i2c_bus != -1) {
if (!(interfaces & COMM_I2C)) {
fprintf(stderr, "--i2c_bus is specified, but --interface is set to something other than I2C\n");
parse_error = 1;
} else {
interfaces = COMM_I2C;
}
}
/* Must specify a command */
if (!parse_error && optind == argc)
parse_error = 1;
@ -9236,7 +9260,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "Could not acquire GEC lock.\n");
exit(1);
}
if (comm_init_alt(interfaces, device_name)) {
if (comm_init_alt(interfaces, device_name, i2c_bus)) {
fprintf(stderr, "Couldn't find EC\n");
goto out;
}