usb_pd: Add host command to limit external charger voltage / current

PD charger voltage + current can now be limited with
EC_CMD_EXTERNAL_POWER_LIMIT. The limit is automatically cleared when the
AP transitions out of S0 into S3 / suspend.

BUG=chrome-os-partner:43285
TEST=Manual on Samus w/ zinger.
- Plug zinger, verify charging at 20V/3A.
- `ectool extpwrlimit 3000 12000 --dev=1`, verify charging at 12V/3A
- `ectool extpwrlimit 1000 5000 --dev=1`, verify charging at 5V/1A
- Plug zinger into other port, verify still charging at 5V/1A
- `powerd_dbus_suspend`, verify charging at 20V/3A
- `chglim 2000 12000`, verify charging at 12V/2A
- `ectool extpwrlimit 0xffff 0xffff --dev=1`, verify charging at 20V/3A
- `chglim 1000 20000`, verify charging at 20V/1A
- `chglim`, verify charging at 20V/3A
BRANCH=ryu

Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
Change-Id: I6cd5377be91b3df75f99cb414fd3fa5a463b56cb
Reviewed-on: https://chromium-review.googlesource.com/293954
Reviewed-by: Todd Broch <tbroch@chromium.org>
Reviewed-by: Alec Berg <alecaberg@chromium.org>
This commit is contained in:
Shawn Nematbakhsh
2015-08-17 13:55:47 -07:00
committed by ChromeOS Commit Bot
parent 6f8637a6df
commit ad8ce3f806
8 changed files with 130 additions and 23 deletions

View File

@@ -22,6 +22,7 @@
/* Optional features */
#undef CONFIG_CMD_HASH
#define CONFIG_CHARGE_MANAGER
#define CONFIG_CHARGE_MANAGER_EXTERNAL_POWER_LIMIT
#define CONFIG_CHARGE_RAMP_HW
#define CONFIG_FORCE_CONSOLE_RESUME
#define CONFIG_STM_HWTIMER32

View File

@@ -855,3 +855,76 @@ DECLARE_CONSOLE_COMMAND(chgoverride, command_charge_port_override,
"[port | -1 | -2]",
"Force charging from a given port (-1 = off, -2 = disable charging)",
NULL);
#ifdef CONFIG_CHARGE_MANAGER_EXTERNAL_POWER_LIMIT
static void charge_manager_set_external_power_limit(int current_lim,
int voltage_lim)
{
int port;
if (current_lim == EC_POWER_LIMIT_NONE)
current_lim = CHARGE_CEIL_NONE;
if (voltage_lim == EC_POWER_LIMIT_NONE)
voltage_lim = PD_MAX_VOLTAGE_MV;
for (port = 0; port < CONFIG_USB_PD_PORT_COUNT; ++port) {
charge_manager_set_ceil(port, CEIL_REQUESTOR_HOST, current_lim);
pd_set_external_voltage_limit(port, voltage_lim);
}
}
/*
* On transition out of S0, disable all external power limits, in case AP
* failed to clear them.
*/
static void charge_manager_external_power_limit_off(void)
{
charge_manager_set_external_power_limit(EC_POWER_LIMIT_NONE,
EC_POWER_LIMIT_NONE);
}
DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, charge_manager_external_power_limit_off,
HOOK_PRIO_DEFAULT);
static int hc_external_power_limit(struct host_cmd_handler_args *args)
{
const struct ec_params_external_power_limit_v1 *p = args->params;
charge_manager_set_external_power_limit(p->current_lim,
p->voltage_lim);
return EC_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_EXTERNAL_POWER_LIMIT,
hc_external_power_limit,
EC_VER_MASK(1));
static int command_external_power_limit(int argc, char **argv)
{
int max_current;
int max_voltage;
char *e;
if (argc >= 2) {
max_current = strtoi(argv[1], &e, 10);
if (*e)
return EC_ERROR_PARAM1;
} else
max_current = EC_POWER_LIMIT_NONE;
if (argc >= 3) {
max_voltage = strtoi(argv[2], &e, 10);
if (*e)
return EC_ERROR_PARAM1;
} else
max_voltage = EC_POWER_LIMIT_NONE;
charge_manager_set_external_power_limit(max_current, max_voltage);
ccprintf("max req: %dmA %dmV\n", max_current, max_voltage);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(chglim, command_external_power_limit,
"[max_current (mA)] [max_voltage (mV)]",
"Set max charger current / voltage",
NULL);
#endif /* CONFIG_CHARGE_MANAGER_EXTERNAL_POWER_LIMIT */

View File

@@ -34,7 +34,7 @@ static int rw_flash_changed = 1;
#ifdef CONFIG_USB_PD_DUAL_ROLE
/* Cap on the max voltage requested as a sink (in millivolts) */
static unsigned max_request_mv = -1; /* no cap */
static unsigned max_request_mv = PD_MAX_VOLTAGE_MV; /* no cap */
/**
* Find PDO index that offers the most amount of power and stays within
@@ -53,10 +53,6 @@ static int pd_find_pdo_index(int cnt, uint32_t *src_caps, int max_mv)
int cur_mv;
#endif
/* max_mv of -1 represents max limit */
if (max_mv == -1)
max_mv = PD_MAX_VOLTAGE_MV;
/* max voltage is always limited by this boards max request */
max_mv = MIN(max_mv, PD_MAX_VOLTAGE_MV);
@@ -155,7 +151,7 @@ void pd_process_source_cap(int port, int cnt, uint32_t *src_caps)
int pdo_index;
/* Get max power info that we could request */
pdo_index = pd_find_pdo_index(cnt, src_caps, -1);
pdo_index = pd_find_pdo_index(cnt, src_caps, PD_MAX_VOLTAGE_MV);
if (pdo_index < 0)
pdo_index = 0;
pd_extract_pdo_power(src_caps[pdo_index], &ma, &mv);

View File

@@ -2725,6 +2725,19 @@ void pd_request_source_voltage(int port, int mv)
task_wake(PD_PORT_TO_TASK_ID(port));
}
void pd_set_external_voltage_limit(int port, int mv)
{
pd_set_max_voltage(mv);
if (pd[port].task_state == PD_STATE_SNK_READY ||
pd[port].task_state == PD_STATE_SNK_TRANSITION) {
/* Set flag to send new power request in pd_task */
pd[port].new_power_request = 1;
task_wake(PD_PORT_TO_TASK_ID(port));
}
}
#endif /* CONFIG_USB_PD_DUAL_ROLE */
static int command_pd(int argc, char **argv)

View File

@@ -247,6 +247,9 @@
/* Compile charge manager */
#undef CONFIG_CHARGE_MANAGER
/* Handle the external power limit host command in charge manager */
#undef CONFIG_CHARGE_MANAGER_EXTERNAL_POWER_LIMIT
/* Compile input current ramping support */
#undef CONFIG_CHARGE_RAMP

View File

@@ -2842,14 +2842,18 @@ struct ec_params_current_limit {
} __packed;
/*
* Set maximum external power current.
* Set maximum external voltage / current.
*/
#define EC_CMD_EXT_POWER_CURRENT_LIMIT 0xa2
#define EC_CMD_EXTERNAL_POWER_LIMIT 0xa2
struct ec_params_ext_power_current_limit {
uint32_t limit; /* in mA */
/* Command v0 is used only on Spring and is obsolete + unsupported */
struct ec_params_external_power_limit_v1 {
uint16_t current_lim; /* in mA, or EC_POWER_LIMIT_NONE to clear limit */
uint16_t voltage_lim; /* in mV, or EC_POWER_LIMIT_NONE to clear limit */
} __packed;
#define EC_POWER_LIMIT_NONE 0xffff
/*****************************************************************************/
/* Smart battery pass-through */

View File

@@ -946,6 +946,15 @@ int pd_set_power_supply_ready(int port);
*/
void pd_request_source_voltage(int port, int mv);
/**
* Set a voltage limit from the PD source.
*
* If the source is currently active, it triggers a new negotiation.
* @param port USB-C port number
* @param mv limit voltage in millivolts.
*/
void pd_set_external_voltage_limit(int port, int mv);
/**
* Set the PD input current limit.
*

View File

@@ -43,8 +43,6 @@ static struct option long_opts[] = {
const char help_str[] =
"Commands:\n"
" extpwrcurrentlimit\n"
" Set the maximum external power current\n"
" autofanctrl <on>\n"
" Turn on automatic fan speed control.\n"
" backlight <enabled>\n"
@@ -93,6 +91,8 @@ const char help_str[] =
" Sets the SMI mask for EC host events\n"
" eventsetwakemask <mask>\n"
" Sets the wake mask for EC host events\n"
" extpwrlimit\n"
" Set the maximum external power limit\n"
" fanduty <percent>\n"
" Forces the fan PWM to a constant duty cycle\n"
" flasherase <offset> <size>\n"
@@ -4829,26 +4829,34 @@ int cmd_lcd_backlight(int argc, char *argv[])
}
int cmd_ext_power_current_limit(int argc, char *argv[])
int cmd_ext_power_limit(int argc, char *argv[])
{
struct ec_params_ext_power_current_limit p;
int rv;
/* Version 1 is used, no support for obsolete version 0 */
struct ec_params_external_power_limit_v1 p;
char *e;
if (argc != 2) {
fprintf(stderr, "Usage: %s <max_current_mA>\n", argv[0]);
if (argc != 3) {
fprintf(stderr,
"Usage: %s <max_current_mA> <max_voltage_mV>\n",
argv[0]);
return -1;
}
p.limit = strtol(argv[1], &e, 0);
p.current_lim = strtol(argv[1], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad value.\n");
fprintf(stderr, "Bad param1.\n");
return -1;
}
rv = ec_command(EC_CMD_EXT_POWER_CURRENT_LIMIT, 0, &p, sizeof(p),
NULL, 0);
return rv;
p.voltage_lim = strtol(argv[2], &e, 0);
if (e && *e) {
fprintf(stderr, "Bad param2.\n");
return -1;
}
/* Send version 1 of command */
return ec_command(EC_CMD_EXTERNAL_POWER_LIMIT, 1, &p, sizeof(p),
NULL, 0);
}
@@ -6315,7 +6323,6 @@ int cmd_pd_write_log(int argc, char *argv[])
/* NULL-terminated list of commands */
const struct command commands[] = {
{"extpwrcurrentlimit", cmd_ext_power_current_limit},
{"autofanctrl", cmd_thermal_auto_fan_ctrl},
{"backlight", cmd_lcd_backlight},
{"battery", cmd_battery},
@@ -6340,6 +6347,7 @@ const struct command commands[] = {
{"eventsetscimask", cmd_host_event_set_sci_mask},
{"eventsetsmimask", cmd_host_event_set_smi_mask},
{"eventsetwakemask", cmd_host_event_set_wake_mask},
{"extpwrlimit", cmd_ext_power_limit},
{"fanduty", cmd_fanduty},
{"flasherase", cmd_flash_erase},
{"flashprotect", cmd_flash_protect},