summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/lp5562_battery_led.c189
1 files changed, 140 insertions, 49 deletions
diff --git a/common/lp5562_battery_led.c b/common/lp5562_battery_led.c
index 65457c60a0..1bb66e2e86 100644
--- a/common/lp5562_battery_led.c
+++ b/common/lp5562_battery_led.c
@@ -11,6 +11,7 @@
#include "lp5562.h"
#include "pmu_tpschrome.h"
#include "smart_battery.h"
+#include "util.h"
/* We use yellow LED instead of blue LED. Re-map colors here. */
#define LED_COLOR_NONE LP5562_COLOR_NONE
@@ -18,6 +19,19 @@
#define LED_COLOR_YELLOW LP5562_COLOR_BLUE
#define LED_COLOR_RED LP5562_COLOR_RED
+/* LED states */
+enum led_state_t {
+ LED_STATE_SOLID_RED,
+ LED_STATE_SOLID_GREEN,
+ LED_STATE_SOLID_YELLOW,
+ LED_STATE_TRANSITION_ON, /* Solid yellow -> breathing */
+ LED_STATE_TRANSITION_OFF, /* Breathing -> solid yellow */
+ LED_STATE_BREATHING,
+
+ /* Not an actual state */
+ LED_STATE_OFF,
+};
+
/* LED breathing program */
static const uint8_t breathing_prog[] = {0x41, 0xff, /* 0x80 -> 0x0 */
0x41, 0x7f, /* 0x0 -> 0x80 */
@@ -25,45 +39,132 @@ static const uint8_t breathing_prog[] = {0x41, 0xff, /* 0x80 -> 0x0 */
0x7f, 0x00,
0x7f, 0x00,
0x7f, 0x00,
- 0x00, 0x00}; /* Repeat */
+ 0x00, 0x00, /* Go to start */
+ 0x40, 0x80, /* Set PWM = 0x80 */
+ 0x00, 0x00}; /* Go to start */
+#define BREATHING_PROG_ENTRY 7
+
+static int stop_led_engine(void)
+{
+ int pc;
+ if (lp5562_get_engine_state(LP5562_ENG_SEL_1) == LP5562_ENG_STEP)
+ return 0; /* Not stopped */
+ pc = lp5562_get_pc(LP5562_ENG_SEL_1);
+ if (pc == 1) {
+ /* LED currently off. Ramp up. */
+ lp5562_engine_control(LP5562_ENG_STEP,
+ LP5562_ENG_HOLD,
+ LP5562_ENG_HOLD);
+ return 0;
+ }
+
+ lp5562_set_engine(LP5562_ENG_SEL_NONE,
+ LP5562_ENG_SEL_NONE,
+ LP5562_ENG_SEL_NONE);
+ lp5562_set_color(LED_COLOR_YELLOW);
+ return 1;
+}
+
+static int set_led_color(enum led_state_t state)
+{
+ ASSERT(state != LED_STATE_TRANSITION_ON &&
+ state != LED_STATE_TRANSITION_OFF);
+
+ switch (state) {
+ case LED_STATE_SOLID_RED:
+ return lp5562_set_color(LED_COLOR_RED);
+ case LED_STATE_SOLID_GREEN:
+ return lp5562_set_color(LED_COLOR_GREEN);
+ case LED_STATE_SOLID_YELLOW:
+ case LED_STATE_BREATHING:
+ return lp5562_set_color(LED_COLOR_YELLOW);
+ default:
+ return EC_ERROR_UNKNOWN;
+ }
+}
-static int led_breathing(int enabled)
+static void stablize_led(enum led_state_t desired_state)
{
- int ret = 0;
-
- if (enabled) {
- ret |= lp5562_engine_load(LP5562_ENG_SEL_1,
- breathing_prog,
- sizeof(breathing_prog));
- ret |= lp5562_engine_control(LP5562_ENG_RUN,
- LP5562_ENG_HOLD,
- LP5562_ENG_HOLD);
- ret |= lp5562_set_engine(LP5562_ENG_SEL_NONE,
- LP5562_ENG_SEL_NONE,
- LP5562_ENG_SEL_1);
- } else {
- ret |= lp5562_engine_control(LP5562_ENG_HOLD,
- LP5562_ENG_HOLD,
- LP5562_ENG_HOLD);
- ret |= lp5562_set_engine(LP5562_ENG_SEL_NONE,
- LP5562_ENG_SEL_NONE,
- LP5562_ENG_SEL_NONE);
+ static enum led_state_t current_state = LED_STATE_OFF;
+ enum led_state_t next_state = LED_STATE_OFF;
+
+ /* TRANSITIONs are internal states */
+ ASSERT(desired_state != LED_STATE_TRANSITION_ON &&
+ desired_state != LED_STATE_TRANSITION_OFF);
+
+ if (desired_state == LED_STATE_OFF) {
+ current_state = LED_STATE_OFF;
+ return;
+ }
+
+ /* Determine next state */
+ switch (current_state) {
+ case LED_STATE_OFF:
+ case LED_STATE_SOLID_RED:
+ case LED_STATE_SOLID_GREEN:
+ if (desired_state == LED_STATE_BREATHING)
+ next_state = LED_STATE_SOLID_YELLOW;
+ else
+ next_state = desired_state;
+ set_led_color(next_state);
+ break;
+ case LED_STATE_SOLID_YELLOW:
+ if (desired_state == LED_STATE_BREATHING) {
+ next_state = LED_STATE_TRANSITION_ON;
+ lp5562_set_pc(LP5562_ENG_SEL_1, BREATHING_PROG_ENTRY);
+ lp5562_engine_control(LP5562_ENG_STEP,
+ LP5562_ENG_HOLD,
+ LP5562_ENG_HOLD);
+ } else {
+ next_state = desired_state;
+ set_led_color(next_state);
+ }
+ break;
+ case LED_STATE_BREATHING:
+ if (desired_state != LED_STATE_BREATHING) {
+ next_state = LED_STATE_TRANSITION_OFF;
+ lp5562_engine_control(LP5562_ENG_STEP,
+ LP5562_ENG_HOLD,
+ LP5562_ENG_HOLD);
+ } else {
+ next_state = LED_STATE_BREATHING;
+ }
+ break;
+ case LED_STATE_TRANSITION_ON:
+ if (desired_state == LED_STATE_BREATHING) {
+ next_state = LED_STATE_BREATHING;
+ lp5562_set_engine(LP5562_ENG_SEL_NONE,
+ LP5562_ENG_SEL_NONE,
+ LP5562_ENG_SEL_1);
+ lp5562_engine_control(LP5562_ENG_RUN,
+ LP5562_ENG_HOLD,
+ LP5562_ENG_HOLD);
+ } else {
+ next_state = LED_STATE_SOLID_YELLOW;
+ lp5562_engine_control(LP5562_ENG_HOLD,
+ LP5562_ENG_HOLD,
+ LP5562_ENG_HOLD);
+ }
+ break;
+ case LED_STATE_TRANSITION_OFF:
+ if (stop_led_engine())
+ next_state = LED_STATE_SOLID_YELLOW;
+ else
+ next_state = LED_STATE_TRANSITION_OFF;
+ break;
}
- return ret;
+ current_state = next_state;
}
static void battery_led_update(void)
{
int current;
int desired_current;
+ enum led_state_t state = LED_STATE_OFF;
/* Current states and next states */
- static uint32_t color = LED_COLOR_RED;
- static int breathing;
static int led_power = -1;
- int new_color = LED_COLOR_RED;
- int new_breathing = 0;
int new_led_power;
/* Determine LED power */
@@ -72,13 +173,12 @@ static void battery_led_update(void)
led_power = new_led_power;
if (new_led_power) {
lp5562_poweron();
+ lp5562_engine_load(LP5562_ENG_SEL_1,
+ breathing_prog,
+ sizeof(breathing_prog));
} else {
- color = LED_COLOR_NONE;
- if (breathing) {
- led_breathing(0);
- breathing = 0;
- }
lp5562_poweroff();
+ stablize_led(LED_STATE_OFF);
}
}
if (!new_led_power)
@@ -90,47 +190,38 @@ static void battery_led_update(void)
*/
switch (charge_get_state()) {
case ST_IDLE:
- new_color = LED_COLOR_GREEN;
+ state = LED_STATE_SOLID_GREEN;
break;
case ST_DISCHARGING:
/* Discharging with AC, must be battery assist */
- new_color = LED_COLOR_YELLOW;
- new_breathing = 1;
+ state = LED_STATE_BREATHING;
break;
case ST_PRE_CHARGING:
- new_color = LED_COLOR_YELLOW;
+ state = LED_STATE_SOLID_YELLOW;
break;
case ST_CHARGING:
if (battery_current(&current) ||
battery_desired_current(&desired_current)) {
/* Cannot talk to the battery. Set LED to red. */
- new_color = LED_COLOR_RED;
+ state = LED_STATE_SOLID_RED;
break;
}
if (current < 0 && desired_current > 0) { /* Battery assist */
- new_breathing = 1;
- new_color = LED_COLOR_YELLOW;
+ state = LED_STATE_BREATHING;
break;
}
if (current && desired_current)
- new_color = LED_COLOR_YELLOW;
+ state = LED_STATE_SOLID_YELLOW;
else
- new_color = LED_COLOR_GREEN;
+ state = LED_STATE_SOLID_GREEN;
break;
case ST_CHARGING_ERROR:
- new_color = LED_COLOR_RED;
+ state = LED_STATE_SOLID_RED;
break;
}
- if (new_color != color) {
- lp5562_set_color(new_color);
- color = new_color;
- }
- if (new_breathing != breathing) {
- led_breathing(new_breathing);
- breathing = new_breathing;
- }
+ stablize_led(state);
}
DECLARE_HOOK(HOOK_SECOND, battery_led_update, HOOK_PRIO_DEFAULT);