feat(core): remove suspended charging mode from power manager.
What changed, and why it matters
This commit removes a special 'suspended charging' mode from the Trezor hardware wallet's power manager. Previously, if the device was suspended while plugged into USB or wireless power, it would wake up periodically to update the battery fuel gauge using actual charging current. Now it always uses a fixed self-discharge estimate instead. This is a feature simplification, not a clear security fix. It could make the displayed battery percentage slightly less accurate when charging while suspended, but there is no direct evidence it creates a security vulnerability.
Treat as a normal firmware change, not an urgent security patch. If battery-state accuracy during suspended charging is security-relevant for your use case (for example, low-battery warnings or secure-shutdown thresholds), review whether the simplified self-discharge estimate still meets product requirements. No immediate user action is indicated by the commit itself.
Security signals we found
Behavioral change in power-state machine: removed a charging-aware wakeup path
Fuel-gauge compensation now uses a fixed estimate rather than measured charging current after suspend
No bounds checks, memory safety, cryptographic, or authentication changes visible
No vendor statement that this is a security fix
Evidence from the diff
The patch deletes the suspended_charging boolean and the branch in pm_schedule_rtc_wakeup() that set a short RTC wakeup timeout (PM_SUSPENDED_CHARGING_TIMEOUT_S) when usb_connected or wireless_connected was true during suspend. It also removes the corresponding branch in pm_pmic_data_ready() that compensated the fuel gauge with measured ibat and ntc_temp after a suspended-charging wakeup. After the change, suspend always schedules the longer hibernation countdown and always uses a fixed self-discharge rate (PM_SELF_DISG_RATE_SUSPEND_MA at 25 °C) for fuel-gauge compensation. The commit message frames this as a feature removal (‘remove suspended charging mode’) and explicitly marks ‘[no changelog]’.
Changed components
core/embed/sys/power_manager/stm32u5/power_manager.ccore/embed/sys/power_manager/stm32u5/power_manager_internal.hcore/embed/sys/power_manager/stm32u5/power_monitoring.cInspect captured patch +23 / −44
diff --git a/core/embed/sys/power_manager/stm32u5/power_manager.c b/core/embed/sys/power_manager/stm32u5/power_manager.c
index 4176dcfb7..9557fac24 100644
--- a/core/embed/sys/power_manager/stm32u5/power_manager.c
+++ b/core/embed/sys/power_manager/stm32u5/power_manager.c
@@ -595,30 +595,18 @@ bool pm_schedule_rtc_wakeup(void) {
return false;
}
- if (drv->usb_connected || drv->wireless_connected) {
- drv->suspended_charging = true;
-
- // External power source is connected, wake up early to update the fuel
- // gauge
- rtc_wakeup_timer_start(PM_SUSPENDED_CHARGING_TIMEOUT_S,
- pm_rtc_wakeup_callback, NULL);
-
- } else {
- if ((drv->last_active_timestamp - drv->suspend_timestamp) >=
- PM_AUTO_HIBERNATE_TIMEOUT_S) {
- // Device is very long time in suspend mode without external power source,
- // hibernate it to save power.
- pm_hibernate();
- }
-
- uint32_t time_to_hibernate =
- PM_AUTO_HIBERNATE_TIMEOUT_S -
- (drv->last_active_timestamp - drv->suspend_timestamp);
+ if ((drv->last_active_timestamp - drv->suspend_timestamp) >=
+ PM_AUTO_HIBERNATE_TIMEOUT_S) {
+ // Device is very long time in suspend mode without external power source,
+ // hibernate it to save power.
+ pm_hibernate();
+ }
- drv->suspended_charging = false;
+ uint32_t time_to_hibernate =
+ PM_AUTO_HIBERNATE_TIMEOUT_S -
+ (drv->last_active_timestamp - drv->suspend_timestamp);
- rtc_wakeup_timer_start(time_to_hibernate, pm_rtc_wakeup_callback, NULL);
- }
+ rtc_wakeup_timer_start(time_to_hibernate, pm_rtc_wakeup_callback, NULL);
#endif
diff --git a/core/embed/sys/power_manager/stm32u5/power_manager_internal.h b/core/embed/sys/power_manager/stm32u5/power_manager_internal.h
index c3057f19c..9992d0046 100644
--- a/core/embed/sys/power_manager/stm32u5/power_manager_internal.h
+++ b/core/embed/sys/power_manager/stm32u5/power_manager_internal.h
@@ -112,7 +112,6 @@ typedef struct {
uint32_t pmic_sampling_period_ms;
bool pmic_measurement_ready;
bool woke_up_from_suspend;
- bool suspended_charging;
// Power source logical state
bool usb_connected;
diff --git a/core/embed/sys/power_manager/stm32u5/power_monitoring.c b/core/embed/sys/power_manager/stm32u5/power_monitoring.c
index 2c3bfb176..9d08c83ce 100644
--- a/core/embed/sys/power_manager/stm32u5/power_monitoring.c
+++ b/core/embed/sys/power_manager/stm32u5/power_monitoring.c
@@ -86,27 +86,19 @@ void pm_pmic_data_ready(void* context, pmic_report_t* report) {
} else {
if (drv->woke_up_from_suspend) {
- // Just woke up from suspend, use the last known battery data to
- // update the fuel gauge.
- if (drv->suspended_charging) {
- pm_compensate_fuel_gauge(&drv->fuel_gauge.soc, drv->time_in_suspend_s,
- drv->pmic_data.ibat, drv->pmic_data.ntc_temp);
-
- } else {
- // Use known battery self-discharge rate to compensate the fuel gauge
- // estimation during the suspend period. Since this period may be very
- // long and the battery temperature may vary, use the average ambient
- // temperature.
- pm_compensate_fuel_gauge(&drv->fuel_gauge.soc, drv->time_in_suspend_s,
- PM_SELF_DISG_RATE_SUSPEND_MA, 25.0f);
-
- // TODO: Currently in suspend mode we use single self-discharge rate
- // but in practive the discharge rate may change in case the BLE chip
- // remains active. Since the device is very likely to stay in suspend
- // mode for limited time, for now we decided to neglect this. but in
- // the future we may want to distinguish between suspend mode
- // with/without BLE and use different self-discharge rates.
- }
+ // Use known battery self-discharge rate to compensate the fuel gauge
+ // estimation during the suspend period. Since this period may be very
+ // long and the battery temperature may vary, use the average ambient
+ // temperature.
+ pm_compensate_fuel_gauge(&drv->fuel_gauge.soc, drv->time_in_suspend_s,
+ PM_SELF_DISG_RATE_SUSPEND_MA, 25.0f);
+
+ // TODO: Currently in suspend mode we use single self-discharge rate
+ // but in practive the discharge rate may change in case the BLE chip
+ // remains active. Since the device is very likely to stay in suspend
+ // mode for limited time, for now we decided to neglect this. but in
+ // the future we may want to distinguish between suspend mode
+ // with/without BLE and use different self-discharge rates.
fuel_gauge_set_soc(&drv->fuel_gauge, drv->fuel_gauge.soc,
drv->fuel_gauge.P);
Why this scored 21/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.