From 63a71a6adce21a0354cf8d2245170da824f7d8c2 Mon Sep 17 00:00:00 2001 From: Dave Parker Date: Fri, 2 Aug 2013 18:20:57 -0700 Subject: Peppy ectool led command Glue between the existing ectool led command and the led control logic. BUG=chrome-os-partner:20776 BRANCH=peppy TEST=Manual. Run "ectool led" commands: Should pass: ectool led power blue|yellow|off|auto|blue=1 yellow=1 ectool led battery blue|yellow|off|auto|blue=1 yellow=1 Should fail: ectool led adapter ectool led power|battery red|green|white Signed-off-by: Dave Parker Change-Id: I2540940baa553866760dd9ae62278b6b845793ef Reviewed-on: https://gerrit.chromium.org/gerrit/64627 --- common/build.mk | 2 +- common/led_common.c | 70 ++++++++++++++++++++++++++++++ common/led_peppy.c | 115 ++++++++++++++++++++++++++++++++++++++++---------- include/ec_commands.h | 10 ++++- include/led_common.h | 63 +++++++++++++++++++++++++++ util/ectool.c | 47 ++++++++++++++++----- 6 files changed, 272 insertions(+), 35 deletions(-) create mode 100644 common/led_common.c create mode 100644 include/led_common.h diff --git a/common/build.mk b/common/build.mk index c6c7577153..c617611a43 100644 --- a/common/build.mk +++ b/common/build.mk @@ -14,7 +14,7 @@ common-$(BOARD_bolt)+=battery_link.o common-$(BOARD_daisy)+=extpower_snow.o common-$(BOARD_falco)+=battery_falco.o led_falco.o common-$(BOARD_link)+=battery_link.o -common-$(BOARD_peppy)+=battery_peppy.o led_peppy.o +common-$(BOARD_peppy)+=battery_peppy.o led_common.o led_peppy.o common-$(BOARD_slippy)+=battery_slippy.o led_slippy.o common-$(BOARD_snow)+=extpower_snow.o common-$(BOARD_spring)+=battery_spring.o diff --git a/common/led_common.c b/common/led_common.c new file mode 100644 index 0000000000..88abd841f6 --- /dev/null +++ b/common/led_common.c @@ -0,0 +1,70 @@ +/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Common functions for blinking LEDs. + */ + +#include "console.h" +#include "ec_commands.h" +#include "hooks.h" +#include "host_command.h" +#include "led_common.h" +#include "util.h" + +#define LED_AUTO_CONTROL_FLAG(id) (1 << (id)) + +static uint32_t led_auto_control_flags = ~0x00; + +static int led_is_supported(enum ec_led_id led_id) +{ + int i; + + for (i = 0; i < supported_led_ids_count; i++) + if (led_id == supported_led_ids[i]) + return 1; + + return 0; +} + +void led_auto_control(enum ec_led_id led_id, int enable) +{ + if (enable) + led_auto_control_flags |= LED_AUTO_CONTROL_FLAG(led_id); + else + led_auto_control_flags &= ~LED_AUTO_CONTROL_FLAG(led_id); +} + +int led_auto_control_is_enabled(enum ec_led_id led_id) +{ + return (led_auto_control_flags & LED_AUTO_CONTROL_FLAG(led_id)) != 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; + + args->response_size = sizeof(*r); + memset(r->brightness_range, 0, sizeof(r->brightness_range)); + + if (!led_is_supported(p->led_id)) + return EC_RES_INVALID_PARAM; + + led_get_brightness_range(p->led_id, r->brightness_range); + if (p->flags & EC_LED_FLAGS_QUERY) + return EC_RES_SUCCESS; + + for (i = 0; i < EC_LED_COLOR_COUNT; i++) + if (r->brightness_range[i] == 0 && p->brightness[i] != 0) + return EC_RES_INVALID_PARAM; + + if (p->flags & EC_LED_FLAGS_AUTO) + led_auto_control(p->led_id, 1); + else if (led_set_brightness(p->led_id, p->brightness) != EC_SUCCESS) + return EC_RES_INVALID_PARAM; + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_LED_CONTROL, led_command_control, EC_VER_MASK(1)); diff --git a/common/led_peppy.c b/common/led_peppy.c index aed913cb72..50a851b8ee 100644 --- a/common/led_peppy.c +++ b/common/led_peppy.c @@ -8,8 +8,12 @@ #include "battery.h" #include "charge_state.h" #include "chipset.h" +#include "ec_commands.h" #include "gpio.h" #include "hooks.h" +#include "host_command.h" +#include "led_common.h" +#include "util.h" #define LED_TOTAL_TICKS 16 #define LED_ON_TICKS 4 @@ -18,11 +22,19 @@ enum led_color { LED_OFF = 0, LED_BLUE, LED_AMBER, + LED_PINK, + LED_COLOR_COUNT /* Number of colors, not a color itself */ }; -static int led_set_color(enum led_color color, enum gpio_signal gpio_led_blue_l, - enum gpio_signal gpio_led_amber_l) +const enum ec_led_id supported_led_ids[] = { + EC_LED_ID_POWER_LED, EC_LED_ID_BATTERY_LED}; + +const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids); + +static int peppy_led_set_gpio(enum led_color color, + enum gpio_signal gpio_led_blue_l, + enum gpio_signal gpio_led_amber_l) { switch (color) { case LED_OFF: @@ -37,62 +49,121 @@ static int led_set_color(enum led_color color, enum gpio_signal gpio_led_blue_l, gpio_set_level(gpio_led_blue_l, 1); gpio_set_level(gpio_led_amber_l, 0); break; + case LED_PINK: + gpio_set_level(gpio_led_blue_l, 0); + gpio_set_level(gpio_led_amber_l, 0); + break; default: return EC_ERROR_UNKNOWN; } return EC_SUCCESS; } -static int bat_led_set_color(enum led_color color) +static int peppy_led_set_color_battery(enum led_color color) { - return led_set_color(color, GPIO_BAT_LED0_L, GPIO_BAT_LED1_L); + return peppy_led_set_gpio(color, GPIO_BAT_LED0_L, GPIO_BAT_LED1_L); } -static int pwr_led_set_color(enum led_color color) +static int peppy_led_set_color_power(enum led_color color) { - return led_set_color(color, GPIO_PWR_LED0_L, GPIO_PWR_LED1_L); + return peppy_led_set_gpio(color, GPIO_PWR_LED0_L, GPIO_PWR_LED1_L); } -/* Called by hook task every 250mSec */ -static void led_tick(void) +static int peppy_led_set_color(enum ec_led_id led_id, enum led_color color) { - static int ticks; - uint32_t chflags = charge_get_flags(); + int rv; - ticks++; + led_auto_control(led_id, 0); + switch (led_id) { + case EC_LED_ID_BATTERY_LED: + rv = peppy_led_set_color_battery(color); + break; + case EC_LED_ID_POWER_LED: + rv = peppy_led_set_color_power(color); + break; + default: + return EC_ERROR_UNKNOWN; + } + return rv; +} + +int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness) +{ + if (brightness[EC_LED_COLOR_BLUE] != 0 && + brightness[EC_LED_COLOR_YELLOW] != 0) + peppy_led_set_color(led_id, LED_PINK); + else if (brightness[EC_LED_COLOR_BLUE] != 0) + peppy_led_set_color(led_id, LED_BLUE); + else if (brightness[EC_LED_COLOR_YELLOW] != 0) + peppy_led_set_color(led_id, LED_AMBER); + else + peppy_led_set_color(led_id, LED_OFF); + return EC_SUCCESS; +} + +void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range) +{ + /* Ignoring led_id as both leds support the same colors */ + brightness_range[EC_LED_COLOR_BLUE] = 1; + brightness_range[EC_LED_COLOR_YELLOW] = 1; +} + +static void peppy_led_set_power(int ticks) +{ if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) - pwr_led_set_color(LED_OFF); + peppy_led_set_color_power(LED_OFF); else if (chipset_in_state(CHIPSET_STATE_ON)) - pwr_led_set_color(LED_BLUE); + peppy_led_set_color_power(LED_BLUE); else if (chipset_in_state(CHIPSET_STATE_SUSPEND)) /* Blink once every four seconds. */ - pwr_led_set_color((ticks % LED_TOTAL_TICKS < LED_ON_TICKS) ? + peppy_led_set_color_power( + (ticks % LED_TOTAL_TICKS < LED_ON_TICKS) ? LED_AMBER : LED_OFF); +} + +static void peppy_led_set_battery(int ticks) +{ + uint32_t chflags = charge_get_flags(); switch (charge_get_state()) { case PWR_STATE_CHARGE: - bat_led_set_color(LED_AMBER); + peppy_led_set_color_battery(LED_AMBER); break; case PWR_STATE_CHARGE_NEAR_FULL: - bat_led_set_color(LED_BLUE); + peppy_led_set_color_battery(LED_BLUE); break; case PWR_STATE_DISCHARGE: - bat_led_set_color(LED_OFF); + peppy_led_set_color_battery(LED_OFF); break; case PWR_STATE_ERROR: - bat_led_set_color((ticks & 0x2) ? LED_AMBER : LED_OFF); + peppy_led_set_color_battery( + (ticks & 0x2) ? LED_AMBER : LED_OFF); break; - case PWR_STATE_IDLE: /* External power connected in IDLE state. */ + case PWR_STATE_IDLE: /* External power connected in IDLE. */ if (chflags & CHARGE_FLAG_FORCE_IDLE) - bat_led_set_color((ticks & 0x4) ? LED_BLUE : LED_OFF); + peppy_led_set_color_battery( + (ticks & 0x4) ? LED_BLUE : LED_OFF); else - bat_led_set_color(LED_BLUE); + peppy_led_set_color_battery(LED_BLUE); break; default: /* Other states don't alter LED behavior */ break; } } -DECLARE_HOOK(HOOK_TICK, led_tick, HOOK_PRIO_DEFAULT); +/* Called by hook task every 250mSec */ +static void led_tick(void) +{ + static int ticks; + + ticks++; + + if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED)) + peppy_led_set_power(ticks); + + if (led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED)) + peppy_led_set_battery(ticks); +} +DECLARE_HOOK(HOOK_TICK, led_tick, HOOK_PRIO_DEFAULT); diff --git a/include/ec_commands.h b/include/ec_commands.h index 054478743b..019c1ab88f 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -989,9 +989,17 @@ enum lightbar_command { #define EC_CMD_LED_CONTROL 0x29 enum ec_led_id { + /* LED to indicate battery state of charge */ EC_LED_ID_BATTERY_LED = 0, - EC_LED_ID_POWER_BUTTON_LED, + /* + * LED to indicate system power state (on or in suspend). + * May be on power button or on C-panel. + */ + EC_LED_ID_POWER_LED, + /* LED on power adapter or its plug */ EC_LED_ID_ADAPTER_LED, + + EC_LED_ID_COUNT }; /* LED control flags */ diff --git a/include/led_common.h b/include/led_common.h new file mode 100644 index 0000000000..eb541743d8 --- /dev/null +++ b/include/led_common.h @@ -0,0 +1,63 @@ +/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Common functions for blinking LEDs. + */ + +#ifndef __CROS_EC_LED_COMMON_H +#define __CROS_EC_LED_COMMON_H + +#include "ec_commands.h" + +/* Defined in led_.c */ +extern const enum ec_led_id supported_led_ids[]; + +/* Defined in led_.c */ +extern const int supported_led_ids_count; + +/** + * Enable or diable automatic control of an LED. + * + * @param led_id ID of LED to enable or disable automatic control. + * @param enable 1 to enable . 0 to disable + * + */ +void led_auto_control(enum ec_led_id led_id, int enable); + +/** + * Whether an LED is under automatic control. + * + * @param led_id ID of LED to query. + * + * @returns 1 if LED is under automatic control. 0 if it is not. + * + */ +int led_auto_control_is_enabled(enum ec_led_id led_id); + +/** + * Query brightness per color channel for an LED. + * + * @param led_id ID of LED to query. + * @param brightness_range Points to EC_LED_COLOR_COUNT element array + * where current brightness will be stored. + * Value per color channel: + * 0 unsupported, + * 1 on/off control, + * 2 -> 255 max brightness under PWM control. + * + */ +void led_get_brightness_range(enum ec_led_id, uint8_t *brightness_range); + +/** + * Set brightness per color channel for an LED. + * + * @param led_id ID of LED to set. + * @param brightness Brightness per color channel to set. + * + * @returns EC_SUCCESS or EC_ERROR_INVAL + * + */ +int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness); + +#endif /* __CROS_EC_LED_COMMON_H */ diff --git a/util/ectool.c b/util/ectool.c index 60633e7aae..0ee39dcb9e 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -98,8 +98,8 @@ const char help_str[] = " Perform I2C transfer on EC's I2C bus\n" " keyscan \n" " Test low-level key scanning\n" - " led >\n" - " Set the color of LED\n" + " led | =...>\n" + " Set the color of an LED or query brightness range\n" " lightbar [CMDS]\n" " Various lightbar control commands\n" " panicinfo\n" @@ -169,6 +169,9 @@ static const char * const image_names[] = {"unknown", "RO", "RW"}; static const char * const led_color_names[EC_LED_COLOR_COUNT] = { "red", "green", "blue", "yellow", "white"}; +/* Note: depends on enum ec_led_id */ +static const char * const led_names[EC_LED_ID_COUNT] = { + "battery", "power", "adapter"}; /* Check SBS numerical value range */ int is_battery_range(int val) @@ -1425,7 +1428,6 @@ static int cmd_lightbar(int argc, char **argv) return lb_help(argv[0]); } - static int find_led_color_by_name(const char *color) { int i; @@ -1433,6 +1435,18 @@ static int find_led_color_by_name(const char *color) for (i = 0; i < EC_LED_COLOR_COUNT; ++i) if (!strcasecmp(color, led_color_names[i])) return i; + + return -1; +} + +static int find_led_id_by_name(const char *led) +{ + int i; + + for (i = 0; i < EC_LED_ID_COUNT; ++i) + if (!strcasecmp(led, led_names[i])) + return i; + return -1; } @@ -1448,14 +1462,18 @@ int cmd_led(int argc, char *argv[]) if (argc < 3) { fprintf(stderr, - "Usage: %s =...>\n", argv[0]); + "Usage: %s | =...>\n", argv[0]); return -1; } - p.led_id = strtol(argv[1], &e, 0); - if (e && *e) { - fprintf(stderr, "Bad LED ID.\n"); + p.led_id = find_led_id_by_name(argv[1]); + if (p.led_id == (uint8_t)-1) { + fprintf(stderr, "Bad LED name: %s\n", argv[1]); + fprintf(stderr, "Valid LED names: "); + for (i = 0; i < EC_LED_ID_COUNT; i++) + fprintf(stderr, "%s ", led_names[i]); + fprintf(stderr, "\n"); return -1; } @@ -1465,17 +1483,19 @@ int cmd_led(int argc, char *argv[]) &r, sizeof(r)); printf("Brightness range for LED %d:\n", p.led_id); if (rv < 0) { - fprintf(stderr, "Error. Not existing LED?\n"); + fprintf(stderr, "Error: Unsupported LED.\n"); return rv; } - for (i = 0; i < 5; ++i) + for (i = 0; i < EC_LED_COLOR_COUNT; ++i) printf("\t%s\t: 0x%x\n", led_color_names[i], r.brightness_range[i]); return 0; } - if (!strcasecmp(argv[2], "auto")) { + if (!strcasecmp(argv[2], "off")) { + /* Brightness initialized to 0 for each color. */ + } else if (!strcasecmp(argv[2], "auto")) { p.flags = EC_LED_FLAGS_AUTO; } else if ((i = find_led_color_by_name(argv[2])) != -1) { p.brightness[i] = 0xff; @@ -1485,6 +1505,11 @@ int cmd_led(int argc, char *argv[]) j = find_led_color_by_name(ptr); if (j == -1) { fprintf(stderr, "Bad color name: %s\n", ptr); + fprintf(stderr, "Valid colors: "); + for (j = 0; j < EC_LED_COLOR_COUNT; j++) + fprintf(stderr, "%s ", + led_color_names[j]); + fprintf(stderr, "\n"); return -1; } ptr = strtok(NULL, "="); -- cgit v1.2.1