arcv2_timer0: Add suspend and resume support
When going into DEEP_SLEEP state, the ARC timer needs to be restored. This implements the function to restore the timer after sleep. As the time spent during sleep is not currently known, the timer is expired to reschedule the application task. Jira: ZEP-1224 Change-Id: I22a30d0fd79f177cf166b9a29dc78d68f7d7fbad Signed-off-by: Julien Delayen <julien.delayen@intel.com>
This commit is contained in:
parent
cd8504cc9c
commit
d127864366
2 changed files with 72 additions and 2 deletions
|
@ -86,6 +86,12 @@ static bool straddled_tick_on_idle_enter = false;
|
|||
extern int32_t _sys_idle_elapsed_ticks;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
|
||||
static uint32_t arcv2_timer0_device_power_state;
|
||||
static uint32_t saved_limit;
|
||||
static uint32_t saved_control;
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Get contents of Timer0 count register
|
||||
|
@ -130,6 +136,17 @@ static ALWAYS_INLINE void timer0_control_register_set(uint32_t value)
|
|||
_arc_v2_aux_reg_write(_ARC_V2_TMR0_CONTROL, value);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Get contents of Timer0 limit register
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
static ALWAYS_INLINE uint32_t timer0_limit_register_get(void)
|
||||
{
|
||||
return _arc_v2_aux_reg_read(_ARC_V2_TMR0_LIMIT);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Set Timer0 limit register to the specified value
|
||||
|
@ -353,6 +370,59 @@ int _sys_clock_driver_init(struct device *device)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
|
||||
static int sys_clock_suspend(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
saved_limit = timer0_limit_register_get();
|
||||
saved_control = timer0_control_register_get();
|
||||
|
||||
arcv2_timer0_device_power_state = DEVICE_PM_SUSPEND_STATE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sys_clock_resume(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
timer0_limit_register_set(saved_limit);
|
||||
timer0_control_register_set(saved_control);
|
||||
|
||||
/*
|
||||
* It is difficult to accurately know the time spent in DS.
|
||||
* Expire the timer to get the scheduler called.
|
||||
*/
|
||||
timer0_count_register_set(saved_limit - 1);
|
||||
|
||||
arcv2_timer0_device_power_state = DEVICE_PM_ACTIVE_STATE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implements the driver control management functionality
|
||||
* the *context may include IN data or/and OUT data
|
||||
*/
|
||||
int sys_clock_device_ctrl(struct device *port, uint32_t ctrl_command,
|
||||
void *context)
|
||||
{
|
||||
if (ctrl_command == DEVICE_PM_SET_POWER_STATE) {
|
||||
if (*((uint32_t *)context) == DEVICE_PM_SUSPEND_STATE) {
|
||||
return sys_clock_suspend(port);
|
||||
} else if (*((uint32_t *)context) == DEVICE_PM_ACTIVE_STATE) {
|
||||
return sys_clock_resume(port);
|
||||
}
|
||||
} else if (ctrl_command == DEVICE_PM_GET_POWER_STATE) {
|
||||
*((uint32_t *)context) = arcv2_timer0_device_power_state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DEVICE_POWER_MANAGEMENT */
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Read the platform's timer hardware
|
||||
|
|
|
@ -61,11 +61,11 @@ extern int sys_clock_device_ctrl(struct device *device,
|
|||
uint32_t ctrl_command, void *context);
|
||||
|
||||
/*
|
||||
* Currently regarding timers, only loapic timer implements
|
||||
* Currently regarding timers, only loapic timer and arcv2_timer0 implements
|
||||
* device pm functionality. For other timers, use default handler in case
|
||||
* the app enables CONFIG_DEVICE_POWER_MANAGEMENT.
|
||||
*/
|
||||
#ifndef CONFIG_LOAPIC_TIMER
|
||||
#if !defined(CONFIG_LOAPIC_TIMER) && !defined(CONFIG_ARCV2_TIMER)
|
||||
#define sys_clock_device_ctrl device_pm_control_nop
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue