summaryrefslogtreecommitdiff
path: root/common/usb_pd_protocol.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/usb_pd_protocol.c')
-rw-r--r--common/usb_pd_protocol.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index e9525cb547..aba957c77f 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -36,6 +36,14 @@
BUILD_ASSERT(CONFIG_USB_PD_PORT_COUNT <= EC_USB_PD_MAX_PORTS);
/*
+ * If we are trying to upgrade the TCPC port that is supplying power, then we
+ * need to ensure that the battery has enough charge for the upgrade. 100mAh
+ * is about 5% of most batteries, and it should be enough charge to get us
+ * through the EC jump to RW and PD upgrade.
+ */
+#define MIN_BATTERY_FOR_TCPC_UPGRADE_MAH 100 /* mAH */
+
+/*
* Debug log level - higher number == more log
* Level 0: Log state transitions
* Level 1: Level 0, plus state name
@@ -4455,6 +4463,40 @@ static int pd_control(struct host_cmd_handler_args *args)
return EC_RES_ACCESS_DENIED;
if (cmd->subcmd == PD_SUSPEND) {
+ /*
+ * The AP is requesting to suspend PD traffic on the EC so it
+ * can perform a firmware upgrade. If Vbus is present on the
+ * connector (it is either a source or sink), then we will
+ * prevent the upgrade if there is not enough battery to finish
+ * the upgrade. We cannot rely on the EC's active charger data
+ * as the EC just rebooted into RW and has not necessarily
+ * picked the active charger yet.
+ */
+#ifdef HAS_TASK_CHARGER
+ if (pd_is_vbus_present(cmd->chip)) {
+ struct batt_params batt = { 0 };
+ /*
+ * The charger task has not re-initialized, so we need
+ * to ask the battery directly.
+ */
+ battery_get_params(&batt);
+ if (batt.remaining_capacity <
+ MIN_BATTERY_FOR_TCPC_UPGRADE_MAH ||
+ batt.flags & BATT_FLAG_BAD_REMAINING_CAPACITY) {
+ CPRINTS("C%d: Cannot suspend for upgrade, not "
+ "enough battery (%dmAh)!",
+ cmd->chip, batt.remaining_capacity);
+ return EC_RES_BUSY;
+ }
+ }
+#else
+ if (pd_is_vbus_present(cmd->chip)) {
+ CPRINTS("C%d: Cannot suspend for upgrade, Vbus "
+ "present!",
+ cmd->chip);
+ return EC_RES_BUSY;
+ }
+#endif
enable = 0;
} else if (cmd->subcmd == PD_RESUME) {
enable = 1;