summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Collyer <scollyer@google.com>2017-09-27 12:24:06 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-10-06 13:47:13 -0700
commit0dac0876e52321015600792a98b3f17033fb643f (patch)
tree0be6dceb139ce7c246efd6b205879b65a0514c05
parentb87fe062eca43fc00909098e716581bf2aeea7eb (diff)
downloadchrome-ec-0dac0876e52321015600792a98b3f17033fb643f.tar.gz
coral: Modify LED code to support different behavior based on SKU ID
Implemented an led state table based implementation for LED control of the battery LED. The states are the same as previous Coral/Reef single LED control with the exception of allowing for 3 charging states based on the current battery state of charge level. Now the desired state is determined and that's used to access the correct LED behavior based on the current tick count. Changed from a one second tick to the NPCX 200 msec tick so the Robo power button pattern can be supported as well. The are currently two tables implemented, one for Robo devices, and the default table. At init time, after the SKU ID is determined, the correct table is assigned. BUG=b:64192049 BRANCH=None TEST=Manual Tested both Coral proto and Robo EVT systems. Verifed operation in the different states. During tested used modified charging level tables so the 3 different charging states could be exercised. Also removed battery to verify the error state. Change-Id: Ifc6935f73d4fed1eeec9c5aab13f6346f61857ff Signed-off-by: Scott Collyer <scollyer@google.com> Reviewed-on: https://chromium-review.googlesource.com/693387 Commit-Ready: Scott Collyer <scollyer@chromium.org> Tested-by: Scott Collyer <scollyer@chromium.org> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
-rw-r--r--board/coral/led.c252
1 files changed, 183 insertions, 69 deletions
diff --git a/board/coral/led.c b/board/coral/led.c
index ebca865b48..671b02f228 100644
--- a/board/coral/led.c
+++ b/board/coral/led.c
@@ -14,45 +14,115 @@
#include "hooks.h"
#include "host_command.h"
#include "led_common.h"
+#include "system.h"
#include "util.h"
-#define BAT_LED_ON 0
-#define BAT_LED_OFF 1
-
-#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_ON_LVL 0
+#define LED_OFF_LVL 1
+#define LED_INDEFINITE -1
+#define LED_ONE_SEC (1000 / HOOK_TICK_INTERVAL_MS)
+#define LED_CHARGE_LEVEL_1_DEFAULT 100
+#define LED_CHARGE_LEVEL_1_ROBO 5
const enum ec_led_id supported_led_ids[] = {
EC_LED_ID_BATTERY_LED};
const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids);
+#define GPIO_LED_COLOR_1 GPIO_BAT_LED_AMBER
+#define GPIO_LED_COLOR_2 GPIO_BAT_LED_BLUE
+#define GPIO_LED_COLOR_3 GPIO_POW_LED
+
+enum led_phase {
+ LED_PHASE_0,
+ LED_PHASE_1,
+ LED_NUM_PHASES
+};
+
enum led_color {
- LED_OFF = 0,
- LED_BLUE,
- LED_AMBER,
+ LED_OFF,
+ LED_COLOR_1,
+ LED_COLOR_2,
+ LED_COLOR_BOTH,
LED_COLOR_COUNT /* Number of colors, not a color itself */
};
+enum led_states {
+ STATE_CHARGING_LVL_1,
+ STATE_CHARGING_LVL_2,
+ STATE_CHARGING_LVL_3,
+ STATE_DISCHARGE_S0,
+ STATE_DISCHARGE_S3,
+ STATE_DISCHARGE_S5,
+ STATE_BATTERY_ERROR,
+ STATE_FACTORY_TEST,
+ LED_NUM_STATES
+};
+
+struct led_descriptor {
+ int8_t color;
+ int8_t time;
+};
+
+struct led_info {
+ enum led_states state;
+ uint8_t charge_lvl_1;
+ const struct led_descriptor (*state_table)[LED_NUM_PHASES];
+ void (*update_power)(void);
+};
+
+/*
+ * LED state tables describe the desired LED behavior for a each possible
+ * state. The LED state is based on both chip power state and the battery charge
+ * level. The first parameter is the color and the 2nd parameter is the time in
+ * ticks, where each tick is 200 msec. If the time parameter is set to -1, that
+ * means it is a non-blinking pattern.
+ */
+
+/* COLOR_1 = Amber, COLOR_2 = Blue */
+static const struct led_descriptor led_default_state_table[][LED_NUM_PHASES] = {
+ { {LED_COLOR_1, LED_INDEFINITE}, {LED_OFF, LED_INDEFINITE} },
+ { {LED_COLOR_2, LED_INDEFINITE}, {LED_COLOR_1, LED_INDEFINITE} },
+ { {LED_COLOR_2, LED_INDEFINITE}, {LED_OFF, LED_INDEFINITE} },
+ { {LED_COLOR_2, LED_INDEFINITE}, {LED_OFF, LED_INDEFINITE} },
+ { {LED_COLOR_2, LED_INDEFINITE}, {LED_OFF, LED_INDEFINITE} },
+ { {LED_OFF, LED_INDEFINITE}, {LED_OFF, LED_INDEFINITE} },
+ { {LED_COLOR_1, 1 * LED_ONE_SEC}, {LED_COLOR_2, 1 * LED_ONE_SEC} },
+ { {LED_COLOR_1, 2 * LED_ONE_SEC}, {LED_COLOR_2, 2 * LED_ONE_SEC} },
+};
+
+/* COLOR_1 = Green, COLOR_2 = Red */
+static const struct led_descriptor led_robo_state_table[][LED_NUM_PHASES] = {
+ { {LED_COLOR_2, LED_INDEFINITE}, {LED_OFF, LED_INDEFINITE} },
+ { {LED_COLOR_1, LED_INDEFINITE}, {LED_OFF, LED_INDEFINITE} },
+ { {LED_COLOR_BOTH, LED_INDEFINITE}, {LED_OFF, LED_INDEFINITE} },
+ { {LED_OFF, LED_INDEFINITE}, {LED_OFF, LED_INDEFINITE} },
+ { {LED_OFF, LED_INDEFINITE}, {LED_OFF, LED_INDEFINITE} },
+ { {LED_OFF, LED_INDEFINITE}, {LED_OFF, LED_INDEFINITE} },
+ { {LED_COLOR_2, 1 * LED_ONE_SEC}, {LED_OFF, 1 * LED_ONE_SEC} },
+ { {LED_COLOR_2, 2 * LED_ONE_SEC}, {LED_COLOR_1, 2 * LED_ONE_SEC} },
+};
+
+static struct led_info led;
+
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_AMBER, BAT_LED_OFF);
+ gpio_set_level(GPIO_LED_COLOR_1, LED_OFF_LVL);
+ gpio_set_level(GPIO_LED_COLOR_2, LED_OFF_LVL);
break;
- case LED_BLUE:
- gpio_set_level(GPIO_BAT_LED_BLUE, BAT_LED_ON);
- gpio_set_level(GPIO_BAT_LED_AMBER, BAT_LED_OFF);
+ case LED_COLOR_1:
+ gpio_set_level(GPIO_LED_COLOR_1, LED_ON_LVL);
+ gpio_set_level(GPIO_LED_COLOR_2, LED_OFF_LVL);
break;
- case LED_AMBER:
- gpio_set_level(GPIO_BAT_LED_BLUE, BAT_LED_OFF);
- gpio_set_level(GPIO_BAT_LED_AMBER, BAT_LED_ON);
+ case LED_COLOR_2:
+ gpio_set_level(GPIO_LED_COLOR_1, LED_OFF_LVL);
+ gpio_set_level(GPIO_LED_COLOR_2, LED_ON_LVL);
+ break;
+ case LED_COLOR_BOTH:
+ gpio_set_level(GPIO_LED_COLOR_1, LED_ON_LVL);
+ gpio_set_level(GPIO_LED_COLOR_2, LED_ON_LVL);
break;
default:
return EC_ERROR_UNKNOWN;
@@ -64,93 +134,137 @@ void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range)
{
brightness_range[EC_LED_COLOR_BLUE] = 1;
brightness_range[EC_LED_COLOR_AMBER] = 1;
-}
-
-static int led_set_color(enum ec_led_id led_id, enum led_color color)
-{
- 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] = 1;
+ brightness_range[EC_LED_COLOR_GREEN] = 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);
+ led_set_color_battery(GPIO_LED_COLOR_2);
else if (brightness[EC_LED_COLOR_AMBER] != 0)
- led_set_color(led_id, LED_AMBER);
+ led_set_color_battery(GPIO_LED_COLOR_1);
+ else if (brightness[EC_LED_COLOR_RED] != 0)
+ led_set_color_battery(GPIO_LED_COLOR_2);
+ else if (brightness[EC_LED_COLOR_RED] != 0)
+ led_set_color_battery(GPIO_LED_COLOR_1);
else
- led_set_color(led_id, LED_OFF);
+ led_set_color_battery(LED_OFF);
return EC_SUCCESS;
}
-static void led_set_battery(void)
+static enum led_states led_get_state(void)
{
- static int battery_ticks;
- static int suspend_ticks;
+ int charge_lvl;
+ enum led_states new_state = LED_NUM_STATES;
switch (charge_get_state()) {
case PWR_STATE_CHARGE:
- led_set_color_battery(LED_AMBER);
+ /* Get percent charge */
+ charge_lvl = charge_get_percent();
+ /* Determine which charge state to use */
+ new_state = charge_lvl <= led.charge_lvl_1 ?
+ STATE_CHARGING_LVL_1 : STATE_CHARGING_LVL_2;
break;
case PWR_STATE_DISCHARGE_FULL:
if (extpower_is_present()) {
- led_set_color_battery(LED_BLUE);
+ new_state = STATE_CHARGING_LVL_3;
break;
}
/* Intentional fall-through */
case PWR_STATE_DISCHARGE /* and PWR_STATE_DISCHARGE_FULL */:
- if (chipset_in_state(CHIPSET_STATE_ON)) {
- led_set_color_battery(LED_BLUE);
- } else if (chipset_in_state(CHIPSET_STATE_SUSPEND |
- CHIPSET_STATE_STANDBY)) {
- /* Blink once every four seconds. */
- led_set_color_battery(
- (suspend_ticks % LED_TOTAL_4SECS_TICKS)
- < LED_ON_1SEC_TICKS ? LED_AMBER : LED_OFF);
- } else {
- led_set_color_battery(LED_OFF);
- }
+ if (chipset_in_state(CHIPSET_STATE_ON))
+ new_state = STATE_DISCHARGE_S0;
+ else if (chipset_in_state(CHIPSET_STATE_SUSPEND) |
+ chipset_in_state(CHIPSET_STATE_STANDBY))
+ new_state = STATE_DISCHARGE_S3;
+ else
+ new_state = STATE_DISCHARGE_S5;
break;
case PWR_STATE_ERROR:
- led_set_color_battery(
- (battery_ticks % LED_TOTAL_2SECS_TICKS <
- LED_ON_1SEC_TICKS) ? LED_AMBER : LED_OFF);
+ new_state = STATE_BATTERY_ERROR;
break;
case PWR_STATE_CHARGE_NEAR_FULL:
- led_set_color_battery(LED_BLUE);
+ new_state = STATE_CHARGING_LVL_3;
break;
case PWR_STATE_IDLE: /* External power connected in IDLE */
if (charge_get_flags() & CHARGE_FLAG_FORCE_IDLE)
- led_set_color_battery(
- (battery_ticks % LED_TOTAL_4SECS_TICKS <
- LED_ON_2SECS_TICKS) ? LED_AMBER : LED_BLUE);
+ new_state = STATE_FACTORY_TEST;
else
- led_set_color_battery(LED_BLUE);
+ new_state = STATE_DISCHARGE_S0;
break;
default:
/* Other states don't alter LED behavior */
break;
}
- battery_ticks++;
- suspend_ticks++;
+
+ return new_state;
}
-/* Called by hook task every 1 sec */
-static void led_second(void)
+static void led_update_battery(void)
{
+ static int ticks;
+ int phase;
+ enum led_states desired_state = led_get_state();
+
+ /* Get updated state based on power state and charge level */
+ if (desired_state < LED_NUM_STATES && desired_state != led.state) {
+ /* State is changing */
+ led.state = desired_state;
+ /* Reset ticks counter when state changes */
+ ticks = 0;
+ }
+
/*
- * Reference board only has one LED, so overload it to act as both
- * power LED and battery LED.
+ * Determine the which phase of the state table to use. Assume it's
+ * phase 0. If the time values for both phases of the current state are
+ * not -1, then this state uses some blinking pattern. The phase is then
+ * determined by taking the modulo of ticks by the blinking pattern
+ * period.
*/
+ phase = 0;
+ if ((led.state_table[led.state][LED_PHASE_0].time != LED_INDEFINITE) &&
+ (led.state_table[led.state][LED_PHASE_1].time != LED_INDEFINITE)) {
+ int period;
+
+ period = led.state_table[led.state][LED_PHASE_0].time +
+ led.state_table[led.state][LED_PHASE_1].time;
+ if (period)
+ phase = ticks % period <
+ led.state_table[led.state][LED_PHASE_0].time ?
+ 0 : 1;
+ }
+
+ /* Set the color for the given state and phase */
+ led_set_color_battery(led.state_table[led.state][phase].color);
+ ticks++;
+}
+
+/* Called by hook task every 1 sec */
+static void led_update(void)
+{
+ /* Update battery LED */
if (led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED))
- led_set_battery();
+ led_update_battery();
+}
+DECLARE_HOOK(HOOK_TICK, led_update, HOOK_PRIO_DEFAULT);
+
+static void led_init(void)
+{
+ int sku = system_get_sku_id();
+
+ if ((sku >= 70 && sku <= 79) || (sku >= 124 && sku <= 125) ||
+ (sku >= 144 && sku <= 145)) {
+ led.charge_lvl_1 = LED_CHARGE_LEVEL_1_ROBO;
+ led.state_table = led_robo_state_table;
+ led.update_power = NULL;
+ } else {
+ led.charge_lvl_1 = LED_CHARGE_LEVEL_1_DEFAULT;
+ led.state_table = led_default_state_table;
+ led.update_power = NULL;
+ }
+ led_set_color_battery(LED_OFF);
}
-DECLARE_HOOK(HOOK_SECOND, led_second, HOOK_PRIO_DEFAULT);
+/* Make sure this comes after SKU ID hook */
+DECLARE_HOOK(HOOK_INIT, led_init, HOOK_PRIO_DEFAULT + 2);