From 3df0f6a8d0212013e1543072be3b79b96133fe39 Mon Sep 17 00:00:00 2001 From: Bruce Date: Thu, 20 Oct 2016 19:01:46 +0800 Subject: Pyro: modify led behaivor for Pyro spec modify led behaivor for Pyro spec BUG=chrome-os-partner:58696 BRANCH=None TEST=make buildall Signed-off-by: Bruce.Wan Change-Id: I072dee0d15e83e6ea537b52e5475ed6c894e64ef Reviewed-on: https://chromium-review.googlesource.com/403578 Commit-Ready: Keith Tzeng Tested-by: Keith Tzeng Reviewed-by: Aaron Durbin --- board/pyro/board.c | 3 +- board/pyro/board.h | 1 - board/pyro/gpio.inc | 6 +- board/pyro/led.c | 258 ++++++++++++++++++++++++++++++++++------------------ 4 files changed, 176 insertions(+), 92 deletions(-) diff --git a/board/pyro/board.c b/board/pyro/board.c index 6ca7183dc8..ddd4c7976b 100644 --- a/board/pyro/board.c +++ b/board/pyro/board.c @@ -122,7 +122,6 @@ BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT); /* PWM channels. Must be in the exactly same order as in enum pwm_channel. */ const struct pwm_t pwm_channels[] = { - [PWM_CH_LED_GREEN] = { 2, PWM_CONFIG_DSLEEP, 100 }, [PWM_CH_LED_RED] = { 3, PWM_CONFIG_DSLEEP, 100 }, }; BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT); @@ -661,7 +660,7 @@ void board_hibernate_late(void) int i; const uint32_t hibernate_pins[][2] = { /* Turn off LEDs in hibernate */ - {GPIO_BAT_LED_BLUE, GPIO_INPUT | GPIO_PULL_UP}, + {GPIO_BAT_LED_GREEN, GPIO_INPUT | GPIO_PULL_UP}, {GPIO_BAT_LED_AMBER, GPIO_INPUT | GPIO_PULL_UP}, {GPIO_LID_OPEN, GPIO_INT_RISING | GPIO_PULL_DOWN}, diff --git a/board/pyro/board.h b/board/pyro/board.h index f34dccfbf6..f3bf4bcea4 100644 --- a/board/pyro/board.h +++ b/board/pyro/board.h @@ -208,7 +208,6 @@ enum adc_channel { }; enum pwm_channel { - PWM_CH_LED_GREEN = 0, PWM_CH_LED_RED, /* Number of PWM channels */ PWM_CH_COUNT diff --git a/board/pyro/gpio.inc b/board/pyro/gpio.inc index 3f7c3de444..fea1b8e81a 100644 --- a/board/pyro/gpio.inc +++ b/board/pyro/gpio.inc @@ -135,11 +135,10 @@ GPIO(USB_C1_5V_EN, PIN(D, 2), GPIO_OUT_LOW) /* EN_USB_C1_5V_OUT, Enable C1 */ /* Clear for non-HDI breakout, must be pulled high */ GPIO(NC1, PIN(0, 0), GPIO_INPUT | GPIO_PULL_UP | GPIO_SEL_1P8V) -GPIO(NC2, PIN(8, 4), GPIO_INPUT | GPIO_PULL_UP | GPIO_SEL_1P8V) GPIO(ENG_STRAP, PIN(B, 6), GPIO_INPUT) -GPIO(BAT_LED_BLUE, PIN(8, 0), GPIO_OUT_HIGH) +GPIO(BAT_LED_GREEN, PIN(8, 4), GPIO_OUT_HIGH) GPIO(BAT_LED_AMBER, PIN(C, 4), GPIO_OUT_HIGH) /* @@ -168,3 +167,6 @@ ALTERNATE(PIN_MASK(D, 0x03), 1, MODULE_I2C, 0) /* GPIOD1-D0 for EC_I2C_POWER_SDA /* FIXME: Make UART RX an interrupt? */ ALTERNATE(PIN_MASK(6, 0x30), 0, MODULE_UART, 0) /* UART from EC to Servo */ + +/* LED PWM */ +ALTERNATE(PIN_MASK(8, 0x01), 1, MODULE_PWM, GPIO_OUTPUT) /* GPIO80: PWM3 */ diff --git a/board/pyro/led.c b/board/pyro/led.c index dd028f1b65..2a2be4c867 100644 --- a/board/pyro/led.c +++ b/board/pyro/led.c @@ -8,33 +8,46 @@ #include "battery.h" #include "charge_state.h" #include "chipset.h" +#include "console.h" #include "ec_commands.h" #include "extpower.h" #include "gpio.h" #include "hooks.h" #include "host_command.h" #include "led_common.h" +#include "pwm.h" #include "util.h" -#define BAT_LED_ON 0 -#define BAT_LED_OFF 1 +#define CPRINTF(format, args...) cprintf(CC_PWM, format, ## args) +#define CPRINTS(format, args...) cprints(CC_PWM, format, ## args) + +#define BAT_LED_ON 1 +#define BAT_LED_OFF 0 #define CRITICAL_LOW_BATTERY_PERCENTAGE 3 #define LOW_BATTERY_PERCENTAGE 10 -#define LED_TOTAL_4SECS_TICKS 4 -#define LED_TOTAL_2SECS_TICKS 2 -#define LED_ON_1SEC_TICKS 1 -#define LED_ON_2SECS_TICKS 2 +#define LED_TOTAL_TICKS 2 +#define LED_ON_TICKS 1 + +#define TICKS_STEP1_BRIGHTER 0 +#define TICKS_STEP2_DIMMER 20 +#define TICKS_STEP3_OFF 40 + +#define FULL_BATTERY_PERMILLAGE 875 + +static int led_debug; +static int ticks; const enum ec_led_id supported_led_ids[] = { - EC_LED_ID_BATTERY_LED}; + EC_LED_ID_POWER_LED, EC_LED_ID_BATTERY_LED}; const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids); enum led_color { LED_OFF = 0, - LED_BLUE, + LED_RED, + LED_GREEN, LED_AMBER, LED_COLOR_COUNT /* Number of colors, not a color itself */ }; @@ -43,15 +56,15 @@ static int led_set_color_battery(enum led_color color) { switch (color) { case LED_OFF: - gpio_set_level(GPIO_BAT_LED_BLUE, BAT_LED_OFF); + gpio_set_level(GPIO_BAT_LED_GREEN, BAT_LED_OFF); gpio_set_level(GPIO_BAT_LED_AMBER, BAT_LED_OFF); break; - case LED_BLUE: - gpio_set_level(GPIO_BAT_LED_BLUE, BAT_LED_ON); + case LED_GREEN: + gpio_set_level(GPIO_BAT_LED_GREEN, BAT_LED_ON); gpio_set_level(GPIO_BAT_LED_AMBER, BAT_LED_OFF); break; case LED_AMBER: - gpio_set_level(GPIO_BAT_LED_BLUE, BAT_LED_OFF); + gpio_set_level(GPIO_BAT_LED_GREEN, BAT_LED_OFF); gpio_set_level(GPIO_BAT_LED_AMBER, BAT_LED_ON); break; default: @@ -60,34 +73,32 @@ static int led_set_color_battery(enum led_color color) return EC_SUCCESS; } -void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range) +/* Brightness vs. color, in the order of off, red */ +static const uint8_t color_brightness[2] = { + [LED_OFF] = 100, + [LED_RED] = 0, +}; + +static void led_set_color_power(enum led_color color) { - brightness_range[EC_LED_COLOR_BLUE] = 1; - brightness_range[EC_LED_COLOR_AMBER] = 1; + pwm_set_duty(PWM_CH_LED_RED, color_brightness[color]); } -static int led_set_color(enum ec_led_id led_id, enum led_color color) +void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range) { - int rv; - - switch (led_id) { - case EC_LED_ID_BATTERY_LED: - rv = led_set_color_battery(color); - break; - default: - return EC_ERROR_UNKNOWN; - } - return rv; + brightness_range[EC_LED_COLOR_RED] = 100; + brightness_range[EC_LED_COLOR_GREEN] = 1; + brightness_range[EC_LED_COLOR_AMBER] = 1; } int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness) { - if (brightness[EC_LED_COLOR_BLUE] != 0) - led_set_color(led_id, LED_BLUE); + if (brightness[EC_LED_COLOR_GREEN] != 0) + led_set_color_battery(LED_GREEN); else if (brightness[EC_LED_COLOR_AMBER] != 0) - led_set_color(led_id, LED_AMBER); + led_set_color_battery(LED_AMBER); else - led_set_color(led_id, LED_OFF); + led_set_color_battery(LED_OFF); return EC_SUCCESS; } @@ -95,80 +106,153 @@ int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness) static void led_set_battery(void) { static int battery_ticks; - static int suspend_ticks; - static int previous_state_suspend; - uint32_t chflags = charge_get_flags(); + int remaining_capacity; + int full_charge_capacity; + int permillage; battery_ticks++; - suspend_ticks++; + + remaining_capacity = *(int *)host_get_memmap(EC_MEMMAP_BATT_CAP); + full_charge_capacity = *(int *)host_get_memmap(EC_MEMMAP_BATT_LFCC); + permillage = !full_charge_capacity ? 0 : + (1000 * remaining_capacity) / full_charge_capacity; + switch (charge_get_state()) { case PWR_STATE_CHARGE: - led_set_color_battery(LED_AMBER); - break; - case PWR_STATE_DISCHARGE: - /* Less than 3%, blink one second every two second */ - if (!chipset_in_state(CHIPSET_STATE_ANY_OFF) && - charge_get_percent() < CRITICAL_LOW_BATTERY_PERCENTAGE) - led_set_color_battery( - (battery_ticks % LED_TOTAL_2SECS_TICKS < - LED_ON_1SEC_TICKS) ? LED_AMBER : LED_OFF); - /* Less than 10%, blink one second every four seconds */ - else if (!chipset_in_state(CHIPSET_STATE_ANY_OFF) && - charge_get_percent() < LOW_BATTERY_PERCENTAGE) - led_set_color_battery( - (battery_ticks % LED_TOTAL_4SECS_TICKS < - LED_ON_1SEC_TICKS) ? LED_AMBER : LED_OFF); - else { - if (chipset_in_state(CHIPSET_STATE_SUSPEND - | CHIPSET_STATE_STANDBY)) { - if (!previous_state_suspend) - suspend_ticks = 0; - /* Blink once every four seconds. */ - led_set_color_battery( - (suspend_ticks % LED_TOTAL_4SECS_TICKS) - < LED_ON_1SEC_TICKS ? - LED_AMBER : LED_OFF); - previous_state_suspend = 1; - return; - } - - if (chipset_in_state(CHIPSET_STATE_ON)) - led_set_color_battery(LED_BLUE); - else - led_set_color_battery(LED_OFF); - } - break; - case PWR_STATE_ERROR: - led_set_color_battery( - (battery_ticks % LED_TOTAL_2SECS_TICKS < - LED_ON_1SEC_TICKS) ? LED_AMBER : LED_OFF); + led_set_color_battery(permillage < + FULL_BATTERY_PERMILLAGE ? LED_AMBER : LED_GREEN); break; case PWR_STATE_CHARGE_NEAR_FULL: - led_set_color_battery(LED_BLUE); - break; - case PWR_STATE_IDLE: /* External power connected in IDLE */ - if (chflags & CHARGE_FLAG_FORCE_IDLE) - led_set_color_battery( - (battery_ticks % LED_TOTAL_4SECS_TICKS < - LED_ON_2SECS_TICKS) ? LED_AMBER : LED_BLUE); - else - led_set_color_battery(LED_BLUE); + led_set_color_battery(LED_GREEN); break; default: /* Other states don't alter LED behavior */ + led_set_color_battery(LED_OFF); break; } +} + +static void suspend_led_update_deferred(void); +DECLARE_DEFERRED(suspend_led_update_deferred); + +static void suspend_led_update_deferred(void) +{ + int delay = 50 * MSEC; + + ticks++; + + if (ticks <= TICKS_STEP2_DIMMER) { + pwm_set_duty(PWM_CH_LED_RED, (TICKS_STEP2_DIMMER - ticks)*5); + } else if (ticks <= TICKS_STEP3_OFF) { + pwm_set_duty(PWM_CH_LED_RED, (ticks - TICKS_STEP2_DIMMER)*5); + } else { + ticks = TICKS_STEP1_BRIGHTER; + delay = 3000 * MSEC; + } + + hook_call_deferred(&suspend_led_update_deferred_data, delay); +} + +static void suspend_led_init(void) +{ + ticks = TICKS_STEP2_DIMMER; + + hook_call_deferred(&suspend_led_update_deferred_data, 0); +} +DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, suspend_led_init, HOOK_PRIO_DEFAULT); + +static void suspend_led_deinit(void) +{ + hook_call_deferred(&suspend_led_update_deferred_data, -1); +} +DECLARE_HOOK(HOOK_CHIPSET_RESUME, suspend_led_deinit, HOOK_PRIO_DEFAULT); +DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, suspend_led_deinit, HOOK_PRIO_DEFAULT); + +static void led_set_power(void) +{ + static int power_ticks; + static int previous_state_suspend; + static int blink_ticks; + + power_ticks++; + + /* Blink 3 times (0.25s on/0.25s off, repeat 3 times) */ + if (extpower_is_present()) { + blink_ticks++; + if (!previous_state_suspend) + power_ticks = 0; + + while (blink_ticks < 7) { + led_set_color_power( + (power_ticks % LED_TOTAL_TICKS) < LED_ON_TICKS ? + LED_RED : LED_OFF); + + previous_state_suspend = 1; + return; + } + } + if (!extpower_is_present()) + blink_ticks = 0; + previous_state_suspend = 0; + + if (chipset_in_state(CHIPSET_STATE_SOFT_OFF)) + led_set_color_power(LED_OFF); + if (chipset_in_state(CHIPSET_STATE_ON)) + led_set_color_power(LED_RED); } -/* Called by hook task every 1 sec */ -static void led_second(void) +static void led_init(void) { + /* Configure GPIOs */ + gpio_config_module(MODULE_PWM, 1); + /* - * Reference board only has one LED, so overload it to act as both - * power LED and battery LED. + * Enable PWMs and set to 0% duty cycle. If they're disabled, + * seems to ground the pins instead of letting them float. */ + pwm_enable(PWM_CH_LED_RED, 1); + + led_set_color_power(LED_OFF); +} +DECLARE_HOOK(HOOK_INIT, led_init, HOOK_PRIO_DEFAULT); + +/* Called by hook task every 25 ms */ +static void led_tick(void) +{ + if (led_debug) + return; + if (led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED)) led_set_battery(); + if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED)) + led_set_power(); +} +DECLARE_HOOK(HOOK_TICK, led_tick, HOOK_PRIO_DEFAULT); + +/******************************************************************/ +/* Console commands */ +static int command_led_color(int argc, char **argv) +{ + if (argc > 1) { + if (!strcasecmp(argv[1], "debug")) { + led_debug ^= 1; + CPRINTF("led_debug = %d\n", led_debug); + } else if (!strcasecmp(argv[1], "off")) { + led_set_color_power(LED_OFF); + led_set_color_battery(LED_OFF); + } else if (!strcasecmp(argv[1], "red")) { + led_set_color_power(LED_RED); + } else if (!strcasecmp(argv[1], "green")) { + led_set_color_battery(LED_GREEN); + } else if (!strcasecmp(argv[1], "amber")) { + led_set_color_battery(LED_AMBER); + } else { + return EC_ERROR_PARAM1; + } + } + return EC_SUCCESS; } -DECLARE_HOOK(HOOK_SECOND, led_second, HOOK_PRIO_DEFAULT); +DECLARE_CONSOLE_COMMAND(ledcolor, command_led_color, + "[debug|red|green|amber|off]", + "Change LED color"); -- cgit v1.2.1