summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2014-12-17 13:22:36 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-01-03 02:26:21 +0000
commit2b0895179733852a7eb13051ad99a494af5cc3bd (patch)
tree557338d88ec7a20212bc8c4f457d7867073513a5
parenta3f3e38da09eb196a5773021a54832a553c206e3 (diff)
downloadchrome-ec-2b0895179733852a7eb13051ad99a494af5cc3bd.tar.gz
samus: when battery is full, and not in S0, stop charging
When battery is full and system is not in S0, then stop charging and allow battery to power the system. Once battery is no longer full and requests current, allow charging again. This is to work around power consumption issues in our AC input path. The charge override port is stored upon entering S3 and restored going back to S0 so that the charge override port is not affected by this. This also fixes lightbar so lightbar checks if battery is full instead of checking raw percentage. The lightbar is also changed to use the last tap direction if no charger is plugged in. And the lightbar tap for battery threshold for turning green is lowered to 95%. This also moves some samus_pd board code out of interrupt handlers and in to deferred functions to minimize time in interrupts. BUG=chrome-os-partner:34640, chrome-os-partner:34847 BRANCH=samus TEST=load onto samus. use battfake command from pd console to set battery percentage. when system is in G3, see that batt = 100% stops charging, and when batt < 100% it starts charging again. tested that we receive host command from EC with battery information every time battery changes SOC. Change-Id: Ia8e0721508e34ee3630f5e5b0c2f431a00329caf Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/236411 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--board/samus_pd/board.c162
-rw-r--r--board/samus_pd/board.h4
-rw-r--r--common/charge_manager.c20
-rw-r--r--common/charge_state_v2.c45
-rw-r--r--common/lightbar.c13
-rw-r--r--include/charge_manager.h1
6 files changed, 201 insertions, 44 deletions
diff --git a/board/samus_pd/board.c b/board/samus_pd/board.c
index 65e9f03bf7..8359d770f2 100644
--- a/board/samus_pd/board.c
+++ b/board/samus_pd/board.c
@@ -34,6 +34,11 @@ static enum power_state ps;
/* Battery state of charge */
static int batt_soc;
+static int fake_state_of_charge = -1; /* use real soc by default */
+
+/* Last charge port override when charging turned off due to full battery */
+static int chg_override_port = OVERRIDE_OFF;
+static int chg_is_cutoff;
/* PD MCU status and host event status for host command */
static struct ec_response_pd_status pd_status;
@@ -59,19 +64,20 @@ BUILD_ASSERT(ARRAY_SIZE(supplier_priority) == CHARGE_SUPPLIER_COUNT);
static void pericom_port0_reenable_interrupts(void)
{
+ CPRINTS("VBUS p0 %d", gpio_get_level(GPIO_USB_C0_VBUS_WAKE));
pi3usb9281_enable_interrupts(0);
}
DECLARE_DEFERRED(pericom_port0_reenable_interrupts);
static void pericom_port1_reenable_interrupts(void)
{
+ CPRINTS("VBUS p1 %d", gpio_get_level(GPIO_USB_C1_VBUS_WAKE));
pi3usb9281_enable_interrupts(1);
}
DECLARE_DEFERRED(pericom_port1_reenable_interrupts);
void vbus0_evt(enum gpio_signal signal)
{
- ccprintf("VBUS %d, %d!\n", signal, gpio_get_level(signal));
/*
* Re-enable interrupts on pericom charger detector since the
* chip may periodically reset itself, and come back up with
@@ -84,7 +90,6 @@ void vbus0_evt(enum gpio_signal signal)
void vbus1_evt(enum gpio_signal signal)
{
- ccprintf("VBUS %d, %d!\n", signal, gpio_get_level(signal));
/*
* Re-enable interrupts on pericom charger detector since the
* chip may periodically reset itself, and come back up with
@@ -210,41 +215,96 @@ void usb1_evt(enum gpio_signal signal)
wake_usb_charger_task(1);
}
-void pch_evt(enum gpio_signal signal)
+/* When battery is full, cutoff charging by disabling AC input current */
+static void check_charging_cutoff(void)
+{
+ int port;
+
+ /* Only check if charging needs to be turned off when not in S0 */
+ if (ps == POWER_S0)
+ return;
+
+ port = charge_manager_get_active_charge_port();
+
+ /*
+ * If battery is full disable charging, if battery is not full, restore
+ * charge port.
+ */
+ if (!chg_is_cutoff && port != CHARGE_PORT_NONE && batt_soc == 100) {
+ charge_manager_set_override(OVERRIDE_DONT_CHARGE);
+ chg_is_cutoff = 1;
+ } else if (chg_is_cutoff && batt_soc < 100) {
+ charge_manager_set_override(chg_override_port);
+ chg_is_cutoff = 0;
+ }
+}
+DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, check_charging_cutoff, HOOK_PRIO_DEFAULT);
+
+static void chipset_s5_to_s3(void)
{
- /* Determine new chipset state, trigger corresponding hook */
+ ps = POWER_S3;
+ hook_notify(HOOK_CHIPSET_STARTUP);
+}
+
+static void chipset_s3_to_s0(void)
+{
+ /* Disable deep sleep and restore charge override port */
+ disable_sleep(SLEEP_MASK_AP_RUN);
+ charge_manager_set_override(chg_override_port);
+ chg_is_cutoff = 0;
+
+ ps = POWER_S0;
+ hook_notify(HOOK_CHIPSET_RESUME);
+}
+
+static void chipset_s3_to_s5(void)
+{
+ ps = POWER_S5;
+ hook_notify(HOOK_CHIPSET_SHUTDOWN);
+}
+
+static void chipset_s0_to_s3(void)
+{
+ /* Enable deep sleep and store charge override port */
+ enable_sleep(SLEEP_MASK_AP_RUN);
+ chg_override_port = charge_manager_get_override();
+
+ ps = POWER_S3;
+ hook_notify(HOOK_CHIPSET_SUSPEND);
+}
+
+static void pch_evt_deferred(void)
+{
+ /* Determine new chipset state, trigger corresponding transition */
switch (ps) {
case POWER_S5:
- if (gpio_get_level(GPIO_PCH_SLP_S5_L)) {
- /* S5 -> S3 */
- hook_notify(HOOK_CHIPSET_STARTUP);
- ps = POWER_S3;
- }
+ if (gpio_get_level(GPIO_PCH_SLP_S5_L))
+ chipset_s5_to_s3();
+ if (gpio_get_level(GPIO_PCH_SLP_S3_L))
+ chipset_s3_to_s0();
break;
case POWER_S3:
- if (gpio_get_level(GPIO_PCH_SLP_S3_L)) {
- /* S3 -> S0: disable deep sleep */
- disable_sleep(SLEEP_MASK_AP_RUN);
- hook_notify(HOOK_CHIPSET_RESUME);
- ps = POWER_S0;
- } else if (!gpio_get_level(GPIO_PCH_SLP_S5_L)) {
- /* S3 -> S5 */
- hook_notify(HOOK_CHIPSET_SHUTDOWN);
- ps = POWER_S5;
- }
+ if (gpio_get_level(GPIO_PCH_SLP_S3_L))
+ chipset_s3_to_s0();
+ else if (!gpio_get_level(GPIO_PCH_SLP_S5_L))
+ chipset_s3_to_s5();
break;
case POWER_S0:
- if (!gpio_get_level(GPIO_PCH_SLP_S3_L)) {
- /* S0 -> S3: enable deep sleep */
- enable_sleep(SLEEP_MASK_AP_RUN);
- hook_notify(HOOK_CHIPSET_SUSPEND);
- ps = POWER_S3;
- }
+ if (!gpio_get_level(GPIO_PCH_SLP_S3_L))
+ chipset_s0_to_s3();
+ if (!gpio_get_level(GPIO_PCH_SLP_S5_L))
+ chipset_s3_to_s5();
break;
default:
break;
}
}
+DECLARE_DEFERRED(pch_evt_deferred);
+
+void pch_evt(enum gpio_signal signal)
+{
+ hook_call_deferred(pch_evt_deferred, 0);
+}
void board_config_pre_init(void)
{
@@ -483,6 +543,7 @@ void board_flip_usb_mux(int port)
void board_update_battery_soc(int soc)
{
batt_soc = soc;
+ check_charging_cutoff();
}
int board_get_battery_soc(void)
@@ -521,8 +582,10 @@ static void pd_send_ec_int(void)
*/
int board_set_active_charge_port(int charge_port)
{
- if (charge_port >= 0 && charge_port < PD_PORT_COUNT &&
- pd_get_role(charge_port) != PD_ROLE_SINK) {
+ /* charge port is a realy physical port */
+ int is_real_port = (charge_port >= 0 && charge_port < PD_PORT_COUNT);
+
+ if (is_real_port && pd_get_role(charge_port) != PD_ROLE_SINK) {
CPRINTS("Skip enable p%d", charge_port);
return EC_ERROR_INVAL;
}
@@ -531,6 +594,17 @@ int board_set_active_charge_port(int charge_port)
gpio_set_level(GPIO_USB_C0_CHARGE_EN_L, !(charge_port == 0));
gpio_set_level(GPIO_USB_C1_CHARGE_EN_L, !(charge_port == 1));
+ /*
+ * If new charge port when charge is cutoff, then user must have
+ * plugged in a new dedicated charger. This resets the charge
+ * override port and clears the charge cutoff flag.
+ */
+ if (chg_is_cutoff && is_real_port) {
+ chg_override_port = OVERRIDE_OFF;
+ chg_is_cutoff = 0;
+ }
+ check_charging_cutoff();
+
CPRINTS("New chg p%d", charge_port);
return EC_SUCCESS;
}
@@ -602,6 +676,36 @@ DECLARE_CONSOLE_COMMAND(pdevent, command_pd_host_event,
"Send PD host event",
NULL);
+static int command_battfake(int argc, char **argv)
+{
+ char *e;
+ int v;
+
+ if (argc == 2) {
+ v = strtoi(argv[1], &e, 0);
+ if (*e || v < -1 || v > 100)
+ return EC_ERROR_PARAM1;
+
+ fake_state_of_charge = v;
+ }
+
+ if (fake_state_of_charge < 0) {
+ ccprintf("Using real batt level\n");
+ } else {
+ ccprintf("Using fake batt level %d%%\n",
+ fake_state_of_charge);
+ }
+
+ /* Send EC int to get batt info from EC */
+ pd_send_ec_int();
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(battfake, command_battfake,
+ "percent (-1 = use real level)",
+ "Set fake battery level",
+ NULL);
+
/****************************************************************************/
/* Host commands */
static int ec_status_host_cmd(struct host_cmd_handler_args *args)
@@ -609,7 +713,9 @@ static int ec_status_host_cmd(struct host_cmd_handler_args *args)
const struct ec_params_pd_status *p = args->params;
struct ec_response_pd_status *r = args->response;
- board_update_battery_soc(p->batt_soc);
+ /* if not using fake soc, then update battery soc */
+ board_update_battery_soc(fake_state_of_charge < 0 ?
+ p->batt_soc : fake_state_of_charge);
*r = pd_status;
diff --git a/board/samus_pd/board.h b/board/samus_pd/board.h
index ea660d1f84..adbb4f02df 100644
--- a/board/samus_pd/board.h
+++ b/board/samus_pd/board.h
@@ -66,9 +66,9 @@
*/
#define CONFIG_SYSTEM_UNLOCKED
-/* 10 deferrable tasks on this board */
+/* Maximum number of deferrable functions */
#undef DEFERRABLE_MAX_COUNT
-#define DEFERRABLE_MAX_COUNT 8
+#define DEFERRABLE_MAX_COUNT 9
#ifndef __ASSEMBLER__
diff --git a/common/charge_manager.c b/common/charge_manager.c
index 651cf3af5e..4b400f137c 100644
--- a/common/charge_manager.c
+++ b/common/charge_manager.c
@@ -347,6 +347,8 @@ int charge_manager_set_override(int port)
ASSERT(port >= OVERRIDE_DONT_CHARGE && port < PD_PORT_COUNT);
+ CPRINTS("Charge Override: %d", port);
+
/* Supersede any pending delayed overrides. */
if (delayed_override_port != OVERRIDE_OFF) {
if (delayed_override_port != port)
@@ -387,6 +389,17 @@ int charge_manager_set_override(int port)
return retval;
}
+/**
+ * Get the override port. OVERRIDE_OFF if no override port.
+ * OVERRIDE_DONT_CHARGE if override is set for no port.
+ *
+ * @return override port
+ */
+int charge_manager_get_override(void)
+{
+ return override_port;
+}
+
int charge_manager_get_active_charge_port(void)
{
return charge_port;
@@ -508,16 +521,19 @@ DECLARE_HOST_COMMAND(EC_CMD_PD_CHARGE_PORT_OVERRIDE,
static int command_charge_port_override(int argc, char **argv)
{
int port = OVERRIDE_OFF;
+ int ret = EC_SUCCESS;
char *e;
if (argc >= 2) {
port = strtoi(argv[1], &e, 0);
if (*e || port < OVERRIDE_DONT_CHARGE || port >= PD_PORT_COUNT)
return EC_ERROR_PARAM1;
+ ret = charge_manager_set_override(port);
}
- ccprintf("Set override: %d\n", port);
- return charge_manager_set_override(port);
+ ccprintf("Override: %d\n", (argc >= 2 && ret == EC_SUCCESS) ?
+ port : override_port);
+ return ret;
}
DECLARE_CONSOLE_COMMAND(chgoverride, command_charge_port_override,
"[port | -1 | -2]",
diff --git a/common/charge_state_v2.c b/common/charge_state_v2.c
index de7cfea731..051113c0e2 100644
--- a/common/charge_state_v2.c
+++ b/common/charge_state_v2.c
@@ -39,7 +39,8 @@
*/
static const struct battery_info *batt_info;
static struct charge_state_data curr;
-static int prev_ac, prev_charge;
+static int prev_ac, prev_charge, prev_full;
+static int is_full; /* battery not accepting current */
static int state_machine_force_idle;
static int manual_mode; /* volt/curr are no longer maintained by charger */
static unsigned int user_current_limit = -1U;
@@ -275,14 +276,16 @@ static void show_charging_progress(void)
}
if (rv)
- CPRINTS("Battery %d%% / ??h:?? %s",
+ CPRINTS("Battery %d%% / ??h:?? %s%s",
curr.batt.state_of_charge,
- to_full ? "to full" : "to empty");
+ to_full ? "to full" : "to empty",
+ is_full ? ", not accepting current" : "");
else
- CPRINTS("Battery %d%% / %dh:%d %s",
+ CPRINTS("Battery %d%% / %dh:%d %s%s",
curr.batt.state_of_charge,
minutes / 60, minutes % 60,
- to_full ? "to full" : "to empty");
+ to_full ? "to full" : "to empty",
+ is_full ? ", not accepting current" : "");
if (debugging) {
ccprintf("battery:\n");
@@ -294,6 +297,26 @@ static void show_charging_progress(void)
}
}
+/* Calculate if battery is full based on whether it is accepting charge */
+static int calc_is_full(void)
+{
+ static int ret;
+
+ /* If bad state of charge reading, return last value */
+ if (curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE ||
+ curr.batt.state_of_charge > 100)
+ return ret;
+ /*
+ * Battery is full when SoC is above 90% and battery desired current
+ * is 0. This is necessary because some batteries stop charging when
+ * the SoC still reports <100%, so we need to check desired current
+ * to know if it is actually full.
+ */
+ ret = (curr.batt.state_of_charge >= 90 &&
+ curr.batt.desired_current == 0);
+ return ret;
+}
+
/*
* Ask the charger for some voltage and current. If either value is 0,
* charging is disabled; otherwise it's enabled. Negative values are ignored.
@@ -732,11 +755,17 @@ wait_for_it:
notify_host_of_low_battery();
/* And the EC console */
- if (!(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) &&
- curr.batt.state_of_charge != prev_charge) {
+ is_full = calc_is_full();
+ if ((!(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) &&
+ curr.batt.state_of_charge != prev_charge) ||
+ (is_full != prev_full)) {
show_charging_progress();
prev_charge = curr.batt.state_of_charge;
+#ifdef HAS_TASK_PDCMD
+ host_command_pd_send_status();
+#endif
}
+ prev_full = is_full;
/* Turn charger off if it's not needed */
if (curr.state == ST_IDLE || curr.state == ST_DISCHARGE) {
@@ -882,7 +911,7 @@ int charge_get_percent(void)
* to the battery, that'll be zero, which is probably as good as
* anything.
*/
- return curr.batt.state_of_charge;
+ return is_full ? 100 : curr.batt.state_of_charge;
}
int charge_temp_sensor_get_val(int idx, int *temp_ptr)
diff --git a/common/lightbar.c b/common/lightbar.c
index bc43a6080e..ab9bfa8985 100644
--- a/common/lightbar.c
+++ b/common/lightbar.c
@@ -80,7 +80,7 @@ static const struct lightbar_params_v1 default_params = {
.tap_display_time = 3 * SECOND, /* total sequence time */
.tap_pct_red = 10, /* below this is red */
- .tap_pct_green = 97, /* above this is green */
+ .tap_pct_green = 94, /* above this is green */
.tap_seg_min_on = 35, /* min intensity (%) for "on" */
.tap_seg_max_on = 100, /* max intensity (%) for "on" */
.tap_seg_osc = 50, /* amplitude for charging osc */
@@ -876,8 +876,9 @@ static uint32_t sequence_TAP_inner(int dir)
f_mult = f_mult * gate[i] / FP_SCALE;
- /* Pulse when charging */
- if (st.battery_is_charging) {
+ /* Pulse when charging and not yet full */
+ if (st.battery_is_charging &&
+ st.battery_percent <= st.p.tap_pct_green) {
int scale = (FP_SCALE -
f_osc * cycle_010(w++) / FP_SCALE);
f_mult = f_mult * scale / FP_SCALE;
@@ -906,6 +907,7 @@ static int force_dir = -1;
/* Return 0 (left or none) or 1 (right) */
static int get_tap_direction(void)
{
+ static int last_dir;
int dir = 0;
if (force_dir >= 0)
@@ -914,10 +916,13 @@ static int get_tap_direction(void)
else
pd_exchange_status(&dir);
#endif
- if (dir != 1)
+ if (dir < 0)
+ dir = last_dir;
+ else if (dir != 1)
dir = 0;
CPRINTS("LB tap direction %d", dir);
+ last_dir = dir;
return dir;
}
diff --git a/include/charge_manager.h b/include/charge_manager.h
index d1ee472a50..0b1de3186d 100644
--- a/include/charge_manager.h
+++ b/include/charge_manager.h
@@ -31,6 +31,7 @@ void charge_manager_set_ceil(int port, int ceil);
/* Select an 'override port', which is always the preferred charge port */
int charge_manager_set_override(int port);
+int charge_manager_get_override(void);
/* Returns the current active charge port, as determined by charge manager */
int charge_manager_get_active_charge_port(void);