1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 /* Useful direct commands to the EC host interface */ 17 18 #define LOG_TAG "fwtool" 19 20 #include <errno.h> 21 #include <stdint.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 #include "ec_commands.h" 27 #include "debug_cmd.h" 28 #include "flash_device.h" 29 #include "update_log.h" 30 31 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 32 33 static void *ec; 34 35 static void *get_ec(void) 36 { 37 if (!ec) 38 ec = flash_open("ec", NULL); 39 40 return ec; 41 } 42 43 static int ec_readmem(int offset, int bytes, void *dest) 44 { 45 struct ec_params_read_memmap r_mem; 46 int r; 47 48 r_mem.offset = offset; 49 r_mem.size = bytes; 50 return flash_cmd(ec, EC_CMD_READ_MEMMAP, 0, 51 &r_mem, sizeof(r_mem), dest, bytes); 52 } 53 54 static uint8_t ec_readmem8(int offset) 55 { 56 uint8_t val; 57 int ret; 58 ret = ec_readmem(offset, sizeof(val), &val); 59 return ret ? 0 : val; 60 } 61 62 static uint32_t ec_readmem32(int offset) 63 { 64 uint32_t val; 65 int ret; 66 ret = ec_readmem(offset, sizeof(val), &val); 67 return ret ? 0 : val; 68 } 69 70 static int cmd_ec_battery(int argc, const char **argv) 71 { 72 char batt_text[EC_MEMMAP_TEXT_MAX + 1]; 73 uint32_t val; 74 75 if (!get_ec()) 76 return -ENODEV; 77 78 printf("Battery info:\n"); 79 80 val = ec_readmem8(EC_MEMMAP_BATTERY_VERSION); 81 if (val < 1) { 82 fprintf(stderr, "Battery version %d is not supported\n", val); 83 return -EINVAL; 84 } 85 86 memset(batt_text, 0, EC_MEMMAP_TEXT_MAX + 1); 87 ec_readmem(EC_MEMMAP_BATT_MFGR, sizeof(batt_text), batt_text); 88 printf(" OEM name: %s\n", batt_text); 89 ec_readmem(EC_MEMMAP_BATT_MODEL, sizeof(batt_text), batt_text); 90 printf(" Model number: %s\n", batt_text); 91 printf(" Chemistry : %s\n", batt_text); 92 ec_readmem(EC_MEMMAP_BATT_SERIAL, sizeof(batt_text), batt_text); 93 printf(" Serial number: %s\n", batt_text); 94 val = ec_readmem32(EC_MEMMAP_BATT_DCAP); 95 printf(" Design capacity: %u mAh\n", val); 96 val = ec_readmem32(EC_MEMMAP_BATT_LFCC); 97 printf(" Last full charge: %u mAh\n", val); 98 val = ec_readmem32(EC_MEMMAP_BATT_DVLT); 99 printf(" Design output voltage %u mV\n", val); 100 val = ec_readmem32(EC_MEMMAP_BATT_CCNT); 101 printf(" Cycle count %u\n", val); 102 val = ec_readmem32(EC_MEMMAP_BATT_VOLT); 103 printf(" Present voltage %u mV\n", val); 104 val = ec_readmem32(EC_MEMMAP_BATT_RATE); 105 printf(" Present current %u mA\n", val); 106 val = ec_readmem32(EC_MEMMAP_BATT_CAP); 107 printf(" Remaining capacity %u mAh\n", val); 108 val = ec_readmem8(EC_MEMMAP_BATT_FLAG); 109 printf(" Flags 0x%02x", val); 110 if (val & EC_BATT_FLAG_AC_PRESENT) 111 printf(" AC_PRESENT"); 112 if (val & EC_BATT_FLAG_BATT_PRESENT) 113 printf(" BATT_PRESENT"); 114 if (val & EC_BATT_FLAG_DISCHARGING) 115 printf(" DISCHARGING"); 116 if (val & EC_BATT_FLAG_CHARGING) 117 printf(" CHARGING"); 118 if (val & EC_BATT_FLAG_LEVEL_CRITICAL) 119 printf(" LEVEL_CRITICAL"); 120 printf("\n"); 121 122 return 0; 123 } 124 125 /* BQ25892 I2C registers */ 126 #define BQ2589X_ADDR (0x6B << 1) 127 #define BQ2589X_REG_CFG1 0x02 128 #define BQ2589X_CFG1_CONV_START (1<<7) 129 #define BQ2589X_REG_ADC_BATT_VOLT 0x0E 130 #define BQ2589X_REG_ADC_SYS_VOLT 0x0F 131 #define BQ2589X_REG_ADC_TS 0x10 132 #define BQ2589X_REG_ADC_VBUS_VOLT 0x11 133 #define BQ2589X_REG_ADC_CHG_CURR 0x12 134 #define BQ2589X_REG_ADC_INPUT_CURR 0x13 135 136 static int bq25892_read(int reg, int *value) 137 { 138 int rv; 139 struct ec_response_i2c_read r; 140 struct ec_params_i2c_read p = { 141 .port = 0, .read_size = 8, .addr = BQ2589X_ADDR, .offset = reg 142 }; 143 144 rv = flash_cmd(ec, EC_CMD_I2C_READ, 0, &p, sizeof(p), &r, sizeof(r)); 145 if (rv < 0) { 146 *value = -1; 147 return rv; 148 } 149 150 *value = r.data; 151 return 0; 152 } 153 154 static int bq25892_write(int reg, int value) 155 { 156 int rv; 157 struct ec_params_i2c_write p = { 158 .port = 0, .write_size = 8, .addr = BQ2589X_ADDR, 159 .offset = reg, .data = value 160 }; 161 162 rv = flash_cmd(ec, EC_CMD_I2C_WRITE, 0, &p, sizeof(p), NULL, 0); 163 return rv < 0 ? rv : 0; 164 } 165 166 static int cmd_ec_bq25892(int argc, const char **argv) 167 { 168 int i; 169 int value; 170 int rv; 171 int batt_mv, sys_mv, vbus_mv, chg_ma, input_ma; 172 173 174 if (!get_ec()) 175 return -ENODEV; 176 177 /* Trigger one ADC conversion */ 178 bq25892_read(BQ2589X_REG_CFG1, &value); 179 bq25892_write(BQ2589X_REG_CFG1, value | BQ2589X_CFG1_CONV_START); 180 do { 181 rv = bq25892_read(BQ2589X_REG_CFG1, &value); 182 } while ((value & BQ2589X_CFG1_CONV_START) || (rv < 0)); 183 184 bq25892_read(BQ2589X_REG_ADC_BATT_VOLT, &batt_mv); 185 bq25892_read(BQ2589X_REG_ADC_SYS_VOLT, &sys_mv); 186 bq25892_read(BQ2589X_REG_ADC_VBUS_VOLT, &vbus_mv); 187 bq25892_read(BQ2589X_REG_ADC_CHG_CURR, &chg_ma); 188 bq25892_read(BQ2589X_REG_ADC_INPUT_CURR, &input_ma); 189 printf("ADC Batt %dmV Sys %dmV VBUS %dmV Chg %dmA Input %dmA\n", 190 2304 + (batt_mv & 0x7f) * 20, 2304 + sys_mv * 20, 191 2600 + (vbus_mv & 0x7f) * 100, 192 chg_ma * 50, 100 + (input_ma & 0x3f) * 50); 193 194 printf("REG:"); 195 for (i = 0; i <= 0x14; ++i) 196 printf(" %02x", i); 197 printf("\n"); 198 199 printf("VAL:"); 200 for (i = 0; i <= 0x14; ++i) { 201 rv = bq25892_read(i, &value); 202 if (rv) 203 return rv; 204 printf(" %02x", value); 205 } 206 printf("\n"); 207 return 0; 208 } 209 210 /* BQ27742 I2C registers */ 211 #define BQ27742_ADDR 0xAA 212 #define BQ27742_REG_CTRL 0x00 213 #define BQ27742_REG_FLAGS 0x0A 214 #define BQ27742_REG_CHARGING_MV 0x30 215 #define BQ27742_REG_CHARGING_MA 0x32 216 #define BQ27742_REG_PROTECTOR 0x6D 217 218 static int bq27742_read(int reg, int size, int *value) 219 { 220 int rv; 221 struct ec_response_i2c_read r; 222 struct ec_params_i2c_read p = { 223 .port = 0, .read_size = size, .addr = BQ27742_ADDR, 224 .offset = reg 225 }; 226 227 rv = flash_cmd(ec, EC_CMD_I2C_READ, 0, &p, sizeof(p), &r, sizeof(r)); 228 if (rv < 0) { 229 *value = -1; 230 return rv; 231 } 232 233 *value = r.data; 234 return 0; 235 } 236 237 static int bq27742_write(int reg, int size, int value) 238 { 239 int rv; 240 struct ec_params_i2c_write p = { 241 .port = 0, .write_size = size, .addr = BQ27742_ADDR, 242 .offset = reg, .data = value 243 }; 244 245 rv = flash_cmd(ec, EC_CMD_I2C_WRITE, 0, &p, sizeof(p), NULL, 0); 246 return rv < 0 ? rv : 0; 247 } 248 249 static int cmd_ec_bq27742(int argc, const char **argv) 250 { 251 int i; 252 int value; 253 int rv; 254 int chg_mv, chg_ma; 255 256 257 if (!get_ec()) 258 return -ENODEV; 259 260 /* Get chip ID in Control subcommand DEVICE_TYPE (0x1) */ 261 bq27742_write(BQ27742_REG_CTRL, 16, 0x1); 262 bq27742_read(BQ27742_REG_CTRL, 16, &value); 263 printf("ID: BQ27%3x\n", value); 264 265 bq27742_read(BQ27742_REG_CHARGING_MV, 16, &chg_mv); 266 bq27742_read(BQ27742_REG_CHARGING_MA, 16, &chg_ma); 267 printf("Requested charge: %d mV %d mA\n", chg_mv, chg_ma); 268 269 bq27742_read(BQ27742_REG_FLAGS, 16, &value); 270 printf("Flags: %04x\n", value); 271 bq27742_read(BQ27742_REG_PROTECTOR, 8, &value); 272 printf("ProtectorState: %02x\n", value); 273 274 return 0; 275 } 276 277 static int cmd_ec_chargecontrol(int argc, const char **argv) 278 { 279 struct ec_params_charge_control p; 280 int rv; 281 282 if (argc != 2) { 283 fprintf(stderr, "Usage: %s <normal | idle | discharge>\n", 284 argv[0]); 285 return -EINVAL; 286 } 287 288 if (!strcasecmp(argv[1], "normal")) { 289 p.mode = CHARGE_CONTROL_NORMAL; 290 } else if (!strcasecmp(argv[1], "idle")) { 291 p.mode = CHARGE_CONTROL_IDLE; 292 } else if (!strcasecmp(argv[1], "discharge")) { 293 p.mode = CHARGE_CONTROL_DISCHARGE; 294 } else { 295 fprintf(stderr, "Bad value.\n"); 296 return -EINVAL; 297 } 298 299 if (!get_ec()) 300 return -ENODEV; 301 302 rv = flash_cmd(ec, EC_CMD_CHARGE_CONTROL, 1, &p, sizeof(p), NULL, 0); 303 if (rv < 0) { 304 fprintf(stderr, "Is AC connected?\n"); 305 return rv; 306 } 307 308 switch (p.mode) { 309 case CHARGE_CONTROL_NORMAL: 310 printf("Charge state machine normal mode.\n"); 311 break; 312 case CHARGE_CONTROL_IDLE: 313 printf("Charge state machine force idle.\n"); 314 break; 315 case CHARGE_CONTROL_DISCHARGE: 316 printf("Charge state machine force discharge.\n"); 317 break; 318 default: 319 break; 320 } 321 return 0; 322 } 323 324 static int cmd_ec_console(int argc, const char **argv) 325 { 326 char data[128]; 327 int rv; 328 329 if (!get_ec()) 330 return -ENODEV; 331 332 /* Snapshot the EC console */ 333 rv = flash_cmd(ec, EC_CMD_CONSOLE_SNAPSHOT, 0, NULL, 0, NULL, 0); 334 if (rv < 0) 335 return rv; 336 337 /* Loop and read from the snapshot until it's done */ 338 while (1) { 339 memset(data, 0, sizeof(data)); 340 rv = flash_cmd(ec, EC_CMD_CONSOLE_READ, 0, 341 NULL, 0, data, sizeof(data)); 342 if (rv) 343 return rv; 344 345 /* Empty response means done */ 346 if (!data[0]) 347 break; 348 349 /* Make sure output is null-terminated, then dump it */ 350 data[sizeof(data) - 1] = '\0'; 351 fputs(data, stdout); 352 } 353 printf("\n"); 354 return 0; 355 } 356 357 static int cmd_ec_gpioget(int argc, const char **argv) 358 { 359 struct ec_params_gpio_get_v1 p_v1; 360 struct ec_response_gpio_get_v1 r_v1; 361 int i, rv, subcmd, num_gpios; 362 363 if (!get_ec()) 364 return -ENODEV; 365 366 if (argc > 2) { 367 printf("Usage: %s [<subcmd> <GPIO name>]\n", argv[0]); 368 printf("'gpioget <GPIO_NAME>' - Get value by name\n"); 369 printf("'gpioget count' - Get count of GPIOS\n"); 370 printf("'gpioget all' - Get info for all GPIOs\n"); 371 return -1; 372 } 373 374 /* Keeping it consistent with console command behavior */ 375 if (argc == 1) 376 subcmd = EC_GPIO_GET_INFO; 377 else if (!strcmp(argv[1], "count")) 378 subcmd = EC_GPIO_GET_COUNT; 379 else if (!strcmp(argv[1], "all")) 380 subcmd = EC_GPIO_GET_INFO; 381 else 382 subcmd = EC_GPIO_GET_BY_NAME; 383 384 if (subcmd == EC_GPIO_GET_BY_NAME) { 385 p_v1.subcmd = EC_GPIO_GET_BY_NAME; 386 if (strlen(argv[1]) + 1 > sizeof(p_v1.get_value_by_name.name)) { 387 fprintf(stderr, "GPIO name too long.\n"); 388 return -1; 389 } 390 strcpy(p_v1.get_value_by_name.name, argv[1]); 391 392 rv = flash_cmd(ec, EC_CMD_GPIO_GET, 1, &p_v1, 393 sizeof(p_v1), &r_v1, sizeof(r_v1)); 394 395 if (rv < 0) 396 return rv; 397 398 printf("GPIO %s = %d\n", p_v1.get_value_by_name.name, 399 r_v1.get_value_by_name.val); 400 return 0; 401 } 402 403 /* Need GPIO count for EC_GPIO_GET_COUNT or EC_GPIO_GET_INFO */ 404 p_v1.subcmd = EC_GPIO_GET_COUNT; 405 rv = flash_cmd(ec, EC_CMD_GPIO_GET, 1, &p_v1, 406 sizeof(p_v1), &r_v1, sizeof(r_v1)); 407 if (rv < 0) 408 return rv; 409 410 if (subcmd == EC_GPIO_GET_COUNT) { 411 printf("GPIO COUNT = %d\n", r_v1.get_count.val); 412 return 0; 413 } 414 415 /* subcmd EC_GPIO_GET_INFO */ 416 num_gpios = r_v1.get_count.val; 417 p_v1.subcmd = EC_GPIO_GET_INFO; 418 419 for (i = 0; i < num_gpios; i++) { 420 p_v1.get_info.index = i; 421 422 rv = flash_cmd(ec, EC_CMD_GPIO_GET, 1, &p_v1, 423 sizeof(p_v1), &r_v1, sizeof(r_v1)); 424 if (rv < 0) 425 return rv; 426 427 printf("%2d %-32s 0x%04X\n", r_v1.get_info.val, 428 r_v1.get_info.name, r_v1.get_info.flags); 429 } 430 431 return 0; 432 } 433 434 435 static int cmd_ec_gpioset(int argc, const char **argv) 436 { 437 struct ec_params_gpio_set p; 438 char *e; 439 int rv; 440 441 if (!get_ec()) 442 return -ENODEV; 443 444 if (argc != 3) { 445 fprintf(stderr, "Usage: %s <GPIO name> <0 | 1>\n", argv[0]); 446 return -1; 447 } 448 449 if (strlen(argv[1]) + 1 > sizeof(p.name)) { 450 fprintf(stderr, "GPIO name too long.\n"); 451 return -1; 452 } 453 strcpy(p.name, argv[1]); 454 455 p.val = strtol(argv[2], &e, 0); 456 if (e && *e) { 457 fprintf(stderr, "Bad value.\n"); 458 return -1; 459 } 460 461 rv = flash_cmd(ec, EC_CMD_GPIO_SET, 0, &p, sizeof(p), NULL, 0); 462 if (rv < 0) 463 return rv; 464 465 printf("GPIO %s set to %d\n", p.name, p.val); 466 return 0; 467 } 468 469 static int ec_hash_print(const struct ec_response_vboot_hash *r) 470 { 471 int i; 472 473 if (r->status == EC_VBOOT_HASH_STATUS_BUSY) { 474 printf("status: busy\n"); 475 return 0; 476 } else if (r->status == EC_VBOOT_HASH_STATUS_NONE) { 477 printf("status: unavailable\n"); 478 return 0; 479 } else if (r->status != EC_VBOOT_HASH_STATUS_DONE) { 480 printf("status: %d\n", r->status); 481 return 0; 482 } 483 484 printf("status: done\n"); 485 if (r->hash_type == EC_VBOOT_HASH_TYPE_SHA256) 486 printf("type: SHA-256\n"); 487 else 488 printf("type: %d\n", r->hash_type); 489 490 printf("offset: 0x%08x\n", r->offset); 491 printf("size: 0x%08x\n", r->size); 492 493 printf("hash: "); 494 for (i = 0; i < r->digest_size; i++) 495 printf("%02x", r->hash_digest[i]); 496 printf("\n"); 497 return 0; 498 } 499 500 static int cmd_ec_echash(int argc, const char **argv) 501 { 502 struct ec_params_vboot_hash p; 503 struct ec_response_vboot_hash r; 504 char *e; 505 int rv; 506 507 if (!get_ec()) 508 return -ENODEV; 509 510 if (argc < 2) { 511 /* Get hash status */ 512 p.cmd = EC_VBOOT_HASH_GET; 513 rv = flash_cmd(ec, EC_CMD_VBOOT_HASH, 0, 514 &p, sizeof(p), &r, sizeof(r)); 515 if (rv < 0) 516 return rv; 517 518 return ec_hash_print(&r); 519 } 520 521 if (argc == 2 && !strcasecmp(argv[1], "abort")) { 522 /* Abort hash calculation */ 523 p.cmd = EC_VBOOT_HASH_ABORT; 524 rv = flash_cmd(ec, EC_CMD_VBOOT_HASH, 0, 525 &p, sizeof(p), &r, sizeof(r)); 526 return (rv < 0 ? rv : 0); 527 } 528 529 /* The only other commands are start and recalc */ 530 if (!strcasecmp(argv[1], "start")) 531 p.cmd = EC_VBOOT_HASH_START; 532 else if (!strcasecmp(argv[1], "recalc")) 533 p.cmd = EC_VBOOT_HASH_RECALC; 534 else 535 return -EINVAL; 536 537 p.hash_type = EC_VBOOT_HASH_TYPE_SHA256; 538 539 if (argc < 3) { 540 fprintf(stderr, "Must specify offset\n"); 541 return -1; 542 } 543 544 if (!strcasecmp(argv[2], "ro")) { 545 p.offset = EC_VBOOT_HASH_OFFSET_RO; 546 p.size = 0; 547 printf("Hashing EC-RO...\n"); 548 } else if (!strcasecmp(argv[2], "rw")) { 549 p.offset = EC_VBOOT_HASH_OFFSET_RW; 550 p.size = 0; 551 printf("Hashing EC-RW...\n"); 552 } else if (argc < 4) { 553 fprintf(stderr, "Must specify size\n"); 554 return -1; 555 } else { 556 p.offset = strtol(argv[2], &e, 0); 557 if (e && *e) { 558 fprintf(stderr, "Bad offset.\n"); 559 return -1; 560 } 561 p.size = strtol(argv[3], &e, 0); 562 if (e && *e) { 563 fprintf(stderr, "Bad size.\n"); 564 return -1; 565 } 566 printf("Hashing %d bytes at offset %d...\n", p.size, p.offset); 567 } 568 569 if (argc == 5) { 570 /* 571 * Technically nonce can be any binary data up to 64 bytes, 572 * but this command only supports a 32-bit value. 573 */ 574 uint32_t nonce = strtol(argv[4], &e, 0); 575 if (e && *e) { 576 fprintf(stderr, "Bad nonce integer.\n"); 577 return -1; 578 } 579 memcpy(p.nonce_data, &nonce, sizeof(nonce)); 580 p.nonce_size = sizeof(nonce); 581 } else 582 p.nonce_size = 0; 583 584 rv = flash_cmd(ec, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), &r, sizeof(r)); 585 if (rv < 0) 586 return rv; 587 588 /* Start command doesn't wait for hashing to finish */ 589 if (p.cmd == EC_VBOOT_HASH_START) 590 return 0; 591 592 /* Recalc command does wait around, so a result is ready now */ 593 return ec_hash_print(&r); 594 } 595 596 #define LIGHTBAR_NUM_SEQUENCES 13 597 598 static int lb_do_cmd(enum lightbar_command cmd, 599 struct ec_params_lightbar *in, 600 struct ec_response_lightbar *out) 601 { 602 int rv; 603 in->cmd = cmd; 604 rv = flash_cmd(ec, EC_CMD_LIGHTBAR_CMD, 0, 605 in, 120, 606 out, 120); 607 return (rv < 0 ? rv : 0); 608 } 609 610 static int cmd_ec_lightbar(int argc, const char **argv) 611 { 612 unsigned i; 613 int r; 614 struct ec_params_lightbar param; 615 struct ec_response_lightbar resp; 616 617 if (!get_ec()) 618 return -ENODEV; 619 620 if (1 == argc) { /* no args = dump 'em all */ 621 r = lb_do_cmd(LIGHTBAR_CMD_DUMP, ¶m, &resp); 622 if (r) 623 return r; 624 for (i = 0; i < ARRAY_SIZE(resp.dump.vals); i++) { 625 printf(" %02x %02x %02x\n", 626 resp.dump.vals[i].reg, 627 resp.dump.vals[i].ic0, 628 resp.dump.vals[i].ic1); 629 } 630 return 0; 631 } 632 633 if (argc == 2 && !strcasecmp(argv[1], "init")) 634 return lb_do_cmd(LIGHTBAR_CMD_INIT, ¶m, &resp); 635 636 if (argc == 2 && !strcasecmp(argv[1], "off")) 637 return lb_do_cmd(LIGHTBAR_CMD_OFF, ¶m, &resp); 638 639 if (argc == 2 && !strcasecmp(argv[1], "on")) 640 return lb_do_cmd(LIGHTBAR_CMD_ON, ¶m, &resp); 641 642 if (!strcasecmp(argv[1], "version")) { 643 r = lb_do_cmd(LIGHTBAR_CMD_VERSION, ¶m, &resp); 644 if (!r) 645 printf("version %d flags 0x%x\n", 646 resp.version.num, resp.version.flags); 647 return r; 648 } 649 650 if (argc > 1 && !strcasecmp(argv[1], "brightness")) { 651 char *e; 652 int rv; 653 if (argc > 2) { 654 param.set_brightness.num = 0xff & 655 strtoul(argv[2], &e, 16); 656 return lb_do_cmd(LIGHTBAR_CMD_SET_BRIGHTNESS, 657 ¶m, &resp); 658 } 659 rv = lb_do_cmd(LIGHTBAR_CMD_GET_BRIGHTNESS, 660 ¶m, &resp); 661 if (rv) 662 return rv; 663 printf("%02x\n", resp.get_brightness.num); 664 return 0; 665 } 666 667 if (argc > 1 && !strcasecmp(argv[1], "demo")) { 668 int rv; 669 if (argc > 2) { 670 if (!strcasecmp(argv[2], "on") || argv[2][0] == '1') 671 param.demo.num = 1; 672 else if (!strcasecmp(argv[2], "off") || 673 argv[2][0] == '0') 674 param.demo.num = 0; 675 else { 676 fprintf(stderr, "Invalid arg\n"); 677 return -1; 678 } 679 return lb_do_cmd(LIGHTBAR_CMD_DEMO, ¶m, &resp); 680 } 681 682 rv = lb_do_cmd(LIGHTBAR_CMD_GET_DEMO, ¶m, &resp); 683 if (rv) 684 return rv; 685 printf("%s\n", resp.get_demo.num ? "on" : "off"); 686 return 0; 687 } 688 689 if (argc > 2 && !strcasecmp(argv[1], "seq")) { 690 char *e; 691 uint8_t num; 692 num = 0xff & strtoul(argv[2], &e, 16); 693 if (e && *e) { 694 if (!strcasecmp(argv[2], "stop")) 695 num = 0x8; 696 else if (!strcasecmp(argv[2], "run")) 697 num = 0x9; 698 else if (!strcasecmp(argv[2], "konami")) 699 num = 0xA; 700 else 701 num = LIGHTBAR_NUM_SEQUENCES; 702 } 703 if (num >= LIGHTBAR_NUM_SEQUENCES) { 704 fprintf(stderr, "Invalid arg\n"); 705 return -1; 706 } 707 param.seq.num = num; 708 return lb_do_cmd(LIGHTBAR_CMD_SEQ, ¶m, &resp); 709 } 710 711 if (argc == 4) { 712 char *e; 713 param.reg.ctrl = 0xff & strtoul(argv[1], &e, 16); 714 param.reg.reg = 0xff & strtoul(argv[2], &e, 16); 715 param.reg.value = 0xff & strtoul(argv[3], &e, 16); 716 return lb_do_cmd(LIGHTBAR_CMD_REG, ¶m, &resp); 717 } 718 719 if (argc == 5) { 720 char *e; 721 param.set_rgb.led = strtoul(argv[1], &e, 16); 722 param.set_rgb.red = strtoul(argv[2], &e, 16); 723 param.set_rgb.green = strtoul(argv[3], &e, 16); 724 param.set_rgb.blue = strtoul(argv[4], &e, 16); 725 return lb_do_cmd(LIGHTBAR_CMD_SET_RGB, ¶m, &resp); 726 } 727 728 /* Only thing left is to try to read an LED value */ 729 if (argc == 2) { 730 char *e; 731 param.get_rgb.led = strtoul(argv[1], &e, 0); 732 if (!(e && *e)) { 733 r = lb_do_cmd(LIGHTBAR_CMD_GET_RGB, ¶m, &resp); 734 if (r) 735 return r; 736 printf("%02x %02x %02x\n", 737 resp.get_rgb.red, 738 resp.get_rgb.green, 739 resp.get_rgb.blue); 740 return 0; 741 } 742 } 743 744 return 0; 745 } 746 747 /* PI3USB9281 I2C registers */ 748 #define PI3USB9281_ADDR (0x25 << 1) 749 #define PI3USB9281_REG_DEV_ID 0x01 750 #define PI3USB9281_REG_CONTROL 0x02 751 #define PI3USB9281_REG_INT 0x03 752 #define PI3USB9281_REG_INT_MASK 0x05 753 #define PI3USB9281_REG_DEV_TYPE 0x0a 754 #define PI3USB9281_REG_CHG_STATUS 0x0e 755 #define PI3USB9281_REG_MANUAL 0x13 756 #define PI3USB9281_REG_RESET 0x1b 757 #define PI3USB9281_REG_VBUS 0x1d 758 759 static const uint8_t pi3usb9281_regs[] = { 760 PI3USB9281_REG_DEV_ID, PI3USB9281_REG_CONTROL, PI3USB9281_REG_INT, 761 PI3USB9281_REG_INT_MASK, PI3USB9281_REG_DEV_TYPE, PI3USB9281_REG_CHG_STATUS, 762 PI3USB9281_REG_MANUAL, PI3USB9281_REG_VBUS 763 }; 764 #define PI3USB9281_COUNT ARRAY_SIZE(pi3usb9281_regs) 765 766 static int pi3usb9281_read(int reg, int *value) 767 { 768 int rv; 769 struct ec_response_i2c_read r; 770 struct ec_params_i2c_read p = { 771 .port = 0, .read_size = 8, .addr = PI3USB9281_ADDR, .offset = reg 772 }; 773 774 rv = flash_cmd(ec, EC_CMD_I2C_READ, 0, &p, sizeof(p), &r, sizeof(r)); 775 if (rv < 0) { 776 *value = -1; 777 return rv; 778 } 779 780 *value = r.data; 781 return 0; 782 } 783 784 static int cmd_ec_pi3usb9281(int argc, const char **argv) 785 { 786 unsigned i; 787 int value; 788 int rv; 789 int dev_type, chg_stat, vbus; 790 char *apple_chg = "", *proprio_chg = ""; 791 792 if (!get_ec()) 793 return -ENODEV; 794 795 pi3usb9281_read(PI3USB9281_REG_DEV_TYPE, &dev_type); 796 pi3usb9281_read(PI3USB9281_REG_CHG_STATUS, &chg_stat); 797 pi3usb9281_read(PI3USB9281_REG_VBUS, &vbus); 798 switch((chg_stat>>2)&7) { 799 case 4: apple_chg = "Apple 2.4A"; break; 800 case 2: apple_chg = "Apple 2A"; break; 801 case 1: apple_chg = "Apple 1A"; break; 802 } 803 switch(chg_stat&3) { 804 case 3: proprio_chg = "type-2"; break; 805 case 2: proprio_chg = "type-1"; break; 806 case 1: proprio_chg = "rsvd"; break; 807 } 808 printf("USB: %s%s%s%s%s%s Charger: %s%s VBUS: %d\n", 809 dev_type & (1<<6) ? "DCP" : " ", 810 dev_type & (1<<5) ? "CDP" : " ", 811 dev_type & (1<<4) ? "CarKit" : " ", 812 dev_type & (1<<2) ? "SDP" : " ", 813 dev_type & (1<<1) ? "OTG" : " ", 814 dev_type & (1<<0) ? "MHL" : " ", 815 apple_chg, 816 proprio_chg, 817 !!(vbus & 2)); 818 819 printf("REG:"); 820 for (i = 0; i < PI3USB9281_COUNT; ++i) 821 printf(" %02x", pi3usb9281_regs[i]); 822 printf("\n"); 823 824 printf("VAL:"); 825 for (i = 0; i < PI3USB9281_COUNT; ++i) { 826 rv = pi3usb9281_read(pi3usb9281_regs[i], &value); 827 if (rv) 828 return rv; 829 printf(" %02x", value); 830 } 831 printf("\n"); 832 return 0; 833 } 834 835 #define PD_ROLE_SINK 0 836 #define PD_ROLE_SOURCE 1 837 #define PD_ROLE_UFP 0 838 #define PD_ROLE_DFP 1 839 840 static int cmd_ec_usbpd(int argc, const char **argv) 841 { 842 const char *role_str[] = {"", "toggle", "toggle-off", "sink", "source"}; 843 const char *mux_str[] = {"", "none", "usb", "dp", "dock", "auto"}; 844 const char *swap_str[] = {"", "dr_swap", "pr_swap", "vconn_swap"}; 845 struct ec_params_usb_pd_control p; 846 struct ec_response_usb_pd_control_v1 r; 847 int rv, i; 848 unsigned j; 849 int option_ok; 850 char *e; 851 852 if (!get_ec()) 853 return -ENODEV; 854 855 p.role = USB_PD_CTRL_ROLE_NO_CHANGE; 856 p.mux = USB_PD_CTRL_MUX_NO_CHANGE; 857 p.swap = USB_PD_CTRL_SWAP_NONE; 858 859 if (argc < 2) { 860 fprintf(stderr, "No port specified.\n"); 861 return -1; 862 } 863 864 p.port = strtol(argv[1], &e, 0); 865 if (e && *e) { 866 fprintf(stderr, "Invalid param (port)\n"); 867 return -1; 868 } 869 870 for (i = 2; i < argc; ++i) { 871 option_ok = 0; 872 if (!strcmp(argv[i], "auto")) { 873 if (argc != 3) { 874 fprintf(stderr, "\"auto\" may not be used " 875 "with other options.\n"); 876 return -1; 877 } 878 p.role = USB_PD_CTRL_ROLE_TOGGLE_ON; 879 p.mux = USB_PD_CTRL_MUX_AUTO; 880 continue; 881 } 882 883 for (j = 0; j < ARRAY_SIZE(role_str); ++j) { 884 if (!strcmp(argv[i], role_str[j])) { 885 if (p.role != USB_PD_CTRL_ROLE_NO_CHANGE) { 886 fprintf(stderr, 887 "Only one role allowed.\n"); 888 return -1; 889 } 890 p.role = j; 891 option_ok = 1; 892 break; 893 } 894 } 895 if (option_ok) 896 continue; 897 898 for (j = 0; j < ARRAY_SIZE(mux_str); ++j) { 899 if (!strcmp(argv[i], mux_str[j])) { 900 if (p.mux != USB_PD_CTRL_MUX_NO_CHANGE) { 901 fprintf(stderr, 902 "Only one mux type allowed.\n"); 903 return -1; 904 } 905 p.mux = j; 906 option_ok = 1; 907 break; 908 } 909 } 910 if (option_ok) 911 continue; 912 913 for (j = 0; j < ARRAY_SIZE(swap_str); ++j) { 914 if (!strcmp(argv[i], swap_str[j])) { 915 if (p.swap != USB_PD_CTRL_SWAP_NONE) { 916 fprintf(stderr, 917 "Only one swap type allowed.\n"); 918 return -1; 919 } 920 p.swap = j; 921 option_ok = 1; 922 break; 923 } 924 } 925 926 927 if (!option_ok) { 928 fprintf(stderr, "Unknown option: %s\n", argv[i]); 929 return -1; 930 } 931 } 932 933 rv = flash_cmd(ec, EC_CMD_USB_PD_CONTROL, 1, &p, sizeof(p), 934 &r, sizeof(r)); 935 936 if (rv < 0 || argc != 2) 937 return (rv < 0) ? rv : 0; 938 939 printf("Port C%d is %s,%s, Role:%s %s%s Polarity:CC%d State:%s\n", 940 p.port, (r.enabled & 1) ? "enabled" : "disabled", 941 (r.enabled & 2) ? "connected" : "disconnected", 942 r.role & PD_ROLE_SOURCE ? "SRC" : "SNK", 943 r.role & (PD_ROLE_DFP << 1) ? "DFP" : "UFP", 944 r.role & (1 << 2) ? " VCONN" : "", 945 r.polarity + 1, r.state); 946 947 return (rv < 0 ? rv : 0); 948 } 949 950 static void print_pd_power_info(struct ec_response_usb_pd_power_info *r) 951 { 952 switch (r->role) { 953 case USB_PD_PORT_POWER_DISCONNECTED: 954 printf("Disconnected"); 955 break; 956 case USB_PD_PORT_POWER_SOURCE: 957 printf("SRC"); 958 break; 959 case USB_PD_PORT_POWER_SINK: 960 printf("SNK"); 961 break; 962 case USB_PD_PORT_POWER_SINK_NOT_CHARGING: 963 printf("SNK (not charging)"); 964 break; 965 default: 966 printf("Unknown"); 967 } 968 969 if ((r->role == USB_PD_PORT_POWER_DISCONNECTED) || 970 (r->role == USB_PD_PORT_POWER_SOURCE)) { 971 printf("\n"); 972 return; 973 } 974 975 printf(r->dualrole ? " DRP" : " Charger"); 976 switch (r->type) { 977 case USB_CHG_TYPE_PD: 978 printf(" PD"); 979 break; 980 case USB_CHG_TYPE_C: 981 printf(" Type-C"); 982 break; 983 case USB_CHG_TYPE_PROPRIETARY: 984 printf(" Proprietary"); 985 break; 986 case USB_CHG_TYPE_BC12_DCP: 987 printf(" DCP"); 988 break; 989 case USB_CHG_TYPE_BC12_CDP: 990 printf(" CDP"); 991 break; 992 case USB_CHG_TYPE_BC12_SDP: 993 printf(" SDP"); 994 break; 995 case USB_CHG_TYPE_OTHER: 996 printf(" Other"); 997 break; 998 case USB_CHG_TYPE_VBUS: 999 printf(" VBUS"); 1000 break; 1001 case USB_CHG_TYPE_UNKNOWN: 1002 printf(" Unknown"); 1003 break; 1004 } 1005 printf(" %dmV / %dmA, max %dmV / %dmA", 1006 r->meas.voltage_now, r->meas.current_lim, r->meas.voltage_max, 1007 r->meas.current_max); 1008 if (r->max_power) 1009 printf(" / %dmW", r->max_power / 1000); 1010 printf("\n"); 1011 } 1012 1013 static int cmd_ec_usbpdpower(int argc, const char **argv) 1014 { 1015 struct ec_params_usb_pd_power_info p; 1016 struct ec_response_usb_pd_power_info r; 1017 struct ec_response_usb_pd_ports rp; 1018 int i, rv; 1019 1020 if (!get_ec()) 1021 return -ENODEV; 1022 1023 rv = flash_cmd(ec, EC_CMD_USB_PD_PORTS, 0, NULL, 0, &rp, sizeof(rp)); 1024 if (rv) 1025 return rv; 1026 1027 for (i = 0; i < rp.num_ports; i++) { 1028 p.port = i; 1029 rv = flash_cmd(ec, EC_CMD_USB_PD_POWER_INFO, 0, 1030 &p, sizeof(p), &r, sizeof(r)); 1031 if (rv) 1032 return rv; 1033 1034 printf("Port %d: ", i); 1035 print_pd_power_info(&r); 1036 } 1037 1038 return 0; 1039 } 1040 1041 static int cmd_ec_version(int argc, const char **argv) 1042 { 1043 static const char * const image_names[] = {"unknown", "RO", "RW"}; 1044 struct ec_response_get_version r; 1045 char build_string[128]; 1046 int rv; 1047 1048 if (!get_ec()) 1049 return -ENODEV; 1050 1051 rv = flash_cmd(ec, EC_CMD_GET_VERSION, 0, NULL, 0, &r, sizeof(r)); 1052 if (rv < 0) { 1053 fprintf(stderr, "ERROR: EC_CMD_GET_VERSION failed: %d\n", rv); 1054 return rv; 1055 } 1056 rv = flash_cmd(ec, EC_CMD_GET_BUILD_INFO, 0, 1057 NULL, 0, build_string, sizeof(build_string)); 1058 if (rv < 0) { 1059 fprintf(stderr, "ERROR: EC_CMD_GET_BUILD_INFO failed: %d\n", 1060 rv); 1061 return rv; 1062 } 1063 1064 /* Ensure versions are null-terminated before we print them */ 1065 r.version_string_ro[sizeof(r.version_string_ro) - 1] = '\0'; 1066 r.version_string_rw[sizeof(r.version_string_rw) - 1] = '\0'; 1067 build_string[sizeof(build_string) - 1] = '\0'; 1068 1069 /* Print versions */ 1070 printf("RO version: %s\n", r.version_string_ro); 1071 printf("RW version: %s\n", r.version_string_rw); 1072 printf("Firmware copy: %s\n", 1073 (r.current_image < ARRAY_SIZE(image_names) ? 1074 image_names[r.current_image] : "?")); 1075 printf("Build info: %s\n", build_string); 1076 1077 return 0; 1078 } 1079 1080 struct command subcmds_ec[] = { 1081 CMD(ec_battery, "Show battery status"), 1082 CMD(ec_bq25892, "Dump the state of the bq25892 charger chip"), 1083 CMD(ec_bq27742, "Dump the state of the bq27742 gas gauge"), 1084 CMD(ec_chargecontrol, "Force the battery to stop charging/discharge"), 1085 CMD(ec_console, "Prints the last output to the EC debug console"), 1086 CMD(ec_gpioget, "Get the value of GPIO signal"), 1087 CMD(ec_gpioset, "Set the value of GPIO signal"), 1088 CMD(ec_echash, "Various EC hash commands"), 1089 CMD(ec_lightbar, "Lightbar control commands"), 1090 CMD(ec_pi3usb9281, "Dump the state of the Pericom PI3USB9281 chip"), 1091 CMD(ec_usbpd, "Control USB PD/type-C"), 1092 CMD(ec_usbpdpower, "Power information about USB PD ports"), 1093 CMD(ec_version, "Prints EC version"), 1094 CMD_GUARD_LAST 1095 }; 1096