diff options
-rw-r--r-- | board/spring/board.c | 67 | ||||
-rw-r--r-- | include/ec_commands.h | 43 | ||||
-rw-r--r-- | util/ectool.c | 100 |
3 files changed, 144 insertions, 66 deletions
diff --git a/board/spring/board.c b/board/spring/board.c index db65e77986..117338d469 100644 --- a/board/spring/board.c +++ b/board/spring/board.c @@ -342,32 +342,6 @@ static int set_led_color(enum led_state_t state) } /*****************************************************************************/ -/* Host commands */ - -static int led_command_set(struct host_cmd_handler_args *args) -{ - const struct ec_params_led_set *p = args->params; - - if (p->flags & EC_LED_FLAGS_AUTO) { - if (!board_get_ac()) - lp5562_poweroff(); - last_state = LED_STATE_OFF; - led_auto_control = 1; - } else { - led_auto_control = 0; - if (!board_get_ac()) - lp5562_poweron(); - if (lp5562_set_color((p->r << 16) + (p->g << 8) + p->b)) - return EC_RES_ERROR; - } - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_LED_SET, - led_command_set, - EC_VER_MASK(0)); - -/*****************************************************************************/ /* Hooks */ static void board_battery_led_update(void) @@ -458,3 +432,44 @@ static int power_command_info(struct host_cmd_handler_args *args) return EC_RES_SUCCESS; } DECLARE_HOST_COMMAND(EC_CMD_POWER_INFO, power_command_info, EC_VER_MASK(0)); + +static int led_command_control(struct host_cmd_handler_args *args) +{ + const struct ec_params_led_control *p = args->params; + struct ec_response_led_control *r = args->response; + int i; + uint8_t clipped[EC_LED_COLOR_COUNT]; + + /* Only support battery LED control */ + if (p->led_id != EC_LED_ID_BATTERY_LED) + return EC_RES_INVALID_PARAM; + + if (p->flags & EC_LED_FLAGS_AUTO) { + if (!board_get_ac()) + lp5562_poweroff(); + last_state = LED_STATE_OFF; + led_auto_control = 1; + } else if (!(p->flags & EC_LED_FLAGS_QUERY)) { + for (i = 0; i < EC_LED_COLOR_COUNT; ++i) + clipped[i] = MIN(p->brightness[i], 0x80); + led_auto_control = 0; + if (!board_get_ac()) + lp5562_poweron(); + if (lp5562_set_color((clipped[EC_LED_COLOR_RED] << 16) + + (clipped[EC_LED_COLOR_GREEN] << 8) + + clipped[EC_LED_COLOR_YELLOW])) + return EC_RES_ERROR; + } + + r->brightness_range[EC_LED_COLOR_RED] = 0x80; + r->brightness_range[EC_LED_COLOR_GREEN] = 0x80; + r->brightness_range[EC_LED_COLOR_BLUE] = 0x0; + r->brightness_range[EC_LED_COLOR_YELLOW] = 0x80; + r->brightness_range[EC_LED_COLOR_WHITE] = 0x0; + args->response_size = sizeof(struct ec_response_led_control); + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_LED_CONTROL, + led_command_control, + EC_VER_MASK(1)); diff --git a/include/ec_commands.h b/include/ec_commands.h index b16871462e..b35b15050a 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -729,15 +729,44 @@ enum lightbar_command { /*****************************************************************************/ /* LED control commands */ -#define EC_CMD_LED_SET 0x29 +#define EC_CMD_LED_CONTROL 0x29 -#define EC_LED_FLAGS_AUTO (1 << 1) +enum ec_led_id { + EC_LED_ID_BATTERY_LED = 0, + EC_LED_ID_POWER_BUTTON_LED, + EC_LED_ID_ADAPTER_LED, +}; -struct ec_params_led_set { - uint8_t r; - uint8_t g; - uint8_t b; /* Used as yellow if there is no blue LED */ - uint8_t flags; +/* LED control flags */ +#define EC_LED_FLAGS_QUERY (1 << 0) /* Query LED capability only */ +#define EC_LED_FLAGS_AUTO (1 << 1) /* Switch LED back to automatic control */ + +enum ec_led_colors { + EC_LED_COLOR_RED = 0, + EC_LED_COLOR_GREEN, + EC_LED_COLOR_BLUE, + EC_LED_COLOR_YELLOW, + EC_LED_COLOR_WHITE, + + EC_LED_COLOR_COUNT +}; + +struct ec_params_led_control { + uint8_t led_id; /* Which LED to control */ + uint8_t flags; /* Control flags */ + + uint8_t brightness[EC_LED_COLOR_COUNT]; +} __packed; + +struct ec_response_led_control { + /* + * Available brightness value range. + * + * Range 0 means color channel not present. + * Range 1 means on/off control. + * Other values means the LED is control by PWM. + */ + uint8_t brightness_range[EC_LED_COLOR_COUNT]; } __packed; /*****************************************************************************/ diff --git a/util/ectool.c b/util/ectool.c index c5ebf30c6f..597dd72eaf 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -161,6 +161,10 @@ const char help_str[] = /* Note: depends on enum system_image_copy_t */ static const char * const image_names[] = {"unknown", "RO", "RW"}; +/* Note: depends on enum ec_led_colors */ +static const char * const led_color_names[EC_LED_COLOR_COUNT] = { + "red", "green", "blue", "yellow", "white"}; + /* Write a buffer to the file. Return non-zero if error. */ static int write_file(const char *filename, const char *buf, int size) { @@ -1405,51 +1409,81 @@ static int cmd_lightbar(int argc, char **argv) } +static int find_led_color_by_name(const char *color) +{ + int i; + + for (i = 0; i < EC_LED_COLOR_COUNT; ++i) + if (!strcasecmp(color, led_color_names[i])) + return i; + return -1; +} + int cmd_led(int argc, char *argv[]) { - struct ec_params_led_set p; - char *e; - int rv; + struct ec_params_led_control p; + struct ec_response_led_control r; + char *e, *ptr; + int rv, i, j; - if (argc == 1) { + memset(p.brightness, 0, sizeof(p.brightness)); + p.flags = 0; + + if (argc < 3) { fprintf(stderr, - "Usage: %s <auto | red | green | blue | " - "<R> <G> <B>>\n", argv[0]); + "Usage: %s <ID> <query | auto | " + "<color>=<brightness>...>\n", argv[0]); return -1; } - p.r = p.g = p.b = p.flags = 0; + p.led_id = strtol(argv[1], &e, 0); + if (e && *e) { + fprintf(stderr, "Bad LED ID.\n"); + return -1; + } - if (!strcasecmp(argv[1], "auto")) { + if (!strcasecmp(argv[2], "query")) { + p.flags = EC_LED_FLAGS_QUERY; + rv = ec_command(EC_CMD_LED_CONTROL, 1, &p, sizeof(p), + &r, sizeof(r)); + printf("Brightness range for LED %d:\n", p.led_id); + if (rv < 0) { + fprintf(stderr, "Error. Not existing LED?\n"); + return rv; + } + for (i = 0; i < 5; ++i) + printf("\t%s\t: 0x%x\n", + led_color_names[i], + r.brightness_range[i]); + return 0; + } + + if (!strcasecmp(argv[2], "auto")) { p.flags = EC_LED_FLAGS_AUTO; - } else if (!strcasecmp(argv[1], "red")) { - p.r = 0xff; - } else if (!strcasecmp(argv[1], "green")) { - p.g = 0xff; - } else if (!strcasecmp(argv[1], "blue")) { - p.b = 0xff; - } else if (argc != 4) { - fprintf(stderr, "Incorrect number of arguments\n"); - return -1; + } else if ((i = find_led_color_by_name(argv[2])) != -1) { + p.brightness[i] = 0xff; } else { - p.r = strtol(argv[1], &e, 0); - if (e && *e) { - fprintf(stderr, "Bad R value.\n"); - return -1; - } - p.g = strtol(argv[2], &e, 0); - if (e && *e) { - fprintf(stderr, "Bad G value.\n"); - return -1; - } - p.b = strtol(argv[3], &e, 0); - if (e && *e) { - fprintf(stderr, "Bad B value.\n"); - return -1; + for (i = 2; i < argc; ++i) { + ptr = strtok(argv[i], "="); + j = find_led_color_by_name(ptr); + if (j == -1) { + fprintf(stderr, "Bad color name: %s\n", ptr); + return -1; + } + ptr = strtok(NULL, "="); + if (ptr == NULL) { + fprintf(stderr, "Missing brightness value\n"); + return -1; + } + p.brightness[j] = strtol(ptr, &e, 0); + if (e && *e) { + fprintf(stderr, "Bad brightness: %s\n", ptr); + return -1; + } } - p.flags = 0; } - rv = ec_command(EC_CMD_LED_SET, 0, &p, sizeof(p), NULL, 0); + + rv = ec_command(EC_CMD_LED_CONTROL, 1, &p, sizeof(p), &r, sizeof(r)); return (rv < 0 ? rv : 0); } |