summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/samus/board.c2
-rw-r--r--board/samus/extpower.c204
-rw-r--r--board/samus_pd/board.c167
-rw-r--r--board/samus_pd/board.h1
-rw-r--r--common/charge_state_v2.c3
-rw-r--r--common/host_command_pd.c20
-rw-r--r--common/usb_pd_protocol.c15
-rw-r--r--driver/charger/bq24773.c13
-rw-r--r--include/config.h15
-rw-r--r--include/ec_commands.h10
-rw-r--r--include/host_command.h4
-rw-r--r--include/usb_pd.h8
12 files changed, 332 insertions, 130 deletions
diff --git a/board/samus/board.c b/board/samus/board.c
index 7199d60c6b..7f606516b0 100644
--- a/board/samus/board.c
+++ b/board/samus/board.c
@@ -47,7 +47,7 @@
static void pd_mcu_interrupt(enum gpio_signal signal)
{
/* Exchange status with PD MCU. */
- host_command_pd_send_status();
+ host_command_pd_send_status(PD_CHARGE_NO_CHANGE);
}
#include "gpio_list.h"
diff --git a/board/samus/extpower.c b/board/samus/extpower.c
index 8eb2494795..51cf5454e8 100644
--- a/board/samus/extpower.c
+++ b/board/samus/extpower.c
@@ -8,6 +8,8 @@
* Drive high in S5-S0 when AC_PRESENT is high, otherwise drive low.
*/
+#include "bq24773.h"
+#include "charge_state.h"
#include "charger.h"
#include "chipset.h"
#include "common.h"
@@ -16,13 +18,32 @@
#include "gpio.h"
#include "hooks.h"
#include "host_command.h"
+#include "i2c.h"
#include "system.h"
#include "task.h"
#include "util.h"
+/* Console output macros */
+#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
+
+/* Max number of attempts to enable/disable NVDC charger */
+#define CHARGER_MODE_ATTEMPTS 3
+
/* Backboost has been detected */
static int bkboost_detected;
+/* Charging is disabled */
+static int charge_is_disabled;
+
+/*
+ * Charge circuit occasionally gets wedged and doesn't charge.
+ * This variable keeps track of the state of the circuit.
+ */
+static enum {
+ CHARGE_CIRCUIT_OK,
+ CHARGE_CIRCUIT_WEDGED,
+} charge_circuit_state = CHARGE_CIRCUIT_OK;
+
int extpower_is_present(void)
{
return gpio_get_level(GPIO_AC_PRESENT);
@@ -64,71 +85,188 @@ static void extpower_init(void)
}
DECLARE_HOOK(HOOK_INIT, extpower_init, HOOK_PRIO_DEFAULT);
-static void extpower_board_hacks(int extpower)
+/*
+ * Save power in S3/S5/G3 by disabling charging when the battery is
+ * full. Restore charging when battery is not full anymore. This saves
+ * power because our input AC path is inefficient.
+ */
+
+static void check_charging_cutoff(void)
{
- static int extpower_prev;
+ /* If battery is full disable charging */
+ if (charge_get_percent() == 100) {
+ charge_is_disabled = 1;
+ host_command_pd_send_status(PD_CHARGE_NONE);
+ }
+}
+DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, check_charging_cutoff, HOOK_PRIO_DEFAULT);
- /*
- * Use discharge_on_ac() to workaround hardware backboosting
- * charge circuit problems.
- */
- int use_bkboost_workaround = (system_get_board_version() < 1);
+static void cancel_charging_cutoff(void)
+{
+ /* If charging is disabled, enable it */
+ if (charge_is_disabled) {
+ charge_is_disabled = 0;
+ host_command_pd_send_status(PD_CHARGE_5V);
+ }
+}
+DECLARE_HOOK(HOOK_CHIPSET_RESUME, cancel_charging_cutoff, HOOK_PRIO_DEFAULT);
+
+static void batt_soc_change(void)
+{
+ /* If in S0, leave charging alone */
+ if (chipset_in_state(CHIPSET_STATE_ON))
+ return;
+
+ /* Check to disable or enable charging based on batt state of charge */
+ if (!charge_is_disabled && charge_get_percent() == 100) {
+ host_command_pd_send_status(PD_CHARGE_NONE);
+ charge_is_disabled = 1;
+ } else if (charge_is_disabled && charge_get_percent() < 100) {
+ charge_is_disabled = 0;
+ host_command_pd_send_status(PD_CHARGE_5V);
+ }
+}
+DECLARE_HOOK(HOOK_BATTERY_SOC_CHANGE, batt_soc_change, HOOK_PRIO_DEFAULT);
+
+/**
+ * Enable/disable NVDC charger to control AC to system and battery.
+ */
+static void charger_disable(int disable)
+{
+ int i, rv;
+
+ for (i = 0; i < CHARGER_MODE_ATTEMPTS; i++) {
+ rv = charger_discharge_on_ac(disable);
+ if (rv == EC_SUCCESS)
+ return;
+ }
+
+ CPRINTS("Setting learn mode %d failed!", disable);
+}
+
+static void allow_max_request(void)
+{
+ int prochot_status;
+ if (charge_circuit_state == CHARGE_CIRCUIT_WEDGED) {
+ /* Read PROCHOT status register to clear it */
+ i2c_read8(I2C_PORT_CHARGER, BQ24773_ADDR,
+ BQ24773_PROCHOT_STATUS, &prochot_status);
+ charge_circuit_state = CHARGE_CIRCUIT_OK;
+ }
+ host_command_pd_send_status(PD_CHARGE_MAX);
+}
+DECLARE_DEFERRED(allow_max_request);
+
+static void extpower_board_hacks(int extpower, int extpower_prev)
+{
+ /* Cancel deferred attempt to enable max charge request */
+ hook_call_deferred(allow_max_request, -1);
/*
+ * When AC is detected, delay briefly before allowing PD
+ * to negotiate up to the max voltage to give charge circuit
+ * time to settle down. When AC goes away, set PD to only allow
+ * 5V charging for the next time AC is connected.
+ *
+ * Use NVDC charger learn mode (charger_disable()) when AC
+ * is not present to avoid backboosting when AC is plugged in.
+ *
* When in G3, PP5000 needs to be enabled to accurately sense
* CC voltage when AC is attached. When AC is disconnceted
* it needs to be off to save power.
*/
if (extpower && !extpower_prev) {
- if (use_bkboost_workaround)
- charger_discharge_on_ac(0);
-
+ /* AC connected */
+ charger_disable(0);
+ hook_call_deferred(allow_max_request, 500*MSEC);
set_pp5000_in_g3(PP5000_IN_G3_AC, 1);
} else if (extpower && extpower_prev) {
- if (use_bkboost_workaround) {
- /*
- * Glitch on AC_PRESENT, attempt to recover from
- * backboost
- */
- charger_discharge_on_ac(1);
- charger_discharge_on_ac(0);
- }
+ /*
+ * Glitch on AC_PRESENT, attempt to recover from
+ * backboost
+ */
+ host_command_pd_send_status(PD_CHARGE_NONE);
} else {
- if (use_bkboost_workaround)
- charger_discharge_on_ac(1);
+ /* AC disconnected */
+ if (!charge_is_disabled &&
+ charge_circuit_state == CHARGE_CIRCUIT_OK)
+ host_command_pd_send_status(PD_CHARGE_NONE);
+
+ charger_disable(1);
+
+ if (!charge_is_disabled &&
+ charge_circuit_state == CHARGE_CIRCUIT_OK)
+ host_command_pd_send_status(PD_CHARGE_5V);
set_pp5000_in_g3(PP5000_IN_G3_AC, 0);
}
extpower_prev = extpower;
}
+static void check_charge_wedged(void)
+{
+ int rv, prochot_status;
+
+ if (charge_circuit_state == CHARGE_CIRCUIT_OK) {
+ /* Check PROCHOT warning */
+ rv = i2c_read8(I2C_PORT_CHARGER, BQ24773_ADDR,
+ BQ24773_PROCHOT_STATUS, &prochot_status);
+ if (rv)
+ return;
+
+ /*
+ * If PROCHOT is asserted, then charge circuit is wedged, turn
+ * on learn mode and notify PD to disable charging on all ports.
+ * Note: learn mode is critical here because when in this state
+ * backboosting causes >20V on boostin even after PD disables
+ * CHARGE_EN lines.
+ */
+ if (prochot_status) {
+ host_command_pd_send_status(PD_CHARGE_NONE);
+ charge_circuit_state = CHARGE_CIRCUIT_WEDGED;
+ CPRINTS("Charge circuit wedged!");
+ }
+ } else {
+ /*
+ * Charge circuit is wedged and we already disabled charging,
+ * Now start to recover from wedged state by allowing 5V.
+ */
+ host_command_pd_send_status(PD_CHARGE_5V);
+ }
+}
+
/**
* Task to handle external power change
*/
void extpower_task(void)
{
int extpower = extpower_is_present();
- extpower_board_hacks(extpower);
+ int extpower_prev = 0;
+
+ extpower_board_hacks(extpower, extpower_prev);
/* Enable backboost detection interrupt */
gpio_enable_interrupt(GPIO_BKBOOST_DET);
while (1) {
- /* Wait until next extpower interrupt */
- task_wait_event(-1);
-
- extpower = extpower_is_present();
+ if (task_wait_event(2*SECOND) == TASK_EVENT_TIMER) {
+ /* Periodically check if charge circuit is wedged */
+ check_charge_wedged();
+ } else {
+ /* Must have received power change interrupt */
+ extpower = extpower_is_present();
- /* Various board hacks to run on extpower change */
- extpower_board_hacks(extpower);
+ /* Various board hacks to run on extpower change */
+ extpower_board_hacks(extpower, extpower_prev);
+ extpower_prev = extpower;
- hook_notify(HOOK_AC_CHANGE);
+ hook_notify(HOOK_AC_CHANGE);
- /* Forward notification to host */
- if (extpower)
- host_set_single_event(EC_HOST_EVENT_AC_CONNECTED);
- else
- host_set_single_event(EC_HOST_EVENT_AC_DISCONNECTED);
+ /* Forward notification to host */
+ host_set_single_event(extpower ?
+ EC_HOST_EVENT_AC_CONNECTED :
+ EC_HOST_EVENT_AC_DISCONNECTED);
+ }
}
}
diff --git a/board/samus_pd/board.c b/board/samus_pd/board.c
index d89527dfc2..3fd3f0e219 100644
--- a/board/samus_pd/board.c
+++ b/board/samus_pd/board.c
@@ -37,11 +37,9 @@ 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;
+/* Default to 5V charging allowed for dead battery case */
+enum pd_charge_state charge_state = PD_CHARGE_5V;
/* PD MCU status and host event status for host command */
static struct ec_response_pd_status pd_status;
@@ -266,31 +264,6 @@ void usb1_evt(enum gpio_signal signal)
wake_usb_charger_task(1);
}
-/* 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)
{
ps = POWER_S3;
@@ -301,9 +274,6 @@ 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);
}
@@ -318,8 +288,6 @@ 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);
}
@@ -438,6 +406,9 @@ static void board_init(void)
gpio_enable_interrupt(GPIO_PCH_SLP_S3_L);
gpio_enable_interrupt(GPIO_PCH_SLP_S5_L);
+ /* Initialize active charge port to none */
+ pd_status.active_charge_port = CHARGE_PORT_NONE;
+
/*
* Do not enable PD communication in RO as a security measure.
* We don't want to allow communication to outside world until
@@ -596,7 +567,6 @@ 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)
@@ -643,26 +613,42 @@ int board_set_active_charge_port(int charge_port)
return EC_ERROR_INVAL;
}
- pd_status.active_charge_port = 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));
+ CPRINTS("New chg p%d", charge_port);
/*
- * 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 charging and the active charge port is changed, then disable
+ * charging to guarantee charge circuit starts up cleanly.
*/
- if (chg_is_cutoff && is_real_port) {
- chg_override_port = OVERRIDE_OFF;
- chg_is_cutoff = 0;
+ if (pd_status.active_charge_port != CHARGE_PORT_NONE &&
+ (charge_port == CHARGE_PORT_NONE ||
+ charge_port != pd_status.active_charge_port)) {
+ gpio_set_level(GPIO_USB_C0_CHARGE_EN_L, 1);
+ gpio_set_level(GPIO_USB_C1_CHARGE_EN_L, 1);
+ charge_state = PD_CHARGE_NONE;
+ pd_status.active_charge_port = charge_port;
+ CPRINTS("Chg: None\n");
+ return EC_SUCCESS;
+ }
+
+ /* Save active charge port and enable charging if allowed */
+ pd_status.active_charge_port = charge_port;
+ if (charge_state != PD_CHARGE_NONE) {
+ gpio_set_level(GPIO_USB_C0_CHARGE_EN_L, !(charge_port == 0));
+ gpio_set_level(GPIO_USB_C1_CHARGE_EN_L, !(charge_port == 1));
}
- check_charging_cutoff();
- CPRINTS("New chg p%d", charge_port);
return EC_SUCCESS;
}
/**
+ * Return if max voltage charging is allowed.
+ */
+int pd_is_max_request_allowed(void)
+{
+ return charge_state == PD_CHARGE_MAX;
+}
+
+/**
* Set the charge limit based upon desired maximum.
*
* @param charge_ma Desired charge limit (mA).
@@ -732,36 +718,6 @@ 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)
@@ -769,9 +725,60 @@ 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;
- /* 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);
+ /* update battery soc */
+ board_update_battery_soc(p->batt_soc);
+
+ if (args->version == 1) {
+ if (p->charge_state != charge_state) {
+ switch (p->charge_state) {
+ case PD_CHARGE_NONE:
+ /*
+ * No current allowed in, set new power request
+ * so that PD negotiates down to vSafe5V.
+ */
+ charge_state = p->charge_state;
+ gpio_set_level(GPIO_USB_C0_CHARGE_EN_L, 1);
+ gpio_set_level(GPIO_USB_C1_CHARGE_EN_L, 1);
+ pd_set_new_power_request(
+ pd_status.active_charge_port);
+ CPRINTS("Chg: None");
+ break;
+ case PD_CHARGE_5V:
+ /* Allow current on the active charge port */
+ charge_state = p->charge_state;
+ gpio_set_level(GPIO_USB_C0_CHARGE_EN_L,
+ !(pd_status.active_charge_port == 0));
+ gpio_set_level(GPIO_USB_C1_CHARGE_EN_L,
+ !(pd_status.active_charge_port == 1));
+ CPRINTS("Chg: 5V");
+ break;
+ case PD_CHARGE_MAX:
+ /*
+ * Allow negotiation above vSafe5V. Should only
+ * ever get this command when 5V charging is
+ * already allowed.
+ */
+ if (charge_state == PD_CHARGE_5V) {
+ charge_state = p->charge_state;
+ pd_set_new_power_request(
+ pd_status.active_charge_port);
+ CPRINTS("Chg: Max");
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ /*
+ * If the EC is using this command version, then it won't ever
+ * set charging allowed, so we should just assume charging at
+ * the max is allowed.
+ */
+ charge_state = PD_CHARGE_MAX;
+ pd_set_new_power_request(pd_status.active_charge_port);
+ CPRINTS("Chg: Max");
+ }
*r = pd_status;
@@ -783,7 +790,7 @@ static int ec_status_host_cmd(struct host_cmd_handler_args *args)
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_PD_EXCHANGE_STATUS, ec_status_host_cmd,
- EC_VER_MASK(0));
+ EC_VER_MASK(0) | EC_VER_MASK(1));
static int host_event_status_host_cmd(struct host_cmd_handler_args *args)
{
diff --git a/board/samus_pd/board.h b/board/samus_pd/board.h
index 702dfcc9f5..641f78ece1 100644
--- a/board/samus_pd/board.h
+++ b/board/samus_pd/board.h
@@ -40,6 +40,7 @@
#define CONFIG_USB_POWER_DELIVERY
#define CONFIG_USB_PD_ALT_MODE
#define CONFIG_USB_PD_ALT_MODE_DFP
+#define CONFIG_USB_PD_CHECK_MAX_REQUEST_ALLOWED
#undef CONFIG_USB_PD_COMM_ENABLED
#define CONFIG_USB_PD_COMM_ENABLED 0
#define CONFIG_USB_PD_CUSTOM_VDM
diff --git a/common/charge_state_v2.c b/common/charge_state_v2.c
index 2487f05fe5..445819fc4e 100644
--- a/common/charge_state_v2.c
+++ b/common/charge_state_v2.c
@@ -774,9 +774,6 @@ wait_for_it:
show_charging_progress();
prev_charge = curr.batt.state_of_charge;
hook_notify(HOOK_BATTERY_SOC_CHANGE);
-#ifdef HAS_TASK_PDCMD
- host_command_pd_send_status();
-#endif
}
prev_full = is_full;
diff --git a/common/host_command_pd.c b/common/host_command_pd.c
index 5e3494c46e..e9282abee4 100644
--- a/common/host_command_pd.c
+++ b/common/host_command_pd.c
@@ -17,8 +17,15 @@
#define TASK_EVENT_EXCHANGE_PD_STATUS TASK_EVENT_CUSTOM(1)
-void host_command_pd_send_status(void)
+/* By default allow 5V charging only for the dead battery case */
+static enum pd_charge_state charge_state = PD_CHARGE_5V;
+
+void host_command_pd_send_status(enum pd_charge_state new_chg_state)
{
+ /* Update PD MCU charge state if necessary */
+ if (new_chg_state != PD_CHARGE_NO_CHANGE)
+ charge_state = new_chg_state;
+ /* Wake PD HC task to send status */
task_set_event(TASK_ID_PDCMD, TASK_EVENT_EXCHANGE_PD_STATUS, 0);
}
@@ -31,13 +38,20 @@ void pd_exchange_status(int *charge_port)
};
int rv = 0;
- /* Send battery state of charge */
+ /* Send PD charge state and battery state of charge */
+ ec_status.charge_state = charge_state;
if (charge_get_flags() & CHARGE_FLAG_BATT_RESPONSIVE)
ec_status.batt_soc = charge_get_percent();
else
ec_status.batt_soc = -1;
- rv = pd_host_command(EC_CMD_PD_EXCHANGE_STATUS, 0, &ec_status,
+ rv = pd_host_command(EC_CMD_PD_EXCHANGE_STATUS, 1, &ec_status,
+ sizeof(struct ec_params_pd_status), &pd_status,
+ sizeof(struct ec_response_pd_status));
+
+ /* If PD doesn't support new command version, try old version */
+ if (rv == -EC_RES_INVALID_VERSION)
+ rv = pd_host_command(EC_CMD_PD_EXCHANGE_STATUS, 0, &ec_status,
sizeof(struct ec_params_pd_status), &pd_status,
sizeof(struct ec_response_pd_status));
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 0bad095dd5..8d168e1f1c 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -917,14 +917,25 @@ static void pd_send_request_msg(int port, int always_send_request)
#else
const int charging = 1;
#endif
+
+#ifdef CONFIG_USB_PD_CHECK_MAX_REQUEST_ALLOWED
+ int max_request_allowed = pd_is_max_request_allowed();
+#else
+ const int max_request_allowed = 1;
+#endif
+
/* Clear new power request */
pd[port].new_power_request = 0;
/* Build and send request RDO */
- /* If this port is not actively charging, select vSafe5V */
+ /*
+ * If this port is not actively charging or we are not allowed to
+ * request the max voltage, then select vSafe5V
+ */
res = pd_build_request(pd_src_cap_cnt[port], pd_src_caps[port],
&rdo, &curr_limit, &supply_voltage,
- charging ? PD_REQUEST_MAX : PD_REQUEST_VSAFE5V);
+ charging && max_request_allowed ?
+ PD_REQUEST_MAX : PD_REQUEST_VSAFE5V);
if (res != EC_SUCCESS)
/*
diff --git a/driver/charger/bq24773.c b/driver/charger/bq24773.c
index fc5e7c688c..becef6d378 100644
--- a/driver/charger/bq24773.c
+++ b/driver/charger/bq24773.c
@@ -184,9 +184,22 @@ int charger_post_init(void)
if (rv)
return rv;
+#ifndef BOARD_SAMUS
/* Turn off PROCHOT warning */
rv = i2c_write8(I2C_PORT_CHARGER, BQ24773_ADDR,
BQ24773_PROCHOT_OPTION1, 0);
+#else
+ /* On Samus, use PROCHOT warning to detect charging problems */
+ /* Turn on PROCHOT warning */
+ rv = i2c_write16(I2C_PORT_CHARGER, BQ24773_ADDR,
+ BQ24773_PROCHOT_OPTION1, 0x8120);
+ /* Set PROCHOT ICRIT warning when IADP is >120% of IDPM */
+ rv |= i2c_write16(I2C_PORT_CHARGER, BQ24773_ADDR,
+ BQ24773_PROCHOT_OPTION0, 0x1b54);
+#endif
+
+ if (rv)
+ return rv;
#ifdef CONFIG_CHARGER_ILIM_PIN_DISABLED
/* Read the external ILIM pin enabled flag. */
diff --git a/include/config.h b/include/config.h
index 435a8889d0..e3983eb064 100644
--- a/include/config.h
+++ b/include/config.h
@@ -1157,18 +1157,18 @@
/* Include all USB Power Delivery modules */
#undef CONFIG_USB_POWER_DELIVERY
-/* Alternative configuration keeping only the TX part of PHY */
-#undef CONFIG_USB_PD_TX_PHY_ONLY
-
-/* Default state of PD communication enabled flag */
-#define CONFIG_USB_PD_COMM_ENABLED 1
-
/* Support for USB PD alternate mode */
#undef CONFIG_USB_PD_ALT_MODE
/* Support for USB PD alternate mode of Downward Facing Port */
#undef CONFIG_USB_PD_ALT_MODE_DFP
+/* Check if max voltage request is allowed before each request */
+#undef CONIFG_USB_PD_CHECK_MAX_REQUEST_ALLOWED
+
+/* Default state of PD communication enabled flag */
+#define CONFIG_USB_PD_COMM_ENABLED 1
+
/* Respond to custom vendor-defined messages over PD */
#undef CONFIG_USB_PD_CUSTOM_VDM
@@ -1206,6 +1206,9 @@
/* Use comparator module for PD RX interrupt */
#define CONFIG_USB_PD_RX_COMP_IRQ
+/* Alternative configuration keeping only the TX part of PHY */
+#undef CONFIG_USB_PD_TX_PHY_ONLY
+
/* Support for USB type-c superspeed mux */
#undef CONFIG_USBC_SS_MUX
diff --git a/include/ec_commands.h b/include/ec_commands.h
index f42e525c4a..304cb9acda 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -2680,9 +2680,17 @@ struct ec_params_reboot_ec {
/* EC to PD MCU exchange status command */
#define EC_CMD_PD_EXCHANGE_STATUS 0x100
+enum pd_charge_state {
+ PD_CHARGE_NO_CHANGE = 0, /* Don't change charge state */
+ PD_CHARGE_NONE, /* No charging allowed */
+ PD_CHARGE_5V, /* 5V charging only */
+ PD_CHARGE_MAX /* Charge at max voltage */
+};
+
/* Status of EC being sent to PD */
struct ec_params_pd_status {
- int8_t batt_soc; /* battery state of charge */
+ int8_t batt_soc; /* battery state of charge */
+ uint8_t charge_state; /* charging state (from enum pd_charge_state) */
} __packed;
/* Status of PD being sent back to EC */
diff --git a/include/host_command.h b/include/host_command.h
index e833b96101..4661e59dd6 100644
--- a/include/host_command.h
+++ b/include/host_command.h
@@ -210,8 +210,10 @@ void host_throttle_cpu(int throttle);
/**
* Signal host command task to send status to PD MCU.
+ *
+ * @new_chg_state PD MCU charge state
*/
-void host_command_pd_send_status(void);
+void host_command_pd_send_status(enum pd_charge_state new_chg_state);
/**
* Ask the PD MCU for its status, obtaining the current charge_port as a
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 543b939682..410251775f 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -759,6 +759,14 @@ int pd_build_request(int cnt, uint32_t *src_caps, uint32_t *rdo,
uint32_t *ma, uint32_t *mv, enum pd_request_type req_type);
/**
+ * Check if max voltage request is allowed (only used if
+ * CONFIG_USB_PD_CHECK_MAX_REQUEST_ALLOWED is defined).
+ *
+ * @return True if max voltage request allowed, False otherwise
+ */
+int pd_is_max_request_allowed(void);
+
+/**
* Process source capabilities packet
*
* @param port USB-C port number