mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
charge_manager: Support multiple independent charge ceilings
We will soon have a need to independently set a charge ceiling from both the PD state machine and from incoming host commands. Store these ceilings separately, and have the minimum take effect. BUG=chrome-os-partner:43285 TEST=Pass unit tests. Also, host command current limit takes effect with subsequent commit. BRANCH=None Change-Id: I0ecfe888a7df0d5da5a68999c164c7c841da348b Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/293818 Reviewed-by: Alec Berg <alecaberg@chromium.org>
This commit is contained in:
committed by
ChromeOS Commit Bot
parent
aa14b36f18
commit
4d382ad640
@@ -45,10 +45,12 @@ static struct charge_port_info available_charge[CHARGE_SUPPLIER_COUNT]
|
||||
static timestamp_t registration_time[CONFIG_USB_PD_PORT_COUNT];
|
||||
|
||||
/*
|
||||
* Charge ceiling for ports. This can be set to temporarily limit the charge
|
||||
* pulled from a port, without influencing the port selection logic.
|
||||
* Charge current ceiling (mA) for ports. This can be set to temporarily limit
|
||||
* the charge pulled from a port, without influencing the port selection logic.
|
||||
* The ceiling can be set independently from several requestors, with the
|
||||
* minimum ceiling taking effect.
|
||||
*/
|
||||
static int charge_ceil[CONFIG_USB_PD_PORT_COUNT];
|
||||
static int charge_ceil[CONFIG_USB_PD_PORT_COUNT][CEIL_REQUESTOR_COUNT];
|
||||
|
||||
/* Dual-role capability of attached partner port */
|
||||
static enum dualrole_capabilities dualrole_capability[CONFIG_USB_PD_PORT_COUNT];
|
||||
@@ -105,7 +107,8 @@ static void charge_manager_init(void)
|
||||
available_charge[j][i].voltage =
|
||||
CHARGE_VOLTAGE_UNINITIALIZED;
|
||||
}
|
||||
charge_ceil[i] = CHARGE_CEIL_NONE;
|
||||
for (j = 0; j < CEIL_REQUESTOR_COUNT; ++j)
|
||||
charge_ceil[i][j] = CHARGE_CEIL_NONE;
|
||||
dualrole_capability[i] = spoof_capability ? CAP_DEDICATED :
|
||||
CAP_UNKNOWN;
|
||||
}
|
||||
@@ -316,6 +319,29 @@ static void charge_manager_cleanup_override_port(int port)
|
||||
pd_request_power_swap(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the computed charge ceiling for a port, which represents the
|
||||
* minimum ceiling among all valid requestors.
|
||||
*
|
||||
* @param port Charge port.
|
||||
* @return Charge ceiling (mA) or CHARGE_CEIL_NONE.
|
||||
*/
|
||||
static int charge_manager_get_ceil(int port)
|
||||
{
|
||||
int ceil = CHARGE_CEIL_NONE;
|
||||
int val, i;
|
||||
|
||||
ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_COUNT);
|
||||
for (i = 0; i < CEIL_REQUESTOR_COUNT; ++i) {
|
||||
val = charge_ceil[port][i];
|
||||
if (val != CHARGE_CEIL_NONE &&
|
||||
(ceil == CHARGE_CEIL_NONE || val < ceil))
|
||||
ceil = val;
|
||||
}
|
||||
|
||||
return ceil;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the 'best' charge port, as defined by the supplier heirarchy and the
|
||||
* ability of the port to provide power.
|
||||
@@ -411,6 +437,7 @@ static void charge_manager_refresh(void)
|
||||
int new_charge_voltage, i;
|
||||
int updated_new_port = CHARGE_PORT_NONE;
|
||||
int updated_old_port = CHARGE_PORT_NONE;
|
||||
int ceil;
|
||||
|
||||
/* Hunt for an acceptable charge port */
|
||||
while (1) {
|
||||
@@ -467,8 +494,9 @@ static void charge_manager_refresh(void)
|
||||
new_charge_current_uncapped);
|
||||
#endif /* CONFIG_CHARGE_RAMP_HW */
|
||||
/* Enforce port charge ceiling. */
|
||||
if (charge_ceil[new_port] != CHARGE_CEIL_NONE)
|
||||
new_charge_current = MIN(charge_ceil[new_port],
|
||||
ceil = charge_manager_get_ceil(new_port);
|
||||
if (ceil != CHARGE_CEIL_NONE)
|
||||
new_charge_current = MIN(ceil,
|
||||
new_charge_current_uncapped);
|
||||
else
|
||||
new_charge_current = new_charge_current_uncapped;
|
||||
@@ -677,17 +705,20 @@ void charge_manager_update_dualrole(int port, enum dualrole_capabilities cap)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update charge ceiling for a given port.
|
||||
* Update charge ceiling for a given port. The ceiling can be set independently
|
||||
* for several requestors, and the min. ceil will be enforced.
|
||||
*
|
||||
* @param port Charge port to update.
|
||||
* @param requestor Charge ceiling requestor.
|
||||
* @param ceil Charge ceiling (mA).
|
||||
*/
|
||||
void charge_manager_set_ceil(int port, int ceil)
|
||||
void charge_manager_set_ceil(int port, enum ceil_requestor requestor, int ceil)
|
||||
{
|
||||
ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_COUNT);
|
||||
ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_COUNT &&
|
||||
requestor >= 0 && requestor < CEIL_REQUESTOR_COUNT);
|
||||
|
||||
if (charge_ceil[port] != ceil) {
|
||||
charge_ceil[port] = ceil;
|
||||
if (charge_ceil[port][requestor] != ceil) {
|
||||
charge_ceil[port][requestor] = ceil;
|
||||
if (port == charge_port && charge_manager_is_seeded())
|
||||
hook_call_deferred(charge_manager_refresh, 0);
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ void pd_process_source_cap(int port, int cnt, uint32_t *src_caps)
|
||||
pd_extract_pdo_power(src_caps[pdo_index], &ma, &mv);
|
||||
|
||||
/* Set max. limit, but apply 500mA ceiling */
|
||||
charge_manager_set_ceil(port, PD_MIN_MA);
|
||||
charge_manager_set_ceil(port, CEIL_REQUESTOR_PD, PD_MIN_MA);
|
||||
pd_set_input_current_limit(port, ma, mv);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -265,7 +265,9 @@ static inline void set_state(int port, enum pd_states next_state)
|
||||
pd_set_input_current_limit(port, 0, 0);
|
||||
#ifdef CONFIG_CHARGE_MANAGER
|
||||
typec_set_input_current_limit(port, 0, 0);
|
||||
charge_manager_set_ceil(port, CHARGE_CEIL_NONE);
|
||||
charge_manager_set_ceil(port,
|
||||
CEIL_REQUESTOR_PD,
|
||||
CHARGE_CEIL_NONE);
|
||||
#endif
|
||||
#ifdef CONFIG_USBC_VCONN
|
||||
tcpm_set_vconn(port, 0);
|
||||
@@ -505,7 +507,9 @@ void pd_execute_hard_reset(int port)
|
||||
/* Clear the input current limit */
|
||||
pd_set_input_current_limit(port, 0, 0);
|
||||
#ifdef CONFIG_CHARGE_MANAGER
|
||||
charge_manager_set_ceil(port, CHARGE_CEIL_NONE);
|
||||
charge_manager_set_ceil(port,
|
||||
CEIL_REQUESTOR_PD,
|
||||
CHARGE_CEIL_NONE);
|
||||
#endif /* CONFIG_CHARGE_MANAGER */
|
||||
|
||||
set_state(port, PD_STATE_SNK_HARD_RESET_RECOVER);
|
||||
@@ -870,7 +874,9 @@ static void handle_ctrl_request(int port, uint16_t head,
|
||||
set_state(port, PD_STATE_SNK_READY);
|
||||
#ifdef CONFIG_CHARGE_MANAGER
|
||||
/* Set ceiling based on what's negotiated */
|
||||
charge_manager_set_ceil(port, pd[port].curr_limit);
|
||||
charge_manager_set_ceil(port,
|
||||
CEIL_REQUESTOR_PD,
|
||||
pd[port].curr_limit);
|
||||
#else
|
||||
pd_set_input_current_limit(port, pd[port].curr_limit,
|
||||
pd[port].supply_voltage);
|
||||
@@ -2211,7 +2217,9 @@ void pd_task(void)
|
||||
pd_set_input_current_limit(port, 0, 0);
|
||||
#ifdef CONFIG_CHARGE_MANAGER
|
||||
typec_set_input_current_limit(port, 0, 0);
|
||||
charge_manager_set_ceil(port, CHARGE_CEIL_NONE);
|
||||
charge_manager_set_ceil(port,
|
||||
CEIL_REQUESTOR_PD,
|
||||
CHARGE_CEIL_NONE);
|
||||
#endif
|
||||
set_state(port, PD_STATE_SNK_SWAP_SRC_DISABLE);
|
||||
timeout = 10*MSEC;
|
||||
|
||||
@@ -51,8 +51,21 @@ enum dualrole_capabilities {
|
||||
/* Called by charging tasks to indicate partner dualrole capability change */
|
||||
void charge_manager_update_dualrole(int port, enum dualrole_capabilities cap);
|
||||
|
||||
/* Update charge ceiling for a given port */
|
||||
void charge_manager_set_ceil(int port, int ceil);
|
||||
/*
|
||||
* Charge ceiling can be set independently by different tasks / functions,
|
||||
* for different purposes.
|
||||
*/
|
||||
enum ceil_requestor {
|
||||
/* Set by PD task, during negotiation */
|
||||
CEIL_REQUESTOR_PD,
|
||||
/* Set by host commands */
|
||||
CEIL_REQUESTOR_HOST,
|
||||
/* Number of ceiling groups */
|
||||
CEIL_REQUESTOR_COUNT,
|
||||
};
|
||||
|
||||
/* Update charge ceiling for a given port / requestor */
|
||||
void charge_manager_set_ceil(int port, enum ceil_requestor requestor, int ceil);
|
||||
|
||||
/* Select an 'override port', which is always the preferred charge port */
|
||||
int charge_manager_set_override(int port);
|
||||
|
||||
@@ -118,7 +118,8 @@ static void initialize_charge_table(int current, int voltage, int ceil)
|
||||
charge.voltage = voltage;
|
||||
|
||||
for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; ++i) {
|
||||
charge_manager_set_ceil(i, ceil);
|
||||
for (j = 0; j < CEIL_REQUESTOR_COUNT; ++j)
|
||||
charge_manager_set_ceil(i, j, ceil);
|
||||
charge_manager_update_dualrole(i, CAP_DEDICATED);
|
||||
pd_set_role(i, PD_ROLE_SINK);
|
||||
for (j = 0; j < CHARGE_SUPPLIER_COUNT; ++j)
|
||||
@@ -246,13 +247,13 @@ static int test_charge_ceil(void)
|
||||
|
||||
/* Set a 500mA ceiling, verify port is unchanged */
|
||||
port = active_charge_port;
|
||||
charge_manager_set_ceil(port, 500);
|
||||
charge_manager_set_ceil(port, 0, 500);
|
||||
wait_for_charge_manager_refresh();
|
||||
TEST_ASSERT(port == active_charge_port);
|
||||
TEST_ASSERT(active_charge_limit == 500);
|
||||
|
||||
/* Raise the ceiling to 2A, verify limit goes back to 1A */
|
||||
charge_manager_set_ceil(port, 2000);
|
||||
charge_manager_set_ceil(port, 0, 2000);
|
||||
wait_for_charge_manager_refresh();
|
||||
TEST_ASSERT(port == active_charge_port);
|
||||
TEST_ASSERT(active_charge_limit == 1000);
|
||||
@@ -263,11 +264,35 @@ static int test_charge_ceil(void)
|
||||
charge_manager_update_charge(0, 0, &charge);
|
||||
charge.current = 2500;
|
||||
charge_manager_update_charge(0, 1, &charge);
|
||||
charge_manager_set_ceil(1, 750);
|
||||
charge_manager_set_ceil(1, 0, 750);
|
||||
wait_for_charge_manager_refresh();
|
||||
TEST_ASSERT(active_charge_port == 1);
|
||||
TEST_ASSERT(active_charge_limit == 750);
|
||||
|
||||
/* Set a secondary lower ceiling and verify it takes effect */
|
||||
charge_manager_set_ceil(1, 1, 500);
|
||||
wait_for_charge_manager_refresh();
|
||||
TEST_ASSERT(active_charge_port == 1);
|
||||
TEST_ASSERT(active_charge_limit == 500);
|
||||
|
||||
/* Raise the secondary ceiling and verify the primary takes effect */
|
||||
charge_manager_set_ceil(1, 1, 800);
|
||||
wait_for_charge_manager_refresh();
|
||||
TEST_ASSERT(active_charge_port == 1);
|
||||
TEST_ASSERT(active_charge_limit == 750);
|
||||
|
||||
/* Remove the primary celing and verify the secondary takes effect */
|
||||
charge_manager_set_ceil(1, 0, CHARGE_CEIL_NONE);
|
||||
wait_for_charge_manager_refresh();
|
||||
TEST_ASSERT(active_charge_port == 1);
|
||||
TEST_ASSERT(active_charge_limit == 800);
|
||||
|
||||
/* Remove all ceilings */
|
||||
charge_manager_set_ceil(1, 1, CHARGE_CEIL_NONE);
|
||||
wait_for_charge_manager_refresh();
|
||||
TEST_ASSERT(active_charge_port == 1);
|
||||
TEST_ASSERT(active_charge_limit == 2500);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -293,7 +318,7 @@ static int test_new_power_request(void)
|
||||
clear_new_power_requests();
|
||||
|
||||
/* Reduce port 1 through ceil and verify no NPR */
|
||||
charge_manager_set_ceil(1, 500);
|
||||
charge_manager_set_ceil(1, 0, 500);
|
||||
wait_for_charge_manager_refresh();
|
||||
TEST_ASSERT(new_power_request[0] == 0);
|
||||
TEST_ASSERT(new_power_request[1] == 0);
|
||||
|
||||
Reference in New Issue
Block a user