summaryrefslogtreecommitdiff
path: root/board
diff options
context:
space:
mode:
authorZick Wei <zick.wei@quanta.corp-partner.google.com>2020-02-05 14:10:52 +0800
committerCommit Bot <commit-bot@chromium.org>2020-02-15 05:34:08 +0000
commit1c47eb53c19749e1d81c7066ac4e8e1b023c8a6e (patch)
tree59907c5654e2f4dce895ba9c08f6e42fa04e5d60 /board
parent987a2440df3dd4b9036882d9da5c337410659d71 (diff)
downloadchrome-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.h1
-rw-r--r--board/morphius/led.c234
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);