summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic Yang <victoryang@chromium.org>2013-04-23 15:04:41 +0800
committerChromeBot <chrome-bot@google.com>2013-04-24 00:06:01 -0700
commit5f86cc0aa5ef7e6c5a4a920ee30dba44773ec7a5 (patch)
tree69c1c03b7e305c848b119e1fde40fc8a9724a182
parent01279936cb7836ee5cef7e4c2332f6a6338a3162 (diff)
downloadchrome-ec-5f86cc0aa5ef7e6c5a4a920ee30dba44773ec7a5.tar.gz
spring: Improve battery LED stability
Previously, we sometimes saw battery LED went off when going into or out of battery assist mode. This CL adds a state machine to stabilize battery LED. By controlling the state of lighting engine, the tranisition from/to battery assist mode is seamless now. BUG=chrome-os-partner:18844 TEST=On spring, check: 1. LED doesn't go off when going into battery assist mode. 2. LED doesn't suddenly change brightness when coming out of battery assist mode. 3. LED goes red after few seconds when battery is not present. 4. LED goes green when battery is charged. BRANCH=spring Signed-off-by: Vic Yang <victoryang@chromium.org> Change-Id: I3286b54a76edd77c65033ec3bbf0d81d916f7be0 Reviewed-on: https://gerrit.chromium.org/gerrit/48875 Reviewed-by: Vincent Palatin <vpalatin@chromium.org> Commit-Queue: Vic Yang <victoryang@chromium.org> Tested-by: Vic Yang <victoryang@chromium.org>
-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);