mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-26 00:18:15 +00:00
feat(core): manage background ops during suspend
[no changelog]
This commit is contained in:
parent
995caca9c7
commit
bec455c9e5
@ -59,6 +59,19 @@ bool pmic_init(void);
|
|||||||
// Deinitializes PMIC driver
|
// Deinitializes PMIC driver
|
||||||
void pmic_deinit(void);
|
void pmic_deinit(void);
|
||||||
|
|
||||||
|
// Suspends driver activity so the CPU can enter low-power mode.
|
||||||
|
//
|
||||||
|
// Suspending may take some time if the driver is currently
|
||||||
|
// performing an operation. Caller may check the status by
|
||||||
|
// pmic_is_suspended().
|
||||||
|
bool pmic_suspend(void);
|
||||||
|
|
||||||
|
// Resumes the driver operation after it has been suspended.
|
||||||
|
bool pmic_resume(void);
|
||||||
|
|
||||||
|
// Checks whether the driver is suspended.
|
||||||
|
bool pmic_is_suspended(void);
|
||||||
|
|
||||||
// Gets the cause of the last restart
|
// Gets the cause of the last restart
|
||||||
uint8_t pmic_restart_cause(void);
|
uint8_t pmic_restart_cause(void);
|
||||||
|
|
||||||
|
@ -107,6 +107,15 @@ typedef struct {
|
|||||||
// Current state of the FSM
|
// Current state of the FSM
|
||||||
npm1300_fsm_state_t state;
|
npm1300_fsm_state_t state;
|
||||||
|
|
||||||
|
// Set if the driver was requested to suspend background operations.
|
||||||
|
// IF so, the driver waits until the last operation is finished,
|
||||||
|
// then enters suspended mode.
|
||||||
|
bool suspending;
|
||||||
|
|
||||||
|
// Set if the driver's background operations are suspended.
|
||||||
|
// In suspended mode, the driver does not start any new operations.
|
||||||
|
bool suspended;
|
||||||
|
|
||||||
// ADC register (global buffer used for ADC measurements)
|
// ADC register (global buffer used for ADC measurements)
|
||||||
npm1300_adc_regs_t adc_regs;
|
npm1300_adc_regs_t adc_regs;
|
||||||
// Charging limit registers (global buffer used for charging limit)
|
// Charging limit registers (global buffer used for charging limit)
|
||||||
@ -418,6 +427,53 @@ void pmic_deinit(void) {
|
|||||||
memset(drv, 0, sizeof(npm1300_driver_t));
|
memset(drv, 0, sizeof(npm1300_driver_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool pmic_suspend(void) {
|
||||||
|
npm1300_driver_t* drv = &g_npm1300_driver;
|
||||||
|
|
||||||
|
if (!drv->initialized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_key_t irq_key = irq_lock();
|
||||||
|
drv->suspending = true;
|
||||||
|
npm1300_fsm_continue(drv);
|
||||||
|
irq_unlock(irq_key);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pmic_resume(void) {
|
||||||
|
npm1300_driver_t* drv = &g_npm1300_driver;
|
||||||
|
|
||||||
|
if (!drv->initialized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_key_t irq_key = irq_lock();
|
||||||
|
drv->suspending = false;
|
||||||
|
drv->suspended = false;
|
||||||
|
npm1300_fsm_continue(drv);
|
||||||
|
irq_unlock(irq_key);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pmic_is_suspended(void) {
|
||||||
|
npm1300_driver_t* drv = &g_npm1300_driver;
|
||||||
|
|
||||||
|
if (!drv->initialized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_suspended;
|
||||||
|
|
||||||
|
irq_key_t irq_key = irq_lock();
|
||||||
|
is_suspended = drv->suspended;
|
||||||
|
irq_unlock(irq_key);
|
||||||
|
|
||||||
|
return is_suspended;
|
||||||
|
}
|
||||||
|
|
||||||
bool pmic_enter_shipmode(void) {
|
bool pmic_enter_shipmode(void) {
|
||||||
npm1300_driver_t* drv = &g_npm1300_driver;
|
npm1300_driver_t* drv = &g_npm1300_driver;
|
||||||
|
|
||||||
@ -830,6 +886,9 @@ static void npm1300_i2c_callback(void* context, i2c_packet_t* packet) {
|
|||||||
case NPM1300_STATE_CLEAR_EVENTS:
|
case NPM1300_STATE_CLEAR_EVENTS:
|
||||||
drv->clear_events_requested = false;
|
drv->clear_events_requested = false;
|
||||||
drv->state = NPM1300_STATE_IDLE;
|
drv->state = NPM1300_STATE_IDLE;
|
||||||
|
#ifdef USE_SUSPEND
|
||||||
|
wakeup_flags_set(WAKEUP_FLAG_POWER);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NPM1300_STATE_CHARGING_ENABLE:
|
case NPM1300_STATE_CHARGING_ENABLE:
|
||||||
@ -903,10 +962,6 @@ void NPM1300_EXTI_INTERRUPT_HANDLER(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_SUSPEND
|
|
||||||
wakeup_flags_set(WAKEUP_FLAG_POWER);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
drv->clear_events_requested = true;
|
drv->clear_events_requested = true;
|
||||||
npm1300_fsm_continue(drv);
|
npm1300_fsm_continue(drv);
|
||||||
}
|
}
|
||||||
@ -915,7 +970,7 @@ void NPM1300_EXTI_INTERRUPT_HANDLER(void) {
|
|||||||
//
|
//
|
||||||
// This function is called in the irq context or when interrupts are disabled.
|
// This function is called in the irq context or when interrupts are disabled.
|
||||||
static void npm1300_fsm_continue(npm1300_driver_t* drv) {
|
static void npm1300_fsm_continue(npm1300_driver_t* drv) {
|
||||||
if (drv->state != NPM1300_STATE_IDLE) {
|
if (drv->state != NPM1300_STATE_IDLE || drv->suspended) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -971,6 +1026,16 @@ static void npm1300_fsm_continue(npm1300_driver_t* drv) {
|
|||||||
drv->shipmode_requested = false;
|
drv->shipmode_requested = false;
|
||||||
drv->state = NPM1300_STATE_ENTER_SHIPMODE;
|
drv->state = NPM1300_STATE_ENTER_SHIPMODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// After processing all requests, check if we need to
|
||||||
|
// suspend the driver
|
||||||
|
if (drv->state == NPM1300_STATE_IDLE) {
|
||||||
|
// No more requests to process
|
||||||
|
if (drv->suspending) {
|
||||||
|
drv->suspending = false;
|
||||||
|
drv->suspended = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // KERNEL_MODE
|
#endif // KERNEL_MODE
|
||||||
|
@ -215,15 +215,19 @@ pm_status_t pm_get_state(pm_state_t* state) {
|
|||||||
// - The callback can schedule the next wake-up by calling
|
// - The callback can schedule the next wake-up by calling
|
||||||
// rtc_wakeup_timer_start().
|
// rtc_wakeup_timer_start().
|
||||||
// - If the callback return with wakeup_flags set, system_suspend() returns.
|
// - If the callback return with wakeup_flags set, system_suspend() returns.
|
||||||
|
#ifdef USE_RTC
|
||||||
void pm_rtc_wakeup_callback(void* context) {
|
void pm_rtc_wakeup_callback(void* context) {
|
||||||
// TODO: update fuel gauge state
|
// TODO: update fuel gauge state
|
||||||
|
// TODO: decide whether to reschedule the next wake-up or wake up the coreapp
|
||||||
if (true) {
|
if (true) {
|
||||||
rtc_wakeup_timer_start(0, pm_rtc_wakeup_callback, NULL);
|
// Reschedule the next wake-up
|
||||||
|
rtc_wakeup_timer_start(10, pm_rtc_wakeup_callback, NULL);
|
||||||
} else {
|
} else {
|
||||||
|
// Wake up the coreapp
|
||||||
wakeup_flags_set(WAKEUP_FLAG_RTC);
|
wakeup_flags_set(WAKEUP_FLAG_RTC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
pm_status_t pm_suspend(wakeup_flags_t* wakeup_reason) {
|
pm_status_t pm_suspend(wakeup_flags_t* wakeup_reason) {
|
||||||
pm_driver_t* drv = &g_pm;
|
pm_driver_t* drv = &g_pm;
|
||||||
@ -256,7 +260,9 @@ pm_status_t pm_suspend(wakeup_flags_t* wakeup_reason) {
|
|||||||
|
|
||||||
wakeup_flags_t wakeup_flags = system_suspend();
|
wakeup_flags_t wakeup_flags = system_suspend();
|
||||||
|
|
||||||
|
#ifdef USE_RTC
|
||||||
rtc_wakeup_timer_stop();
|
rtc_wakeup_timer_stop();
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO: Handle wake-up flags
|
// TODO: Handle wake-up flags
|
||||||
// UNUSED(wakeup_flags);
|
// UNUSED(wakeup_flags);
|
||||||
|
@ -156,6 +156,53 @@ cleanup:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool stwlc38_suspend(void) {
|
||||||
|
stwlc38_driver_t *drv = &g_stwlc38_driver;
|
||||||
|
|
||||||
|
if (!drv->initialized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_key_t irq_key = irq_lock();
|
||||||
|
drv->suspending = true;
|
||||||
|
stwlc38_fsm_continue(drv);
|
||||||
|
irq_unlock(irq_key);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool stwlc38_resume(void) {
|
||||||
|
stwlc38_driver_t *drv = &g_stwlc38_driver;
|
||||||
|
|
||||||
|
if (!drv->initialized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_key_t irq_key = irq_lock();
|
||||||
|
drv->suspending = false;
|
||||||
|
drv->suspended = false;
|
||||||
|
stwlc38_fsm_continue(drv);
|
||||||
|
irq_unlock(irq_key);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool stwlc38_is_suspended(void) {
|
||||||
|
stwlc38_driver_t *drv = &g_stwlc38_driver;
|
||||||
|
|
||||||
|
if (!drv->initialized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_suspended;
|
||||||
|
|
||||||
|
irq_key_t irq_key = irq_lock();
|
||||||
|
is_suspended = drv->suspended;
|
||||||
|
irq_unlock(irq_key);
|
||||||
|
|
||||||
|
return is_suspended;
|
||||||
|
}
|
||||||
|
|
||||||
bool stwlc38_enable(bool enable) {
|
bool stwlc38_enable(bool enable) {
|
||||||
stwlc38_driver_t *drv = &g_stwlc38_driver;
|
stwlc38_driver_t *drv = &g_stwlc38_driver;
|
||||||
|
|
||||||
@ -329,8 +376,6 @@ void STWLC38_EXTI_INTERRUPT_HANDLER(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (drv->state == STWLC38_STATE_POWER_DOWN) {
|
if (drv->state == STWLC38_STATE_POWER_DOWN) {
|
||||||
// Inform the powerctl module about the WPC
|
|
||||||
// wakeup_flags_set(WAKEUP_FLAGS_WPC);
|
|
||||||
drv->report_readout_requested = true;
|
drv->report_readout_requested = true;
|
||||||
stwlc38_fsm_continue(drv);
|
stwlc38_fsm_continue(drv);
|
||||||
}
|
}
|
||||||
@ -339,30 +384,42 @@ void STWLC38_EXTI_INTERRUPT_HANDLER(void) {
|
|||||||
static void stwlc38_fsm_continue(stwlc38_driver_t *drv) {
|
static void stwlc38_fsm_continue(stwlc38_driver_t *drv) {
|
||||||
// The order of the following conditions defines the priority
|
// The order of the following conditions defines the priority
|
||||||
|
|
||||||
if (drv->state == STWLC38_STATE_POWER_DOWN && drv->report_readout_requested) {
|
if (drv->suspended) {
|
||||||
// Check if the i2c interface is ready
|
|
||||||
stwlc38_i2c_submit(drv, stwlc38_ops_report_readout);
|
|
||||||
drv->state = STWLC38_STATE_REPORT_READOUT;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drv->state != STWLC38_STATE_IDLE) {
|
if (drv->state == STWLC38_STATE_POWER_DOWN) {
|
||||||
return;
|
if (drv->report_readout_requested) {
|
||||||
}
|
// Check if the i2c interface is ready
|
||||||
|
stwlc38_i2c_submit(drv, stwlc38_ops_report_readout);
|
||||||
if (drv->vout_enabled != drv->vout_enabled_requested) {
|
drv->state = STWLC38_STATE_REPORT_READOUT;
|
||||||
// Enable/Disable the main LDO output
|
}
|
||||||
if (drv->vout_enabled_requested) {
|
} else if (drv->state == STWLC38_STATE_IDLE) {
|
||||||
stwlc38_i2c_submit(drv, stwlc38_ops_vout_enable);
|
if (drv->vout_enabled != drv->vout_enabled_requested) {
|
||||||
drv->state = STWLC38_STATE_VOUT_ENABLE;
|
// Enable/Disable the main LDO output
|
||||||
} else {
|
if (drv->vout_enabled_requested) {
|
||||||
stwlc38_i2c_submit(drv, stwlc38_ops_vout_disable);
|
stwlc38_i2c_submit(drv, stwlc38_ops_vout_enable);
|
||||||
drv->state = STWLC38_STATE_VOUT_DISABLE;
|
drv->state = STWLC38_STATE_VOUT_ENABLE;
|
||||||
|
} else {
|
||||||
|
stwlc38_i2c_submit(drv, stwlc38_ops_vout_disable);
|
||||||
|
drv->state = STWLC38_STATE_VOUT_DISABLE;
|
||||||
|
}
|
||||||
|
} else if (drv->report_readout_requested) {
|
||||||
|
// Read status registers
|
||||||
|
stwlc38_i2c_submit(drv, stwlc38_ops_report_readout);
|
||||||
|
drv->state = STWLC38_STATE_REPORT_READOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// After processing all requests, check if we need to
|
||||||
|
// suspend the driver
|
||||||
|
if (drv->state == STWLC38_STATE_IDLE ||
|
||||||
|
drv->state == STWLC38_STATE_POWER_DOWN) {
|
||||||
|
// No more requests to process
|
||||||
|
if (drv->suspending) {
|
||||||
|
drv->suspending = false;
|
||||||
|
drv->suspended = true;
|
||||||
}
|
}
|
||||||
} else if (drv->report_readout_requested) {
|
|
||||||
// Read status registers
|
|
||||||
stwlc38_i2c_submit(drv, stwlc38_ops_report_readout);
|
|
||||||
drv->state = STWLC38_STATE_REPORT_READOUT;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +90,19 @@ bool stwlc38_init(void);
|
|||||||
// Deinitializes STWLC38 driver
|
// Deinitializes STWLC38 driver
|
||||||
void stwlc38_deinit(void);
|
void stwlc38_deinit(void);
|
||||||
|
|
||||||
|
// Suspends driver activity so the CPU can enter low-power mode.
|
||||||
|
//
|
||||||
|
// Suspending may take some time if the driver is currently
|
||||||
|
// performing an operation. Caller may check the status by
|
||||||
|
// stwlc38_is_suspended().
|
||||||
|
bool stwlc38_suspend(void);
|
||||||
|
|
||||||
|
// Resumes the driver operation after it has been suspended.
|
||||||
|
bool stwlc38_resume(void);
|
||||||
|
|
||||||
|
// Checks whether the driver is suspended.
|
||||||
|
bool stwlc38_is_suspended(void);
|
||||||
|
|
||||||
// Enables or disables the STWLC38. This can be used to enable/disable
|
// Enables or disables the STWLC38. This can be used to enable/disable
|
||||||
// wireless charging functionality.
|
// wireless charging functionality.
|
||||||
//
|
//
|
||||||
|
@ -72,6 +72,15 @@ typedef struct {
|
|||||||
// Timer used for periodic report readout
|
// Timer used for periodic report readout
|
||||||
systimer_t *timer;
|
systimer_t *timer;
|
||||||
|
|
||||||
|
// Set if the driver was requested to suspend background operations.
|
||||||
|
// IF so, the driver waits until the last operation is finished,
|
||||||
|
// then enters suspended mode.
|
||||||
|
bool suspending;
|
||||||
|
|
||||||
|
// Set if the driver's background operations are suspended.
|
||||||
|
// In suspended mode, the driver does not start any new operations.
|
||||||
|
bool suspended;
|
||||||
|
|
||||||
// Main LDO output current state
|
// Main LDO output current state
|
||||||
bool vout_enabled;
|
bool vout_enabled;
|
||||||
// Main LDO output requested state
|
// Main LDO output requested state
|
||||||
|
@ -25,6 +25,9 @@
|
|||||||
#include <sys/suspend.h>
|
#include <sys/suspend.h>
|
||||||
#include <sys/suspend_io.h>
|
#include <sys/suspend_io.h>
|
||||||
|
|
||||||
|
#include <../../power_manager/stwlc38/stwlc38.h>
|
||||||
|
#include <sys/pmic.h>
|
||||||
|
|
||||||
static wakeup_flags_t g_wakeup_flags = 0;
|
static wakeup_flags_t g_wakeup_flags = 0;
|
||||||
|
|
||||||
static void background_tasks_suspend(void);
|
static void background_tasks_suspend(void);
|
||||||
@ -106,10 +109,18 @@ wakeup_flags_t system_suspend(void) {
|
|||||||
return wakeup_flags;
|
return wakeup_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void background_tasks_suspend(void) {}
|
static void background_tasks_suspend(void) {
|
||||||
|
pmic_suspend();
|
||||||
|
stwlc38_suspend();
|
||||||
|
}
|
||||||
|
|
||||||
static bool background_tasks_suspended(void) { return true; }
|
static bool background_tasks_suspended(void) {
|
||||||
|
return pmic_is_suspended() && stwlc38_is_suspended();
|
||||||
|
}
|
||||||
|
|
||||||
static void background_tasks_resume(void) {}
|
static void background_tasks_resume(void) {
|
||||||
|
stwlc38_resume();
|
||||||
|
pmic_resume();
|
||||||
|
}
|
||||||
|
|
||||||
#endif // defined(KERNEL_MODE) && !defined(SECMON)
|
#endif // defined(KERNEL_MODE) && !defined(SECMON)
|
||||||
|
Loading…
Reference in New Issue
Block a user