mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-29 18:11:05 +00:00
The charge state machine asks for all of this stuff at the same time
anyway. Bundling it into a single function removes a number of
redundant (and painfully slow) I2C reads.
Also refactor the battery debug command so it doesn't have so many
local variables all in one function; it was consuming considerably
more stack space than any other debug command.
Spring still needs low-level access to the smart battery, so move the
two functions it needs directly into the Spring implementation.
BUG=chrome-os-partner:20881
BRANCH=none
TEST=charge/discharge rambi, pit and spring; watch debug messages and
LED and output of 'battery' debug command. All should behave the
same as before. Then run 'taskinfo' and see that the console task
has at least 20 bytes unused.
Change-Id: I951b569542e28bbbb58853d62b57b0aaaf183e3f
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/177797
203 lines
4.9 KiB
C
203 lines
4.9 KiB
C
/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*
|
|
* Battery LED state machine to drive RGB LED on LP5562
|
|
*/
|
|
|
|
#include "battery.h"
|
|
#include "battery_smart.h"
|
|
#include "common.h"
|
|
#include "driver/led/lp5562.h"
|
|
#include "extpower.h"
|
|
#include "hooks.h"
|
|
#include "host_command.h"
|
|
#include "pmu_tpschrome.h"
|
|
#include "timer.h"
|
|
#include "util.h"
|
|
|
|
#define GREEN_LED_THRESHOLD 94
|
|
|
|
/* Minimal interval between changing LED color to green and yellow. */
|
|
#define LED_WAIT_INTERVAL (15 * SECOND)
|
|
|
|
/* We use yellow LED instead of blue LED. Re-map colors here. */
|
|
#define LED_COLOR_NONE LP5562_COLOR_NONE
|
|
#define LED_COLOR_GREEN LP5562_COLOR_GREEN(0x10)
|
|
#define LED_COLOR_YELLOW LP5562_COLOR_BLUE(0x40)
|
|
#define LED_COLOR_RED LP5562_COLOR_RED(0x80)
|
|
|
|
/* LED states */
|
|
enum led_state_t {
|
|
LED_STATE_SOLID_RED,
|
|
LED_STATE_SOLID_GREEN,
|
|
LED_STATE_SOLID_YELLOW,
|
|
|
|
/* Not an actual state */
|
|
LED_STATE_OFF,
|
|
|
|
/* Used to force next LED color update */
|
|
LED_STATE_INVALID,
|
|
};
|
|
|
|
static enum led_state_t last_state = LED_STATE_OFF;
|
|
static int led_auto_control = 1;
|
|
|
|
static int set_led_color(enum led_state_t state)
|
|
{
|
|
int rv = EC_SUCCESS;
|
|
|
|
if (!led_auto_control || state == last_state)
|
|
return EC_SUCCESS;
|
|
|
|
switch (state) {
|
|
case LED_STATE_SOLID_RED:
|
|
rv = lp5562_set_color(LED_COLOR_RED);
|
|
break;
|
|
case LED_STATE_SOLID_GREEN:
|
|
rv = lp5562_set_color(LED_COLOR_GREEN);
|
|
break;
|
|
case LED_STATE_SOLID_YELLOW:
|
|
rv = lp5562_set_color(LED_COLOR_YELLOW);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (rv == EC_SUCCESS)
|
|
last_state = state;
|
|
else
|
|
last_state = LED_STATE_INVALID;
|
|
return rv;
|
|
}
|
|
|
|
/**
|
|
* Directly read state of charge (0-100) of battery.
|
|
*/
|
|
static int battery_state_of_charge(int *percent)
|
|
{
|
|
return sb_read(SB_RELATIVE_STATE_OF_CHARGE, percent);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Host commands */
|
|
|
|
static int led_command_control(struct host_cmd_handler_args *args)
|
|
{
|
|
const struct ec_params_led_control *p = args->params;
|
|
struct ec_response_led_control *r = args->response;
|
|
int i;
|
|
uint8_t clipped[EC_LED_COLOR_COUNT];
|
|
|
|
/* Only support battery LED control */
|
|
if (p->led_id != EC_LED_ID_BATTERY_LED)
|
|
return EC_RES_INVALID_PARAM;
|
|
|
|
if (p->flags & EC_LED_FLAGS_AUTO) {
|
|
if (!extpower_is_present())
|
|
lp5562_poweroff();
|
|
last_state = LED_STATE_OFF;
|
|
led_auto_control = 1;
|
|
} else if (!(p->flags & EC_LED_FLAGS_QUERY)) {
|
|
for (i = 0; i < EC_LED_COLOR_COUNT; ++i)
|
|
clipped[i] = MIN(p->brightness[i], 0x80);
|
|
led_auto_control = 0;
|
|
if (!extpower_is_present())
|
|
lp5562_poweron();
|
|
if (lp5562_set_color((clipped[EC_LED_COLOR_RED] << 16) +
|
|
(clipped[EC_LED_COLOR_GREEN] << 8) +
|
|
clipped[EC_LED_COLOR_YELLOW]))
|
|
return EC_RES_ERROR;
|
|
}
|
|
|
|
r->brightness_range[EC_LED_COLOR_RED] = 0x80;
|
|
r->brightness_range[EC_LED_COLOR_GREEN] = 0x80;
|
|
r->brightness_range[EC_LED_COLOR_BLUE] = 0x0;
|
|
r->brightness_range[EC_LED_COLOR_YELLOW] = 0x80;
|
|
r->brightness_range[EC_LED_COLOR_WHITE] = 0x0;
|
|
args->response_size = sizeof(struct ec_response_led_control);
|
|
|
|
return EC_RES_SUCCESS;
|
|
}
|
|
DECLARE_HOST_COMMAND(EC_CMD_LED_CONTROL,
|
|
led_command_control,
|
|
EC_VER_MASK(1));
|
|
|
|
/*****************************************************************************/
|
|
/* Hooks */
|
|
|
|
static void battery_led_update(void)
|
|
{
|
|
int rv;
|
|
int state_of_charge;
|
|
enum led_state_t state = LED_STATE_OFF;
|
|
|
|
/* Current states and next states */
|
|
static int led_power = -1;
|
|
int new_led_power;
|
|
|
|
/*
|
|
* The time before which we should not change LED
|
|
* color between green and yellow.
|
|
*/
|
|
static timestamp_t led_update_deadline = {.val = 0};
|
|
|
|
/* Determine LED power */
|
|
new_led_power = extpower_is_present();
|
|
if (new_led_power != led_power) {
|
|
if (new_led_power) {
|
|
rv = lp5562_poweron();
|
|
} else {
|
|
rv = lp5562_poweroff();
|
|
set_led_color(LED_STATE_OFF);
|
|
led_update_deadline.val = 0;
|
|
}
|
|
if (!rv)
|
|
led_power = new_led_power;
|
|
}
|
|
if (!new_led_power)
|
|
return;
|
|
|
|
/*
|
|
* LED power is controlled by accessory detection. We only
|
|
* set color here.
|
|
*/
|
|
switch (charge_get_state()) {
|
|
case ST_IDLE0:
|
|
case ST_BAD_COND:
|
|
case ST_PRE_CHARGING:
|
|
state = LED_STATE_SOLID_YELLOW;
|
|
break;
|
|
case ST_IDLE:
|
|
case ST_DISCHARGING:
|
|
case ST_CHARGING:
|
|
if (battery_state_of_charge(&state_of_charge)) {
|
|
/* Cannot talk to the battery. Set LED to red. */
|
|
state = LED_STATE_SOLID_RED;
|
|
break;
|
|
}
|
|
|
|
if (state_of_charge < GREEN_LED_THRESHOLD)
|
|
state = LED_STATE_SOLID_YELLOW;
|
|
else
|
|
state = LED_STATE_SOLID_GREEN;
|
|
break;
|
|
case ST_CHARGING_ERROR:
|
|
state = LED_STATE_SOLID_RED;
|
|
break;
|
|
}
|
|
|
|
if (state == LED_STATE_SOLID_GREEN ||
|
|
state == LED_STATE_SOLID_YELLOW) {
|
|
if (!timestamp_expired(led_update_deadline, NULL))
|
|
return;
|
|
led_update_deadline.val =
|
|
get_time().val + LED_WAIT_INTERVAL;
|
|
} else {
|
|
led_update_deadline.val = 0;
|
|
}
|
|
|
|
set_led_color(state);
|
|
}
|
|
DECLARE_HOOK(HOOK_SECOND, battery_led_update, HOOK_PRIO_DEFAULT);
|