charge_manager: Enter safe mode at boot

Charge port / current selection often needs to be significantly altered
when a battery cannot provide sufficient charge, so have charge_manager
initially enter safe mode. After a battery with sufficient capacity has
been identified, charge manager will leave safe mode, and port / current
selection will return to standard rules.

BUG=chromium:777596
BRANCH=None
TEST=Pass charge_manager unit tests. On kevin, remove battery, attach
Apple PD charger, verify safe mode is not exited and device does not
brown out. Hot-plug battery and verify safe mode is exited. Next,
remove battery, attach to Samus, verify safe mode is not exited and
device doesn't brown out. Hot-plug battery, verify that safe mode is
exited and no active charge port, due to dual-role exclusion.

Change-Id: I7784865750087a037aad8dbbac058b22c77ba6d4
Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/733954
Commit-Ready: Shawn N <shawnn@chromium.org>
Tested-by: Shawn N <shawnn@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
Shawn Nematbakhsh
2017-10-23 15:45:16 -07:00
committed by chrome-bot
parent f28ab5c2ec
commit 2f127f3081
23 changed files with 120 additions and 258 deletions

View File

@@ -593,17 +593,6 @@ int board_set_active_charge_port(int charge_port)
{
enum bd9995x_charge_port bd9995x_port;
int bd9995x_port_select = 1;
static int initialized;
/*
* Reject charge port disable if our battery is critical and we
* have yet to initialize a charge port - continue to charge using
* charger ROM / POR settings.
*/
if (!initialized &&
charge_port == CHARGE_PORT_NONE &&
charge_get_percent() < 2)
return -1;
switch (charge_port) {
case USB_PD_PORT_ANX74XX:
@@ -632,7 +621,6 @@ int board_set_active_charge_port(int charge_port)
}
CPRINTS("New chg p%d", charge_port);
initialized = 1;
return bd9995x_select_input_port(bd9995x_port, bd9995x_port_select);
}

View File

@@ -289,17 +289,6 @@ int board_set_active_charge_port(int charge_port)
charge_port < CONFIG_USB_PD_PORT_COUNT);
/* check if we are source VBUS on the port */
int source = gpio_get_level(GPIO_USB_C0_5V_EN);
static int initialized;
/*
* Reject charge port disable if our battery is critical and we
* have yet to initialize a charge port - continue to charge using
* charger ROM / POR settings.
*/
if (!initialized &&
charge_port == CHARGE_PORT_NONE &&
charge_get_percent() < 2)
return -1;
if (is_real_port && source) {
CPRINTF("Skip enable p%d", charge_port);
@@ -316,7 +305,6 @@ int board_set_active_charge_port(int charge_port)
gpio_set_level(GPIO_USB_C0_CHARGE_L, 0);
}
initialized = 1;
return EC_SUCCESS;
}

View File

@@ -472,17 +472,6 @@ int board_set_active_charge_port(int charge_port)
{
enum bd9995x_charge_port bd9995x_port;
int bd9995x_port_select = 1;
static int initialized;
/*
* Reject charge port disable if our battery is critical and we
* have yet to initialize a charge port - continue to charge using
* charger ROM / POR settings.
*/
if (!initialized &&
charge_port == CHARGE_PORT_NONE &&
charge_get_percent() < 2)
return -1;
switch (charge_port) {
case 0:
@@ -511,7 +500,6 @@ int board_set_active_charge_port(int charge_port)
}
CPRINTS("New chg p%d", charge_port);
initialized = 1;
return bd9995x_select_input_port(bd9995x_port, bd9995x_port_select);
}

View File

@@ -64,6 +64,7 @@
/* Charger */
#define CONFIG_CHARGE_MANAGER
#undef CONFIG_CHARGE_MANAGER_SAFE_MODE
#define CONFIG_CHARGER_LIMIT_POWER_THRESH_CHG_MW 50000

View File

@@ -356,18 +356,6 @@ int pd_snk_is_vbus_provided(int port)
*/
int board_set_active_charge_port(int charge_port)
{
static int initialized;
/*
* Reject charge port disable if our battery is critical and we
* have yet to initialize a charge port - continue to charge using
* charger ROM / POR settings.
*/
if (!initialized &&
charge_port == CHARGE_PORT_NONE &&
charge_get_percent() < 2)
return -1;
switch (charge_port) {
case 0:
/* Don't charge from a source port */
@@ -395,7 +383,6 @@ int board_set_active_charge_port(int charge_port)
}
CPRINTS("New chg p%d", charge_port);
initialized = 1;
return EC_SUCCESS;
}

View File

@@ -356,18 +356,6 @@ int pd_snk_is_vbus_provided(int port)
*/
int board_set_active_charge_port(int charge_port)
{
static int initialized;
/*
* Reject charge port disable if our battery is critical and we
* have yet to initialize a charge port - continue to charge using
* charger ROM / POR settings.
*/
if (!initialized &&
charge_port == CHARGE_PORT_NONE &&
charge_get_percent() < 2)
return -1;
switch (charge_port) {
case 0:
/* Don't charge from a source port */
@@ -395,7 +383,6 @@ int board_set_active_charge_port(int charge_port)
}
CPRINTS("New chg p%d", charge_port);
initialized = 1;
return EC_SUCCESS;
}

View File

@@ -208,19 +208,6 @@ int board_set_active_charge_port(int charge_port)
{
enum bd9995x_charge_port bd9995x_port;
int bd9995x_port_select = 1;
static int initialized;
/*
* Reject charge port disable if our battery is critical and we
* have yet to initialize a charge port - continue to charge using
* charger ROM / POR settings.
*/
if (!initialized &&
charge_port == CHARGE_PORT_NONE &&
charge_get_percent() < CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON) {
CPRINTS("Bat critical, don't stop charging");
return -1;
}
switch (charge_port) {
case 0: case 1:
@@ -240,7 +227,6 @@ int board_set_active_charge_port(int charge_port)
}
CPRINTS("New chg p%d", charge_port);
initialized = 1;
return bd9995x_select_input_port(bd9995x_port, bd9995x_port_select);
}
@@ -248,17 +234,6 @@ int board_set_active_charge_port(int charge_port)
void board_set_charge_limit(int port, int supplier, int charge_ma,
int max_ma, int charge_mv)
{
/*
* Ignore lower charge ceiling on PD transition if our battery is
* critical, as we may brownout.
*/
if (supplier == CHARGE_SUPPLIER_PD &&
charge_ma < 1500 &&
charge_get_percent() < CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON) {
CPRINTS("Using max ilim %d", max_ma);
charge_ma = max_ma;
}
charge_set_input_current_limit(MAX(charge_ma,
CONFIG_CHARGER_INPUT_CURRENT), charge_mv);
}

View File

@@ -708,7 +708,6 @@ DECLARE_HOOK(HOOK_AC_CHANGE, board_extpower, HOOK_PRIO_DEFAULT);
*/
int board_set_active_charge_port(int charge_port)
{
static uint8_t initialized;
/* charge port is a physical port */
int is_real_port = (charge_port >= 0 &&
charge_port < CONFIG_USB_PD_PORT_COUNT);
@@ -721,13 +720,6 @@ int board_set_active_charge_port(int charge_port)
return EC_ERROR_INVAL;
}
if (!initialized &&
charge_port == CHARGE_PORT_NONE &&
charge_get_percent() < CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON) {
CPRINTS("Bat critical, don't stop charging");
return -1;
}
CPRINTF("New chg p%d", charge_port);
if (charge_port == CHARGE_PORT_NONE) {
@@ -743,7 +735,6 @@ int board_set_active_charge_port(int charge_port)
GPIO_USB_C0_CHARGE_L, 0);
}
initialized = 1;
return EC_SUCCESS;
}

View File

@@ -190,20 +190,6 @@ int board_set_active_charge_port(int charge_port)
{
enum bd9995x_charge_port bd9995x_port;
int bd9995x_port_select = 1;
static int initialized;
/*
* Reject charge port disable if our battery is critical and we
* have yet to initialize a charge port - continue to charge using
* charger ROM / POR settings.
*/
if (!initialized &&
charge_port == CHARGE_PORT_NONE &&
(charge_get_percent() < CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON ||
battery_get_disconnect_state() == BATTERY_DISCONNECTED)) {
CPRINTS("Bat critical, don't stop charging");
return -1;
}
CPRINTS("New chg p%d", charge_port);
@@ -224,25 +210,12 @@ int board_set_active_charge_port(int charge_port)
break;
}
initialized = 1;
return bd9995x_select_input_port(bd9995x_port, bd9995x_port_select);
}
void board_set_charge_limit(int port, int supplier, int charge_ma,
int max_ma, int charge_mv)
{
/*
* Ignore lower charge ceiling on PD transition if our battery is
* critical, as we may brownout.
*/
if (supplier == CHARGE_SUPPLIER_PD &&
charge_ma < 1500 &&
(charge_get_percent() < CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON ||
battery_get_disconnect_state() == BATTERY_DISCONNECTED)) {
CPRINTS("Using max ilim %d", max_ma);
charge_ma = max_ma;
}
charge_set_input_current_limit(
MAX(charge_ma, CONFIG_CHARGER_INPUT_CURRENT), charge_mv);
}

View File

@@ -748,7 +748,6 @@ DECLARE_HOOK(HOOK_AC_CHANGE, board_extpower, HOOK_PRIO_DEFAULT);
*/
int board_set_active_charge_port(int charge_port)
{
static uint8_t initialized;
/* charge port is a physical port */
int is_real_port = (charge_port >= 0 &&
charge_port < CONFIG_USB_PD_PORT_COUNT);
@@ -761,13 +760,6 @@ int board_set_active_charge_port(int charge_port)
return EC_ERROR_INVAL;
}
if (!initialized &&
charge_port == CHARGE_PORT_NONE &&
charge_get_percent() < CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON) {
CPRINTS("Bat critical, don't stop charging");
return -1;
}
CPRINTF("New chg p%d", charge_port);
if (charge_port == CHARGE_PORT_NONE) {
@@ -783,7 +775,6 @@ int board_set_active_charge_port(int charge_port)
GPIO_USB_C0_CHARGE_L, 0);
}
initialized = 1;
return EC_SUCCESS;
}

View File

@@ -585,17 +585,6 @@ int board_set_active_charge_port(int charge_port)
{
enum bd9995x_charge_port bd9995x_port;
int bd9995x_port_select = 1;
static int initialized;
/*
* Reject charge port disable if our battery is critical and we
* have yet to initialize a charge port - continue to charge using
* charger ROM / POR settings.
*/
if (!initialized &&
charge_port == CHARGE_PORT_NONE &&
charge_get_percent() < 2)
return -1;
switch (charge_port) {
case USB_PD_PORT_ANX74XX:
@@ -624,7 +613,6 @@ int board_set_active_charge_port(int charge_port)
}
CPRINTS("New chg p%d", charge_port);
initialized = 1;
return bd9995x_select_input_port(bd9995x_port, bd9995x_port_select);
}

View File

@@ -370,17 +370,6 @@ int board_set_active_charge_port(int charge_port)
{
enum bd9995x_charge_port bd9995x_port = 0;
int bd9995x_port_select = 1;
static int initialized;
/*
* Reject charge port disable if our battery is critical and we
* have yet to initialize a charge port - continue to charge using
* charger ROM / POR settings.
*/
if (!initialized &&
charge_port == CHARGE_PORT_NONE &&
charge_get_percent() < 2)
return -1;
switch (charge_port) {
case 0:
@@ -409,7 +398,6 @@ int board_set_active_charge_port(int charge_port)
}
CPRINTS("New chg p%d", charge_port);
initialized = 1;
return bd9995x_select_input_port(bd9995x_port, bd9995x_port_select);
}

View File

@@ -303,17 +303,6 @@ int board_set_active_charge_port(int charge_port)
charge_port < CONFIG_USB_PD_PORT_COUNT);
/* check if we are source VBUS on the port */
int source = gpio_get_level(GPIO_USB_C0_5V_EN);
static int initialized;
/*
* Reject charge port disable if our battery is critical and we
* have yet to initialize a charge port - continue to charge using
* charger ROM / POR settings.
*/
if (!initialized &&
charge_port == CHARGE_PORT_NONE &&
charge_get_percent() < 2)
return -1;
if (is_real_port && source) {
CPRINTF("Skip enable p%d", charge_port);
@@ -330,7 +319,6 @@ int board_set_active_charge_port(int charge_port)
gpio_set_level(GPIO_USB_C0_CHARGE_L, 0);
}
initialized = 1;
return EC_SUCCESS;
}

View File

@@ -475,6 +475,8 @@ static void board_update_battery_soc(int soc)
{
if (batt_soc != soc) {
batt_soc = soc;
if (batt_soc >= CONFIG_CHARGE_MANAGER_BAT_PCT_SAFE_MODE_EXIT)
charge_manager_leave_safe_mode();
board_update_charge_limit(desired_charge_rate_ma);
hook_notify(HOOK_BATTERY_SOC_CHANGE);
}

View File

@@ -21,6 +21,7 @@
#define CONFIG_BOARD_PRE_INIT
#define CONFIG_CHARGE_MANAGER
#define CONFIG_CHARGE_RAMP_SW
#undef CONFIG_CMD_CHARGE_SUPPLIER_INFO
#undef CONFIG_CMD_HASH
#undef CONFIG_CMD_HCDEBUG
#undef CONFIG_CMD_I2C_SCAN

View File

@@ -166,21 +166,6 @@ uint16_t tcpc_get_alert_status(void)
int board_set_active_charge_port(int charge_port)
{
static int initialized;
/*
* Reject charge port disable if our battery is critical and we
* have yet to initialize a charge port - continue to charge using
* charger ROM / POR settings.
*/
if (!initialized &&
charge_port == CHARGE_PORT_NONE &&
(charge_get_percent() < CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON ||
battery_get_disconnect_state() == BATTERY_DISCONNECTED)) {
CPRINTS("Bat critical, don't stop charging");
return -1;
}
CPRINTS("New chg p%d", charge_port);
switch (charge_port) {
@@ -198,25 +183,12 @@ int board_set_active_charge_port(int charge_port)
break;
}
initialized = 1;
return EC_SUCCESS;
}
void board_set_charge_limit(int port, int supplier, int charge_ma,
int max_ma, int charge_mv)
{
/*
* Ignore lower charge ceiling on PD transition if our battery is
* critical, as we may brownout.
*/
if (supplier == CHARGE_SUPPLIER_PD &&
charge_ma < 1500 &&
(charge_get_percent() < CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON ||
battery_get_disconnect_state() == BATTERY_DISCONNECTED)) {
CPRINTS("Using max ilim %d", max_ma);
charge_ma = max_ma;
}
charge_set_input_current_limit(MAX(charge_ma,
CONFIG_CHARGER_INPUT_CURRENT), charge_mv);
}

View File

@@ -91,6 +91,7 @@
#undef CONFIG_TASK_PROFILING
#define CONFIG_CHARGE_MANAGER
#undef CONFIG_CHARGE_MANAGER_SAFE_MODE
#define CONFIG_USB_POWER_DELIVERY
#define CONFIG_CMD_PD
#define CONFIG_USB_PD_DUAL_ROLE

View File

@@ -256,24 +256,11 @@ int board_set_active_charge_port(int port)
{
int is_real_port = (port >= 0 &&
port < CONFIG_USB_PD_PORT_COUNT);
static int initialized;
int i;
if (!is_real_port && port != CHARGE_PORT_NONE)
return EC_ERROR_INVAL;
/*
* Reject charge port none if our battery is critical and we
* have yet to initialize a charge port - continue to charge using
* charger ROM / POR settings.
*/
if (!initialized &&
port == CHARGE_PORT_NONE &&
charge_get_percent() < CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON) {
CPRINTS("Bat critical, don't stop charging");
return EC_ERROR_BUSY;
}
CPRINTS("New chg p%d", port);
if (port == CHARGE_PORT_NONE) {
@@ -281,7 +268,6 @@ int board_set_active_charge_port(int port)
gpio_set_level(GPIO_USB_C0_CHARGE_EN_L, 1);
gpio_set_level(GPIO_USB_C1_CHARGE_EN_L, 1);
gpio_set_level(GPIO_USB_C2_CHARGE_EN_L, 1);
initialized = 1;
return EC_SUCCESS;
}
@@ -297,7 +283,6 @@ int board_set_active_charge_port(int port)
gpio_set_level(GPIO_USB_C0_CHARGE_EN_L, port != 0);
gpio_set_level(GPIO_USB_C1_CHARGE_EN_L, port != 1);
gpio_set_level(GPIO_USB_C2_CHARGE_EN_L, port != 2);
initialized = 1;
/*
* Turn on the PP2 FET such that power actually flows and turn off the
@@ -315,18 +300,6 @@ int board_set_active_charge_port(int port)
void board_set_charge_limit(int port, int supplier, int charge_ma,
int max_ma, int charge_mv)
{
/*
* Ignore lower charge ceiling on PD transition if our battery is
* critical, as we may brownout.
*/
if (supplier == CHARGE_SUPPLIER_PD &&
charge_ma < 1500 &&
charge_get_percent() < CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON) {
CPRINTS("Using max ilim %d", max_ma);
charge_ma = max_ma;
}
/*
* To protect the charge inductor, at voltages above 18V we should
* set the current limit to 2.7A.

View File

@@ -86,6 +86,28 @@ static volatile uint32_t source_port_bitmap;
BUILD_ASSERT(sizeof(source_port_bitmap)*8 >= CONFIG_USB_PD_PORT_COUNT);
static uint8_t source_port_last_rp[CONFIG_USB_PD_PORT_COUNT];
/*
* charge_manager initially operates in safe mode until asked to leave (through
* charge_manager_leave_safe_mode()). While in safe mode, the following
* behavior is altered:
*
* 1) All chargers are considered dedicated (and thus are valid charge source
* candidates) for the purpose of port selection.
* 2) Charge ceilings are ignored. Most significantly, ILIM won't drop on PD
* voltage transition. If current load is high during transition, some
* chargers may brown-out.
* 3) CHARGE_PORT_NONE will not be selected (POR default charge port will
* remain selected rather than CHARGE_PORT_NONE).
*
* After leaving safe mode, charge_manager reverts to its normal behavior and
* immediately selects charge port and current using standard rules.
*/
#ifdef CONFIG_CHARGE_MANAGER_SAFE_MODE
static int left_safe_mode;
#else
static const int left_safe_mode = 1;
#endif
enum charge_manager_change_type {
CHANGE_CHARGE,
CHANGE_DUALROLE,
@@ -112,8 +134,9 @@ static int is_connected(int port)
return 1;
return pd_is_connected(port);
}
#endif
#endif /* !TEST_BUILD */
#ifndef CONFIG_CHARGE_MANAGER_DRP_CHARGING
/**
* In certain cases we need to override the default behavior of not charging
* from non-dedicated chargers. If the system is in RO and locked, we have no
@@ -125,25 +148,13 @@ static int is_connected(int port)
* @return 1 when we need to override the a non-dedicated charger
* to be a dedicated one, 0 otherwise.
*/
#ifdef CONFIG_BATTERY
static int charge_manager_spoof_dualrole_capability(void)
{
int spoof_dualrole = (system_get_image_copy() == SYSTEM_IMAGE_RO &&
system_is_locked()) ||
(battery_is_present() != BP_YES);
#ifdef CONFIG_BATTERY_REVIVE_DISCONNECT
spoof_dualrole |= (battery_get_disconnect_state() !=
BATTERY_NOT_DISCONNECTED);
#endif
return spoof_dualrole;
return (system_get_image_copy() == SYSTEM_IMAGE_RO &&
system_is_locked()) || !left_safe_mode;
}
#else /* CONFIG_BATTERY */
/* No battery, so always charge from input port. */
static inline int charge_manager_spoof_dualrole_capability(void)
{
return 1;
}
#endif /* CONFIG_BATTERY */
#endif /* !CONFIG_CHARGE_MANAGER_DRP_CHARGING */
/**
* Initialize available charge. Run before board init, so board init can
@@ -152,7 +163,6 @@ static inline int charge_manager_spoof_dualrole_capability(void)
static void charge_manager_init(void)
{
int i, j;
int spoof_capability = charge_manager_spoof_dualrole_capability();
for (i = 0; i < CHARGE_PORT_COUNT; ++i) {
for (j = 0; j < CHARGE_SUPPLIER_COUNT; ++j) {
@@ -163,7 +173,7 @@ static void charge_manager_init(void)
}
for (j = 0; j < CEIL_REQUESTOR_COUNT; ++j)
charge_ceil[i][j] = CHARGE_CEIL_NONE;
if (spoof_capability || !is_pd_port(i))
if (!is_pd_port(i))
dualrole_capability[i] = CAP_DEDICATED;
if (is_pd_port(i))
source_port_last_rp[i] = CONFIG_USB_PD_PULLUP;
@@ -492,7 +502,8 @@ static void charge_manager_get_best_charge_port(int *new_port,
* it is our override port.
*/
if (dualrole_capability[j] != CAP_DEDICATED &&
override_port != j)
override_port != j &&
!charge_manager_spoof_dualrole_capability())
continue;
#endif
@@ -550,6 +561,9 @@ static void charge_manager_refresh(void)
while (1) {
charge_manager_get_best_charge_port(&new_port, &new_supplier);
if (!left_safe_mode && new_port == CHARGE_PORT_NONE)
return;
/*
* If the port or supplier changed, make an attempt to switch to
* the port. We will re-set the active port on a supplier change
@@ -563,14 +577,8 @@ static void charge_manager_refresh(void)
board_set_active_charge_port(new_port) == EC_SUCCESS)
break;
/*
* Allow 'Dont charge' request to be rejected only if it
* is our initial selection.
*/
if (new_port == CHARGE_PORT_NONE) {
ASSERT(!active_charge_port_initialized);
return;
}
/* 'Dont charge' request must be accepted. */
ASSERT(new_port != CHARGE_PORT_NONE);
/*
* Zero the available charge on the rejected port so that
@@ -608,7 +616,7 @@ static void charge_manager_refresh(void)
#endif /* CONFIG_CHARGE_RAMP_HW */
/* Enforce port charge ceiling. */
ceil = charge_manager_get_ceil(new_port);
if (ceil != CHARGE_CEIL_NONE)
if (left_safe_mode && ceil != CHARGE_CEIL_NONE)
new_charge_current = MIN(ceil,
new_charge_current_uncapped);
else
@@ -884,9 +892,6 @@ void charge_manager_update_charge(int supplier,
void charge_manager_update_dualrole(int port, enum dualrole_capabilities cap)
{
if (charge_manager_spoof_dualrole_capability())
cap = CAP_DEDICATED;
/* Ignore when capability is unchanged */
if (cap != dualrole_capability[port]) {
dualrole_capability[port] = cap;
@@ -894,6 +899,18 @@ void charge_manager_update_dualrole(int port, enum dualrole_capabilities cap)
}
}
#ifdef CONFIG_CHARGE_MANAGER_SAFE_MODE
void charge_manager_leave_safe_mode(void)
{
if (left_safe_mode)
return;
left_safe_mode = 1;
if (charge_manager_is_seeded())
hook_call_deferred(&charge_manager_refresh_data, 0);
}
#endif
void charge_manager_set_ceil(int port, enum ceil_requestor requestor, int ceil)
{
if (charge_ceil[port][requestor] != ceil) {
@@ -909,7 +926,7 @@ void charge_manager_force_ceil(int port, int ceil)
* Force our input current to ceil if we're exceeding it, without
* waiting for our deferred task to run.
*/
if (port == charge_port && ceil < charge_current)
if (left_safe_mode && port == charge_port && ceil < charge_current)
board_set_charge_limit(port, CHARGE_SUPPLIER_PD, ceil,
charge_current_uncapped, charge_voltage);
@@ -1178,11 +1195,12 @@ DECLARE_CONSOLE_COMMAND(chglim, command_external_power_limit,
#ifdef CONFIG_CMD_CHARGE_SUPPLIER_INFO
static int charge_supplier_info(int argc, char **argv)
{
ccprintf("port=%d, type=%d, cur=%dmA, vtg=%dmV\n",
ccprintf("port=%d, type=%d, cur=%dmA, vtg=%dmV, lsm=%d\n",
charge_manager_get_active_charge_port(),
charge_supplier,
charge_current,
charge_voltage);
charge_voltage,
left_safe_mode);
return 0;
}

View File

@@ -875,6 +875,13 @@ wait_for_it:
}
#endif
#ifdef CONFIG_CHARGE_MANAGER
if (curr.batt.state_of_charge >=
CONFIG_CHARGE_MANAGER_BAT_PCT_SAFE_MODE_EXIT &&
!battery_seems_to_be_disconnected)
charge_manager_leave_safe_mode();
#endif
/* Keep the AP informed */
if (need_static)
need_static = update_static_battery_info();

View File

@@ -80,6 +80,12 @@ enum dualrole_capabilities {
*/
void charge_manager_update_dualrole(int port, enum dualrole_capabilities cap);
/**
* Tell charge_manager to leave safe mode and switch to standard port / ILIM
* selection logic.
*/
void charge_manager_leave_safe_mode(void);
/**
* Charge ceiling can be set independently by different tasks / functions,
* for different purposes.

View File

@@ -434,6 +434,12 @@
/* Handle the external power limit host command in charge manager */
#undef CONFIG_CHARGE_MANAGER_EXTERNAL_POWER_LIMIT
/* Initially enter safe mode, with relaxed port / current selection rules */
#define CONFIG_CHARGE_MANAGER_SAFE_MODE
/* Leave safe mode when battery pct meets or exceeds this value */
#define CONFIG_CHARGE_MANAGER_BAT_PCT_SAFE_MODE_EXIT 2
/* The hardware has some input current ramping/back-off mechanism */
#undef CONFIG_CHARGE_RAMP_HW

View File

@@ -164,6 +164,48 @@ static int test_initialization(void)
return EC_SUCCESS;
}
static int test_safe_mode(void)
{
int port = 0;
struct charge_port_info charge;
/* Initialize table to no charge */
initialize_charge_table(0, 5000, 5000);
/*
* Set a 2A non-dedicated charger on port 0 and verify that
* it is selected, due to safe mode.
*/
charge_manager_update_dualrole(port, CAP_DUALROLE);
charge.current = 2000;
charge.voltage = 5000;
charge_manager_update_charge(CHARGE_SUPPLIER_TEST2, port, &charge);
wait_for_charge_manager_refresh();
TEST_ASSERT(active_charge_port == port);
TEST_ASSERT(active_charge_limit == 2000);
/* Verify ceil is ignored, due to safe mode. */
charge_manager_set_ceil(port, 0, 500);
wait_for_charge_manager_refresh();
TEST_ASSERT(active_charge_limit == 2000);
/*
* Leave safe mode and verify normal port selection rules go
* into effect.
*/
charge_manager_leave_safe_mode();
wait_for_charge_manager_refresh();
#ifdef CONFIG_CHARGE_MANAGER_DRP_CHARGING
TEST_ASSERT(active_charge_port == port);
TEST_ASSERT(active_charge_limit == 500);
#else
TEST_ASSERT(active_charge_port == CHARGE_PORT_NONE);
#endif
/* For subsequent tests, safe mode is exited. */
return EC_SUCCESS;
}
static int test_priority(void)
{
struct charge_port_info charge;
@@ -749,6 +791,7 @@ void run_test(void)
test_reset();
RUN_TEST(test_initialization);
RUN_TEST(test_safe_mode);
RUN_TEST(test_priority);
RUN_TEST(test_charge_ceil);
RUN_TEST(test_new_power_request);