diff --git a/core/embed/projects/prodtest/main.c b/core/embed/projects/prodtest/main.c index 93b9bc9fae..0434339267 100644 --- a/core/embed/projects/prodtest/main.c +++ b/core/embed/projects/prodtest/main.c @@ -194,7 +194,7 @@ static void drivers_init(void) { #endif #ifdef USE_POWER_MANAGER pm_init(true); - pm_turn_on(); + pm_set_soc_limit(70); #endif display_init(DISPLAY_RESET_CONTENT); diff --git a/core/embed/sys/power_manager/inc/sys/power_manager.h b/core/embed/sys/power_manager/inc/sys/power_manager.h index 483788d776..69d0f6375f 100644 --- a/core/embed/sys/power_manager/inc/sys/power_manager.h +++ b/core/embed/sys/power_manager/inc/sys/power_manager.h @@ -114,3 +114,4 @@ pm_status_t pm_store_data_to_backup_ram(); pm_status_t pm_wakeup_flags_set(pm_wakeup_flags_t flags); pm_status_t pm_wakeup_flags_reset(void); pm_status_t pm_wakeup_flags_get(pm_wakeup_flags_t* flags); +pm_status_t pm_set_soc_limit(uint8_t limit); diff --git a/core/embed/sys/power_manager/stm32u5/power_manager.c b/core/embed/sys/power_manager/stm32u5/power_manager.c index a17feca25c..be631fd556 100644 --- a/core/embed/sys/power_manager/stm32u5/power_manager.c +++ b/core/embed/sys/power_manager/stm32u5/power_manager.c @@ -117,6 +117,9 @@ pm_status_t pm_init(bool inherit_state) { drv->charging_enabled = true; pm_charging_set_max_current(PM_BATTERY_CHARGING_CURRENT_MAX); + // Set default SOC limit + drv->soc_limit = 100; + // Poll until fuel_gauge is initialized and first PMIC & WLC measurements // propagates into power_monitor. bool state_machine_stabilized; @@ -407,6 +410,25 @@ pm_status_t pm_wakeup_flags_get(pm_wakeup_flags_t* flags) { return PM_OK; } +pm_status_t pm_set_soc_limit(uint8_t limit) { + pm_driver_t* drv = &g_pm; + + if (!drv->initialized) { + return PM_NOT_INITIALIZED; + } + + if (limit > 100) { + return PM_ERROR; + } + + if (limit <= PM_SOC_LIMIT_HYSTERESIS) { + return PM_ERROR; + } + + drv->soc_limit = limit; + return PM_OK; +} + // Timer handlers static void pm_monitoring_timer_handler(void* context) { pm_monitor_power_sources(); 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 e0042d97e4..cdb427f65c 100644 --- a/core/embed/sys/power_manager/stm32u5/power_manager_internal.h +++ b/core/embed/sys/power_manager/stm32u5/power_manager_internal.h @@ -35,6 +35,7 @@ #define PM_BATTERY_UNDERVOLT_RECOVERY_THR_V 3.1f #define PM_BATTERY_UNDERVOLT_RECOVERY_WPC_THR_V 3.2f #define PM_BATTERY_LOW_THRESHOLD_SOC 15 +#define PM_SOC_LIMIT_HYSTERESIS 5 #define PM_BATTERY_CHARGING_CURRENT_MAX PMIC_CHARGING_LIMIT_MAX #define PM_BATTERY_CHARGING_CURRENT_MIN PMIC_CHARGING_LIMIT_MIN #define PM_BATTERY_SAMPLING_BUF_SIZE 10 @@ -67,6 +68,8 @@ typedef struct { uint8_t bat_sampling_buf_tail_idx; uint8_t bat_sampling_buf_head_idx; uint8_t soc_ceiled; + uint8_t soc_limit; + bool soc_limit_reached; // Battery charging state bool charging_enabled; diff --git a/core/embed/sys/power_manager/stm32u5/power_monitoring.c b/core/embed/sys/power_manager/stm32u5/power_monitoring.c index 01314ccfba..3b1ee97457 100644 --- a/core/embed/sys/power_manager/stm32u5/power_monitoring.c +++ b/core/embed/sys/power_manager/stm32u5/power_monitoring.c @@ -188,6 +188,17 @@ void pm_charging_controller(pm_driver_t* drv) { pmic_set_charging_limit(drv->charging_current_target_ma); } + if (drv->soc_ceiled >= drv->soc_limit) { + drv->soc_limit_reached = true; + } else if (drv->soc_ceiled < drv->soc_limit - PM_SOC_LIMIT_HYSTERESIS) { + drv->soc_limit_reached = false; + } + + if (drv->soc_limit_reached) { + // Set charging current limit to 0 + drv->charging_current_target_ma = 0; + } + if (drv->charging_current_target_ma == 0) { pmic_set_charging(false); } else {