diff options
author | Zick Wei <zick.wei@quanta.corp-partner.google.com> | 2020-02-05 14:10:52 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-02-15 05:34:08 +0000 |
commit | 1c47eb53c19749e1d81c7066ac4e8e1b023c8a6e (patch) | |
tree | 59907c5654e2f4dce895ba9c08f6e42fa04e5d60 /board | |
parent | 987a2440df3dd4b9036882d9da5c337410659d71 (diff) | |
download | chrome-ec-1c47eb53c19749e1d81c7066ac4e8e1b023c8a6e.tar.gz |
morphius: add Power/Battery LED behavior
This CL add morphius Power/Battery led behavior as below:
Power LED:
AC connect: 0.25s ON/0.25s OFF, repeat 3 times
System on: ON
System in S3: Gradual 1 s ON, Gradual 1 s OFF, 3s OFF
System off: OFF
Battery LED:
Battery Charging 0%~90%: Amber
Battery Charging 91%~100%: White
Not connected AC: OFF
BUG=b:146309932
BRANCH=none
TEST=manual verify LEDs behavior meet spec.
Change-Id: I75be8589e0d28b3b77da9b9bdb5713208d567be1
Signed-off-by: Zick Wei <zick.wei@quanta.corp-partner.google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2038551
Reviewed-by: Denis Brockus <dbrockus@chromium.org>
Diffstat (limited to 'board')
-rw-r--r-- | board/morphius/board.h | 1 | ||||
-rw-r--r-- | board/morphius/led.c | 234 |
2 files changed, 196 insertions, 39 deletions
diff --git a/board/morphius/board.h b/board/morphius/board.h index cf9ea084fa..9109358a7d 100644 --- a/board/morphius/board.h +++ b/board/morphius/board.h @@ -19,6 +19,7 @@ #define CONFIG_MKBP_USE_GPIO +#undef CONFIG_LED_ONOFF_STATES /* Battery */ #define CONFIG_BATTERY_LEVEL_NEAR_FULL 91 diff --git a/board/morphius/led.c b/board/morphius/led.c index 9f3f7492c0..fc8ea5d66b 100644 --- a/board/morphius/led.c +++ b/board/morphius/led.c @@ -3,68 +3,224 @@ * found in the LICENSE file. */ +#include "battery.h" +#include "charge_manager.h" +#include "charge_state.h" +#include "chipset.h" #include "ec_commands.h" +#include "extpower.h" #include "gpio.h" +#include "hooks.h" #include "led_common.h" -#include "led_onoff_states.h" - -#define LED_OFF_LVL 1 -#define LED_ON_LVL 0 - -const int led_charge_lvl_1; -const int led_charge_lvl_2 = 100; - -struct led_descriptor led_bat_state_table[LED_NUM_STATES][LED_NUM_PHASES] = { - [STATE_CHARGING_LVL_1] = {{EC_LED_COLOR_GREEN, 2 * LED_ONE_SEC}, - {EC_LED_COLOR_RED, 2 * LED_ONE_SEC} }, - [STATE_CHARGING_LVL_2] = {{EC_LED_COLOR_RED, LED_INDEFINITE} }, - [STATE_CHARGING_FULL_CHARGE] = {{EC_LED_COLOR_GREEN, LED_INDEFINITE} }, - [STATE_DISCHARGE_S0] = {{EC_LED_COLOR_GREEN, LED_INDEFINITE} }, - [STATE_DISCHARGE_S3] = {{EC_LED_COLOR_RED, 1 * LED_ONE_SEC}, - {LED_OFF, 3 * LED_ONE_SEC} }, - [STATE_DISCHARGE_S5] = {{LED_OFF, LED_INDEFINITE} }, - [STATE_BATTERY_ERROR] = {{EC_LED_COLOR_GREEN, 2 * LED_ONE_SEC}, - {EC_LED_COLOR_RED, 2 * LED_ONE_SEC} }, - [STATE_FACTORY_TEST] = {{EC_LED_COLOR_GREEN, LED_INDEFINITE} }, -}; -BUILD_ASSERT(ARRAY_SIZE(led_bat_state_table) == LED_NUM_STATES); +#include "pwm.h" +#include "timer.h" +#include "util.h" + +#define LED_BAT_OFF_LVL 1 +#define LED_BAT_ON_LVL 0 +#define LED_BAT_S3_OFF_TIME_MS 3000 +#define LED_BAT_S3_PWM_RESCALE 5 +#define LED_BAT_S3_TICK_MS 50 + +#define LED_TOTAL_TICKS 2 +#define LED_ON_TICKS 1 + +#define LED_PWR_TICKS_PER_CYCLE 7 -const enum ec_led_id supported_led_ids[] = { EC_LED_ID_BATTERY_LED }; +#define TICKS_STEP1_BRIGHTER 0 +#define TICKS_STEP2_DIMMER 20 +#define TICKS_STEP3_OFF 40 + +static int ticks; + +const enum ec_led_id supported_led_ids[] = { + EC_LED_ID_BATTERY_LED, + EC_LED_ID_POWER_LED +}; const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids); +enum led_color { + LED_OFF = 0, + LED_WHITE, + LED_AMBER, + LED_COLOR_COUNT /* Number of colors, not a color itself */ +}; + +/* PWM brightness vs. color, in the order of off, white */ +static const uint8_t color_brightness[2] = { + [LED_OFF] = 0, + [LED_WHITE] = 100, +}; + +void led_set_color_power(enum ec_led_colors color) +{ + pwm_set_duty(PWM_CH_POWER_LED, color_brightness[color]); +} + void led_set_color_battery(enum ec_led_colors color) { switch (color) { - case EC_LED_COLOR_GREEN: - gpio_set_level(GPIO_LED_FULL_L, LED_ON_LVL); - gpio_set_level(GPIO_LED_CHRG_L, LED_OFF_LVL); + case LED_AMBER: + gpio_set_level(GPIO_LED_FULL_L, LED_BAT_OFF_LVL); + gpio_set_level(GPIO_LED_CHRG_L, LED_BAT_ON_LVL); break; - case EC_LED_COLOR_RED: - gpio_set_level(GPIO_LED_FULL_L, LED_OFF_LVL); - gpio_set_level(GPIO_LED_CHRG_L, LED_ON_LVL); + case LED_WHITE: + gpio_set_level(GPIO_LED_FULL_L, LED_BAT_ON_LVL); + gpio_set_level(GPIO_LED_CHRG_L, LED_BAT_OFF_LVL); break; default: /* LED_OFF and other unsupported colors */ - gpio_set_level(GPIO_LED_FULL_L, LED_OFF_LVL); - gpio_set_level(GPIO_LED_CHRG_L, LED_OFF_LVL); + gpio_set_level(GPIO_LED_FULL_L, LED_BAT_OFF_LVL); + gpio_set_level(GPIO_LED_CHRG_L, LED_BAT_OFF_LVL); break; } } void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range) { - brightness_range[EC_LED_COLOR_GREEN] = 1; - brightness_range[EC_LED_COLOR_RED] = 1; + if (led_id == EC_LED_ID_BATTERY_LED) { + brightness_range[EC_LED_COLOR_AMBER] = 1; + brightness_range[EC_LED_COLOR_WHITE] = 1; + } else if (led_id == EC_LED_ID_POWER_LED) { + brightness_range[EC_LED_COLOR_WHITE] = 100; + } } int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness) { - if (brightness[EC_LED_COLOR_GREEN] != 0) - led_set_color_battery(EC_LED_COLOR_GREEN); - else if (brightness[EC_LED_COLOR_RED] != 0) - led_set_color_battery(EC_LED_COLOR_RED); - else - led_set_color_battery(LED_OFF); + if (led_id == EC_LED_ID_BATTERY_LED) { + if (brightness[EC_LED_COLOR_AMBER] != 0) + led_set_color_battery(LED_AMBER); + else if (brightness[EC_LED_COLOR_WHITE] != 0) + led_set_color_battery(LED_WHITE); + else + led_set_color_battery(LED_OFF); + } else if (led_id == EC_LED_ID_POWER_LED) { + if (brightness[EC_LED_COLOR_WHITE] != 0) + pwm_set_duty(PWM_CH_POWER_LED, + color_brightness[LED_WHITE]); + else + pwm_set_duty(PWM_CH_POWER_LED, + color_brightness[LED_OFF]); + } return EC_SUCCESS; } + +static void suspend_led_update_deferred(void); +DECLARE_DEFERRED(suspend_led_update_deferred); + +static void suspend_led_update_deferred(void) +{ + int delay = LED_BAT_S3_TICK_MS * MSEC; + + ticks++; + + /* 1s gradual on, 1s gradual off, 3s off */ + if (ticks <= TICKS_STEP2_DIMMER) { + pwm_set_duty(PWM_CH_POWER_LED, ticks * LED_BAT_S3_PWM_RESCALE); + } else if (ticks <= TICKS_STEP3_OFF) { + pwm_set_duty(PWM_CH_POWER_LED, + (TICKS_STEP3_OFF - ticks) * LED_BAT_S3_PWM_RESCALE); + } else { + ticks = TICKS_STEP1_BRIGHTER; + delay = LED_BAT_S3_OFF_TIME_MS * 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_battery(void) +{ + switch (charge_get_state()) { + case PWR_STATE_CHARGE: + /* Always indicate when charging, even in suspend. */ + led_set_color_battery(LED_AMBER); + break; + case PWR_STATE_DISCHARGE: + led_set_color_battery(LED_OFF); + break; + case PWR_STATE_CHARGE_NEAR_FULL: + led_set_color_battery(LED_WHITE); + break; + case PWR_STATE_IDLE: /* External power connected in IDLE */ + led_set_color_battery(LED_WHITE); + break; + default: + /* Other states don't alter LED behavior */ + break; + } +} + +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 < LED_PWR_TICKS_PER_CYCLE) { + led_set_color_power( + (power_ticks % LED_TOTAL_TICKS) < LED_ON_TICKS ? + LED_WHITE : 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_WHITE); +} + +static void pwr_led_init(void) +{ + /* Configure GPIOs */ + gpio_config_module(MODULE_PWM, 1); + + /* + * 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_POWER_LED, 1); + led_set_color_power(LED_OFF); +} +DECLARE_HOOK(HOOK_INIT, pwr_led_init, HOOK_PRIO_DEFAULT); + +/* Called by hook task every 200 ms */ +static void led_tick(void) +{ + if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED)) + led_set_power(); + if (led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED)) + led_set_battery(); +} +DECLARE_HOOK(HOOK_TICK, led_tick, HOOK_PRIO_DEFAULT); |