[compoents][pm]The device is registered and uninstalled by linked list

This commit is contained in:
wdfk-prog 2024-07-11 15:57:51 +08:00 committed by Rbb666
parent 8d3ad68caf
commit bceb6635b0
2 changed files with 178 additions and 149 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006-2023, RT-Thread Development Team * Copyright (c) 2006-2024 RT-Thread Development Team
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
@ -10,6 +10,7 @@
* 2019-04-28 Zero-Free improve PM mode and device ops interface * 2019-04-28 Zero-Free improve PM mode and device ops interface
* 2020-11-23 zhangsz update pm mode select * 2020-11-23 zhangsz update pm mode select
* 2020-11-27 zhangsz update pm 2.0 * 2020-11-27 zhangsz update pm 2.0
* 2024-07-04 wdfk-prog The device is registered and uninstalled by linked list
*/ */
#ifndef __PM_H__ #ifndef __PM_H__
@ -134,15 +135,16 @@ struct rt_pm_ops
struct rt_device_pm_ops struct rt_device_pm_ops
{ {
int (*suspend)(const struct rt_device *device, rt_uint8_t mode); rt_err_t (*suspend)(const struct rt_device *device, rt_uint8_t mode);
void (*resume)(const struct rt_device *device, rt_uint8_t mode); void (*resume)(const struct rt_device *device, rt_uint8_t mode);
int (*frequency_change)(const struct rt_device *device, rt_uint8_t mode); rt_err_t (*frequency_change)(const struct rt_device *device, rt_uint8_t mode);
}; };
struct rt_device_pm struct rt_device_pm
{ {
const struct rt_device *device; const struct rt_device *device;
const struct rt_device_pm_ops *ops; const struct rt_device_pm_ops *ops;
rt_slist_t list;
}; };
struct rt_pm_module struct rt_pm_module
@ -172,7 +174,7 @@ struct rt_pm
rt_uint32_t sleep_status[PM_SLEEP_MODE_MAX - 1][(PM_MODULE_MAX_ID + 31) / 32]; rt_uint32_t sleep_status[PM_SLEEP_MODE_MAX - 1][(PM_MODULE_MAX_ID + 31) / 32];
/* the list of device, which has PM feature */ /* the list of device, which has PM feature */
rt_uint8_t device_pm_number; rt_slist_t device_list;
struct rt_device_pm *device_pm; struct rt_device_pm *device_pm;
/* if the mode has timer, the corresponding bit is 1*/ /* if the mode has timer, the corresponding bit is 1*/
@ -194,10 +196,10 @@ struct rt_pm_notify
void *data; void *data;
}; };
void rt_pm_request(rt_uint8_t sleep_mode); rt_err_t rt_pm_request(rt_uint8_t sleep_mode);
void rt_pm_release(rt_uint8_t sleep_mode); rt_err_t rt_pm_release(rt_uint8_t sleep_mode);
void rt_pm_release_all(rt_uint8_t sleep_mode); rt_err_t rt_pm_release_all(rt_uint8_t sleep_mode);
int rt_pm_run_enter(rt_uint8_t run_mode); rt_err_t rt_pm_run_enter(rt_uint8_t run_mode);
void rt_pm_device_register(struct rt_device *device, const struct rt_device_pm_ops *ops); void rt_pm_device_register(struct rt_device *device, const struct rt_device_pm_ops *ops);
void rt_pm_device_unregister(struct rt_device *device); void rt_pm_device_unregister(struct rt_device *device);
@ -208,22 +210,22 @@ void rt_pm_default_set(rt_uint8_t sleep_mode);
void rt_system_pm_init(const struct rt_pm_ops *ops, void rt_system_pm_init(const struct rt_pm_ops *ops,
rt_uint8_t timer_mask, rt_uint8_t timer_mask,
void *user_data); void *user_data);
void rt_pm_module_request(uint8_t module_id, rt_uint8_t sleep_mode); rt_err_t rt_pm_module_request(uint8_t module_id, rt_uint8_t sleep_mode);
void rt_pm_module_release(uint8_t module_id, rt_uint8_t sleep_mode); rt_err_t rt_pm_module_release(uint8_t module_id, rt_uint8_t sleep_mode);
void rt_pm_module_release_all(uint8_t module_id, rt_uint8_t sleep_mode); rt_err_t rt_pm_module_release_all(uint8_t module_id, rt_uint8_t sleep_mode);
void rt_pm_module_delay_sleep(rt_uint8_t module_id, rt_tick_t timeout); void rt_pm_module_delay_sleep(rt_uint8_t module_id, rt_tick_t timeout);
rt_uint32_t rt_pm_module_get_status(void); rt_uint32_t rt_pm_module_get_status(void);
rt_uint8_t rt_pm_get_sleep_mode(void); rt_uint8_t rt_pm_get_sleep_mode(void);
struct rt_pm *rt_pm_get_handle(void); struct rt_pm *rt_pm_get_handle(void);
/* sleep : request or release */ /* sleep : request or release */
void rt_pm_sleep_request(rt_uint16_t module_id, rt_uint8_t mode); rt_err_t rt_pm_sleep_request(rt_uint16_t module_id, rt_uint8_t mode);
void rt_pm_sleep_release(rt_uint16_t module_id, rt_uint8_t mode); rt_err_t rt_pm_sleep_release(rt_uint16_t module_id, rt_uint8_t mode);
void rt_pm_sleep_none_request(rt_uint16_t module_id); rt_err_t rt_pm_sleep_none_request(rt_uint16_t module_id);
void rt_pm_sleep_none_release(rt_uint16_t module_id); rt_err_t rt_pm_sleep_none_release(rt_uint16_t module_id);
void rt_pm_sleep_idle_request(rt_uint16_t module_id); rt_err_t rt_pm_sleep_idle_request(rt_uint16_t module_id);
void rt_pm_sleep_idle_release(rt_uint16_t module_id); rt_err_t rt_pm_sleep_idle_release(rt_uint16_t module_id);
void rt_pm_sleep_light_request(rt_uint16_t module_id); rt_err_t rt_pm_sleep_light_request(rt_uint16_t module_id);
void rt_pm_sleep_light_release(rt_uint16_t module_id); rt_err_t rt_pm_sleep_light_release(rt_uint16_t module_id);
#endif /* __PM_H__ */ #endif /* __PM_H__ */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2006-2023, RT-Thread Development Team * Copyright (c) 2006-2024 RT-Thread Development Team
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
@ -10,6 +10,7 @@
* 2019-04-28 Zero-Free improve PM mode and device ops interface * 2019-04-28 Zero-Free improve PM mode and device ops interface
* 2020-11-23 zhangsz update pm mode select * 2020-11-23 zhangsz update pm mode select
* 2020-11-27 zhangsz update pm 2.0 * 2020-11-27 zhangsz update pm 2.0
* 2024-07-04 wdfk-prog The device is registered and uninstalled by linked list
*/ */
#include <rthw.h> #include <rthw.h>
@ -77,9 +78,6 @@ rt_weak void rt_pm_exit_critical(rt_uint32_t ctx, rt_uint8_t sleep_mode)
/* lptimer start */ /* lptimer start */
static void pm_lptimer_start(struct rt_pm *pm, uint32_t timeout) static void pm_lptimer_start(struct rt_pm *pm, uint32_t timeout)
{ {
if (_pm.ops == RT_NULL)
return;
if (_pm.ops->timer_start != RT_NULL) if (_pm.ops->timer_start != RT_NULL)
_pm.ops->timer_start(pm, timeout); _pm.ops->timer_start(pm, timeout);
} }
@ -87,9 +85,6 @@ static void pm_lptimer_start(struct rt_pm *pm, uint32_t timeout)
/* lptimer stop */ /* lptimer stop */
static void pm_lptimer_stop(struct rt_pm *pm) static void pm_lptimer_stop(struct rt_pm *pm)
{ {
if (_pm.ops == RT_NULL)
return;
if (_pm.ops->timer_stop != RT_NULL) if (_pm.ops->timer_stop != RT_NULL)
_pm.ops->timer_stop(pm); _pm.ops->timer_stop(pm);
} }
@ -97,9 +92,6 @@ static void pm_lptimer_stop(struct rt_pm *pm)
/* lptimer get timeout tick */ /* lptimer get timeout tick */
static rt_tick_t pm_lptimer_get_timeout(struct rt_pm *pm) static rt_tick_t pm_lptimer_get_timeout(struct rt_pm *pm)
{ {
if (_pm.ops == RT_NULL)
return RT_TICK_MAX;
if (_pm.ops->timer_get_tick != RT_NULL) if (_pm.ops->timer_get_tick != RT_NULL)
return _pm.ops->timer_get_tick(pm); return _pm.ops->timer_get_tick(pm);
@ -109,9 +101,6 @@ static rt_tick_t pm_lptimer_get_timeout(struct rt_pm *pm)
/* enter sleep mode */ /* enter sleep mode */
static void pm_sleep(struct rt_pm *pm, uint8_t sleep_mode) static void pm_sleep(struct rt_pm *pm, uint8_t sleep_mode)
{ {
if (_pm.ops == RT_NULL)
return;
if (_pm.ops->sleep != RT_NULL) if (_pm.ops->sleep != RT_NULL)
_pm.ops->sleep(pm, sleep_mode); _pm.ops->sleep(pm, sleep_mode);
} }
@ -119,19 +108,24 @@ static void pm_sleep(struct rt_pm *pm, uint8_t sleep_mode)
/** /**
* This function will suspend all registered devices * This function will suspend all registered devices
*/ */
static int _pm_device_suspend(rt_uint8_t mode) static rt_err_t _pm_device_suspend(rt_uint8_t mode)
{ {
int index, ret = RT_EOK; rt_err_t ret = RT_EOK;
struct rt_device_pm *device_pm = RT_NULL;
rt_slist_t *node = RT_NULL;
for (index = 0; index < _pm.device_pm_number; index++) for (node = rt_slist_first(&_pm.device_list); node; node = rt_slist_next(node))
{ {
if (_pm.device_pm[index].ops->suspend != RT_NULL) device_pm = rt_slist_entry(node, struct rt_device_pm, list);
if (device_pm->ops != RT_NULL && device_pm->ops->suspend != RT_NULL)
{ {
ret = _pm.device_pm[index].ops->suspend(_pm.device_pm[index].device, mode); ret = device_pm->ops->suspend(device_pm->device, mode);
if(ret != RT_EOK) if(ret != RT_EOK)
{
break; break;
} }
} }
}
return ret; return ret;
} }
@ -141,13 +135,15 @@ static int _pm_device_suspend(rt_uint8_t mode)
*/ */
static void _pm_device_resume(rt_uint8_t mode) static void _pm_device_resume(rt_uint8_t mode)
{ {
int index; struct rt_device_pm *device_pm = RT_NULL;
rt_slist_t *node = RT_NULL;
for (index = 0; index < _pm.device_pm_number; index++) for (node = rt_slist_first(&_pm.device_list); node; node = rt_slist_next(node))
{ {
if (_pm.device_pm[index].ops->resume != RT_NULL) device_pm = rt_slist_entry(node, struct rt_device_pm, list);
if (device_pm->ops != RT_NULL && device_pm->ops->resume != RT_NULL)
{ {
_pm.device_pm[index].ops->resume(_pm.device_pm[index].device, mode); device_pm->ops->resume(device_pm->device, mode);
} }
} }
} }
@ -157,13 +153,16 @@ static void _pm_device_resume(rt_uint8_t mode)
*/ */
static void _pm_device_frequency_change(rt_uint8_t mode) static void _pm_device_frequency_change(rt_uint8_t mode)
{ {
rt_uint32_t index; struct rt_device_pm *device_pm = RT_NULL;
rt_slist_t *node = RT_NULL;
/* make the frequency change */ for (node = rt_slist_first(&_pm.device_list); node; node = rt_slist_next(node))
for (index = 0; index < _pm.device_pm_number; index ++)
{ {
if (_pm.device_pm[index].ops->frequency_change != RT_NULL) device_pm = rt_slist_entry(node, struct rt_device_pm, list);
_pm.device_pm[index].ops->frequency_change(_pm.device_pm[index].device, mode); if (device_pm->ops->frequency_change != RT_NULL)
{
device_pm->ops->frequency_change(device_pm->device, mode);
}
} }
} }
@ -172,13 +171,16 @@ static void _pm_device_frequency_change(rt_uint8_t mode)
*/ */
static void _pm_frequency_scaling(struct rt_pm *pm) static void _pm_frequency_scaling(struct rt_pm *pm)
{ {
rt_base_t level; rt_base_t level = 0;
if (pm->flags & RT_PM_FREQUENCY_PENDING) if (pm->flags & RT_PM_FREQUENCY_PENDING)
{ {
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
/* change system runing mode */ /* change system runing mode */
if(pm->ops->run != RT_NULL)
{
pm->ops->run(pm, pm->run_mode); pm->ops->run(pm, pm->run_mode);
}
/* changer device frequency */ /* changer device frequency */
_pm_device_frequency_change(pm->run_mode); _pm_device_frequency_change(pm->run_mode);
pm->flags &= ~RT_PM_FREQUENCY_PENDING; pm->flags &= ~RT_PM_FREQUENCY_PENDING;
@ -288,6 +290,12 @@ static rt_bool_t _pm_device_check_idle(void)
return RT_TRUE; return RT_TRUE;
} }
/**
* @brief Get the next system wake-up time
* @note When used by default, it goes into STANDBY mode and sleeps forever. tickless external rewriting is required
* @param mode: sleep mode
* @retval timeout_tick
*/
rt_weak rt_tick_t pm_timer_next_timeout_tick(rt_uint8_t mode) rt_weak rt_tick_t pm_timer_next_timeout_tick(rt_uint8_t mode)
{ {
switch (mode) switch (mode)
@ -344,6 +352,7 @@ rt_weak rt_uint8_t pm_get_sleep_threshold_mode(rt_uint8_t cur_mode, rt_tick_t ti
else if (timeout_tick < PM_STANDBY_THRESHOLD_TIME) else if (timeout_tick < PM_STANDBY_THRESHOLD_TIME)
sleep_mode = PM_SLEEP_MODE_DEEP; sleep_mode = PM_SLEEP_MODE_DEEP;
} }
cur_mode = sleep_mode;
#else #else
if (timeout_tick < PM_TICKLESS_THRESHOLD_TIME) if (timeout_tick < PM_TICKLESS_THRESHOLD_TIME)
{ {
@ -359,8 +368,8 @@ rt_weak rt_uint8_t pm_get_sleep_threshold_mode(rt_uint8_t cur_mode, rt_tick_t ti
*/ */
static void _pm_change_sleep_mode(struct rt_pm *pm) static void _pm_change_sleep_mode(struct rt_pm *pm)
{ {
rt_tick_t timeout_tick, delta_tick; rt_tick_t timeout_tick = 0, delta_tick = 0;
rt_base_t level; rt_base_t level = 0;
uint8_t sleep_mode = PM_SLEEP_MODE_DEEP; uint8_t sleep_mode = PM_SLEEP_MODE_DEEP;
level = rt_pm_enter_critical(pm->sleep_mode); level = rt_pm_enter_critical(pm->sleep_mode);
@ -380,23 +389,27 @@ static void _pm_change_sleep_mode(struct rt_pm *pm)
if (_pm.sleep_mode == PM_SLEEP_MODE_NONE) if (_pm.sleep_mode == PM_SLEEP_MODE_NONE)
{ {
pm->ops->sleep(pm, PM_SLEEP_MODE_NONE); pm_sleep(pm, PM_SLEEP_MODE_NONE);
rt_pm_exit_critical(level, pm->sleep_mode); rt_pm_exit_critical(level, pm->sleep_mode);
} }
else else
{ {
/* Notify app will enter sleep mode */ /* Notify app will enter sleep mode */
if (_pm_notify.notify) if (_pm_notify.notify)
{
_pm_notify.notify(RT_PM_ENTER_SLEEP, pm->sleep_mode, _pm_notify.data); _pm_notify.notify(RT_PM_ENTER_SLEEP, pm->sleep_mode, _pm_notify.data);
}
/* Suspend all peripheral device */ /* Suspend all peripheral device */
#ifdef PM_ENABLE_SUSPEND_SLEEP_MODE #ifdef PM_ENABLE_SUSPEND_SLEEP_MODE
int ret = _pm_device_suspend(pm->sleep_mode); rt_err_t ret = _pm_device_suspend(pm->sleep_mode);
if (ret != RT_EOK) if (ret != RT_EOK)
{ {
_pm_device_resume(pm->sleep_mode); _pm_device_resume(pm->sleep_mode);
if (_pm_notify.notify) if (_pm_notify.notify)
{
_pm_notify.notify(RT_PM_EXIT_SLEEP, pm->sleep_mode, _pm_notify.data); _pm_notify.notify(RT_PM_EXIT_SLEEP, pm->sleep_mode, _pm_notify.data);
}
if (pm->sleep_mode > PM_SUSPEND_SLEEP_MODE) if (pm->sleep_mode > PM_SUSPEND_SLEEP_MODE)
{ {
pm->sleep_mode = PM_SUSPEND_SLEEP_MODE; pm->sleep_mode = PM_SUSPEND_SLEEP_MODE;
@ -418,17 +431,10 @@ static void _pm_change_sleep_mode(struct rt_pm *pm)
pm->sleep_mode = pm_get_sleep_threshold_mode(pm->sleep_mode, timeout_tick); pm->sleep_mode = pm_get_sleep_threshold_mode(pm->sleep_mode, timeout_tick);
if (pm->timer_mask & (0x01 << pm->sleep_mode)) if (pm->timer_mask & (0x01 << pm->sleep_mode))
{
if (timeout_tick == RT_TICK_MAX)
{
pm_lptimer_start(pm, RT_TICK_MAX);
}
else
{ {
pm_lptimer_start(pm, timeout_tick); pm_lptimer_start(pm, timeout_tick);
} }
} }
}
/* enter lower power state */ /* enter lower power state */
pm_sleep(pm, pm->sleep_mode); pm_sleep(pm, pm->sleep_mode);
@ -440,7 +446,9 @@ static void _pm_change_sleep_mode(struct rt_pm *pm)
pm_lptimer_stop(pm); pm_lptimer_stop(pm);
if (delta_tick) if (delta_tick)
{ {
rt_tick_set(rt_tick_get() + delta_tick); rt_interrupt_enter();
rt_tick_increase_tick(delta_tick);
rt_interrupt_leave();
} }
} }
@ -451,14 +459,6 @@ static void _pm_change_sleep_mode(struct rt_pm *pm)
_pm_notify.notify(RT_PM_EXIT_SLEEP, pm->sleep_mode, _pm_notify.data); _pm_notify.notify(RT_PM_EXIT_SLEEP, pm->sleep_mode, _pm_notify.data);
rt_pm_exit_critical(level, pm->sleep_mode); rt_pm_exit_critical(level, pm->sleep_mode);
if (pm->timer_mask & (0x01 << pm->sleep_mode))
{
if (delta_tick)
{
rt_timer_check();
}
}
} }
} }
@ -467,8 +467,10 @@ static void _pm_change_sleep_mode(struct rt_pm *pm)
*/ */
void rt_system_power_manager(void) void rt_system_power_manager(void)
{ {
if (_pm_init_flag == 0) if (_pm_init_flag == 0 || _pm.ops == RT_NULL)
{
return; return;
}
/* CPU frequency scaling according to the runing mode settings */ /* CPU frequency scaling according to the runing mode settings */
_pm_frequency_scaling(&_pm); _pm_frequency_scaling(&_pm);
@ -483,22 +485,28 @@ void rt_system_power_manager(void)
* *
* @param parameter the parameter of run mode or sleep mode * @param parameter the parameter of run mode or sleep mode
*/ */
void rt_pm_request(rt_uint8_t mode) rt_err_t rt_pm_request(rt_uint8_t mode)
{ {
rt_base_t level; rt_base_t level;
struct rt_pm *pm; struct rt_pm *pm;
if (_pm_init_flag == 0) if (_pm_init_flag == 0)
return; {
return -RT_EPERM;
}
if (mode > (PM_SLEEP_MODE_MAX - 1)) if (mode > (PM_SLEEP_MODE_MAX - 1))
return; {
return -RT_EINVAL;
}
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
pm = &_pm; pm = &_pm;
if (pm->modes[mode] < 255) if (pm->modes[mode] < 255)
pm->modes[mode] ++; pm->modes[mode] ++;
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
return RT_EOK;
} }
/** /**
@ -508,22 +516,28 @@ void rt_pm_request(rt_uint8_t mode)
* @param parameter the parameter of run mode or sleep mode * @param parameter the parameter of run mode or sleep mode
* *
*/ */
void rt_pm_release(rt_uint8_t mode) rt_err_t rt_pm_release(rt_uint8_t mode)
{ {
rt_base_t level; rt_base_t level;
struct rt_pm *pm; struct rt_pm *pm;
if (_pm_init_flag == 0) if (_pm_init_flag == 0)
return; {
return -RT_EPERM;
}
if (mode > (PM_SLEEP_MODE_MAX - 1)) if (mode > (PM_SLEEP_MODE_MAX - 1))
return; {
return -RT_EINVAL;
}
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
pm = &_pm; pm = &_pm;
if (pm->modes[mode] > 0) if (pm->modes[mode] > 0)
pm->modes[mode] --; pm->modes[mode] --;
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
return RT_EOK;
} }
/** /**
@ -533,21 +547,27 @@ void rt_pm_release(rt_uint8_t mode)
* @param parameter the parameter of run mode or sleep mode * @param parameter the parameter of run mode or sleep mode
* *
*/ */
void rt_pm_release_all(rt_uint8_t mode) rt_err_t rt_pm_release_all(rt_uint8_t mode)
{ {
rt_base_t level; rt_base_t level;
struct rt_pm *pm; struct rt_pm *pm;
if (_pm_init_flag == 0) if (_pm_init_flag == 0)
return; {
return -RT_EPERM;
}
if (mode > (PM_SLEEP_MODE_MAX - 1)) if (mode > (PM_SLEEP_MODE_MAX - 1))
return; {
return -RT_EINVAL;
}
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
pm = &_pm; pm = &_pm;
pm->modes[mode] = 0; pm->modes[mode] = 0;
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
return RT_EOK;
} }
/** /**
@ -557,19 +577,25 @@ void rt_pm_release_all(rt_uint8_t mode)
* @param module_id the application or device module id * @param module_id the application or device module id
* @param mode the system power sleep mode * @param mode the system power sleep mode
*/ */
void rt_pm_module_request(uint8_t module_id, rt_uint8_t mode) rt_err_t rt_pm_module_request(uint8_t module_id, rt_uint8_t mode)
{ {
rt_base_t level; rt_base_t level;
struct rt_pm *pm; struct rt_pm *pm;
if (_pm_init_flag == 0) if (_pm_init_flag == 0)
return; {
return -RT_EPERM;
}
if (mode > (PM_SLEEP_MODE_MAX - 1)) if (mode > (PM_SLEEP_MODE_MAX - 1))
return; {
return -RT_EINVAL;
}
if (module_id > (PM_MODULE_MAX_ID - 1)) if (module_id > (PM_MODULE_MAX_ID - 1))
return; {
return -RT_EINVAL;
}
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
pm = &_pm; pm = &_pm;
@ -577,6 +603,8 @@ void rt_pm_module_request(uint8_t module_id, rt_uint8_t mode)
if (pm->modes[mode] < 255) if (pm->modes[mode] < 255)
pm->modes[mode] ++; pm->modes[mode] ++;
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
return RT_EOK;
} }
/** /**
@ -587,19 +615,25 @@ void rt_pm_module_request(uint8_t module_id, rt_uint8_t mode)
* @param mode the system power sleep mode * @param mode the system power sleep mode
* *
*/ */
void rt_pm_module_release(uint8_t module_id, rt_uint8_t mode) rt_err_t rt_pm_module_release(uint8_t module_id, rt_uint8_t mode)
{ {
rt_base_t level; rt_base_t level;
struct rt_pm *pm; struct rt_pm *pm;
if (_pm_init_flag == 0) if (_pm_init_flag == 0)
return; {
return -RT_EPERM;
}
if (mode > (PM_SLEEP_MODE_MAX - 1)) if (mode > (PM_SLEEP_MODE_MAX - 1))
return; {
return -RT_EINVAL;
}
if (module_id > (PM_MODULE_MAX_ID - 1)) if (module_id > (PM_MODULE_MAX_ID - 1))
return; {
return -RT_EINVAL;
}
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
pm = &_pm; pm = &_pm;
@ -608,6 +642,8 @@ void rt_pm_module_release(uint8_t module_id, rt_uint8_t mode)
if (pm->modes[mode] == 0) if (pm->modes[mode] == 0)
pm->module_status[module_id].req_status = 0x00; pm->module_status[module_id].req_status = 0x00;
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
return RT_EOK;
} }
/** /**
@ -618,22 +654,28 @@ void rt_pm_module_release(uint8_t module_id, rt_uint8_t mode)
* @param mode the system power sleep mode * @param mode the system power sleep mode
* *
*/ */
void rt_pm_module_release_all(uint8_t module_id, rt_uint8_t mode) rt_err_t rt_pm_module_release_all(uint8_t module_id, rt_uint8_t mode)
{ {
rt_base_t level; rt_base_t level;
struct rt_pm *pm; struct rt_pm *pm;
if (_pm_init_flag == 0) if (_pm_init_flag == 0)
return; {
return -RT_EPERM;
}
if (mode > (PM_SLEEP_MODE_MAX - 1)) if (mode > (PM_SLEEP_MODE_MAX - 1))
return; {
return -RT_EINVAL;
}
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
pm = &_pm; pm = &_pm;
pm->modes[mode] = 0; pm->modes[mode] = 0;
pm->module_status[module_id].req_status = 0x00; pm->module_status[module_id].req_status = 0x00;
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
return RT_EOK;
} }
/** /**
@ -644,23 +686,24 @@ void rt_pm_module_release_all(uint8_t module_id, rt_uint8_t mode)
* *
* @return none * @return none
*/ */
void rt_pm_sleep_request(rt_uint16_t module_id, rt_uint8_t mode) rt_err_t rt_pm_sleep_request(rt_uint16_t module_id, rt_uint8_t mode)
{ {
rt_base_t level; rt_base_t level;
if (module_id >= PM_MODULE_MAX_ID) if (module_id >= PM_MODULE_MAX_ID)
{ {
return; return -RT_EINVAL;
} }
if (mode >= (PM_SLEEP_MODE_MAX - 1)) if (mode >= (PM_SLEEP_MODE_MAX - 1))
{ {
return; return -RT_EINVAL;
} }
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
_pm.sleep_status[mode][module_id / 32] |= 1 << (module_id % 32); _pm.sleep_status[mode][module_id / 32] |= 1 << (module_id % 32);
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
return RT_EOK;
} }
/** /**
@ -670,9 +713,9 @@ void rt_pm_sleep_request(rt_uint16_t module_id, rt_uint8_t mode)
* *
* @return NULL * @return NULL
*/ */
void rt_pm_sleep_none_request(rt_uint16_t module_id) rt_err_t rt_pm_sleep_none_request(rt_uint16_t module_id)
{ {
rt_pm_sleep_request(module_id, PM_SLEEP_MODE_NONE); return rt_pm_sleep_request(module_id, PM_SLEEP_MODE_NONE);
} }
/** /**
@ -682,9 +725,9 @@ void rt_pm_sleep_none_request(rt_uint16_t module_id)
* *
* @return NULL * @return NULL
*/ */
void rt_pm_sleep_idle_request(rt_uint16_t module_id) rt_err_t rt_pm_sleep_idle_request(rt_uint16_t module_id)
{ {
rt_pm_sleep_request(module_id, PM_SLEEP_MODE_IDLE); return rt_pm_sleep_request(module_id, PM_SLEEP_MODE_IDLE);
} }
/** /**
@ -694,9 +737,9 @@ void rt_pm_sleep_idle_request(rt_uint16_t module_id)
* *
* @return NULL * @return NULL
*/ */
void rt_pm_sleep_light_request(rt_uint16_t module_id) rt_err_t rt_pm_sleep_light_request(rt_uint16_t module_id)
{ {
rt_pm_sleep_request(module_id, PM_SLEEP_MODE_LIGHT); return rt_pm_sleep_request(module_id, PM_SLEEP_MODE_LIGHT);
} }
/** /**
@ -707,23 +750,24 @@ void rt_pm_sleep_light_request(rt_uint16_t module_id)
* *
* @return NULL * @return NULL
*/ */
void rt_pm_sleep_release(rt_uint16_t module_id, rt_uint8_t mode) rt_err_t rt_pm_sleep_release(rt_uint16_t module_id, rt_uint8_t mode)
{ {
rt_base_t level; rt_base_t level;
if (module_id >= PM_MODULE_MAX_ID) if (module_id >= PM_MODULE_MAX_ID)
{ {
return; return -RT_EINVAL;
} }
if (mode >= (PM_SLEEP_MODE_MAX - 1)) if (mode >= (PM_SLEEP_MODE_MAX - 1))
{ {
return; return -RT_EINVAL;
} }
level = rt_hw_interrupt_disable(); level = rt_hw_interrupt_disable();
_pm.sleep_status[mode][module_id / 32] &= ~(1 << (module_id % 32)); _pm.sleep_status[mode][module_id / 32] &= ~(1 << (module_id % 32));
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
return RT_EOK;
} }
/** /**
@ -733,9 +777,9 @@ void rt_pm_sleep_release(rt_uint16_t module_id, rt_uint8_t mode)
* *
* @return none * @return none
*/ */
void rt_pm_sleep_none_release(rt_uint16_t module_id) rt_err_t rt_pm_sleep_none_release(rt_uint16_t module_id)
{ {
rt_pm_sleep_release(module_id, PM_SLEEP_MODE_NONE); return rt_pm_sleep_release(module_id, PM_SLEEP_MODE_NONE);
} }
/** /**
@ -745,9 +789,9 @@ void rt_pm_sleep_none_release(rt_uint16_t module_id)
* *
* @return none * @return none
*/ */
void rt_pm_sleep_idle_release(rt_uint16_t module_id) rt_err_t rt_pm_sleep_idle_release(rt_uint16_t module_id)
{ {
rt_pm_sleep_release(module_id, PM_SLEEP_MODE_IDLE); return rt_pm_sleep_release(module_id, PM_SLEEP_MODE_IDLE);
} }
/** /**
@ -757,9 +801,9 @@ void rt_pm_sleep_idle_release(rt_uint16_t module_id)
* *
* @return none * @return none
*/ */
void rt_pm_sleep_light_release(rt_uint16_t module_id) rt_err_t rt_pm_sleep_light_release(rt_uint16_t module_id)
{ {
rt_pm_sleep_release(module_id, PM_SLEEP_MODE_LIGHT); return rt_pm_sleep_release(module_id, PM_SLEEP_MODE_LIGHT);
} }
/** /**
@ -770,24 +814,15 @@ void rt_pm_sleep_light_release(rt_uint16_t module_id)
*/ */
void rt_pm_device_register(struct rt_device *device, const struct rt_device_pm_ops *ops) void rt_pm_device_register(struct rt_device *device, const struct rt_device_pm_ops *ops)
{ {
rt_base_t level;
struct rt_device_pm *device_pm; struct rt_device_pm *device_pm;
RT_DEBUG_NOT_IN_INTERRUPT; device_pm = RT_KERNEL_MALLOC(sizeof(struct rt_device_pm));
level = rt_hw_interrupt_disable();
device_pm = (struct rt_device_pm *)RT_KERNEL_REALLOC(_pm.device_pm,
(_pm.device_pm_number + 1) * sizeof(struct rt_device_pm));
if (device_pm != RT_NULL) if (device_pm != RT_NULL)
{ {
_pm.device_pm = device_pm; rt_slist_append(&_pm.device_list, &device_pm->list);
_pm.device_pm[_pm.device_pm_number].device = device; device_pm->device = device;
_pm.device_pm[_pm.device_pm_number].ops = ops; device_pm->ops = ops;
_pm.device_pm_number += 1;
} }
rt_hw_interrupt_enable(level);
} }
/** /**
@ -797,32 +832,18 @@ void rt_pm_device_register(struct rt_device *device, const struct rt_device_pm_o
*/ */
void rt_pm_device_unregister(struct rt_device *device) void rt_pm_device_unregister(struct rt_device *device)
{ {
rt_base_t level; struct rt_device_pm *device_pm = RT_NULL;
rt_uint32_t index; rt_slist_t *node = RT_NULL;
RT_DEBUG_NOT_IN_INTERRUPT; for (node = rt_slist_first(&_pm.device_list); node; node = rt_slist_next(node))
level = rt_hw_interrupt_disable();
for (index = 0; index < _pm.device_pm_number; index ++)
{ {
if (_pm.device_pm[index].device == device) device_pm = rt_slist_entry(node, struct rt_device_pm, list);
if (device_pm->device == device)
{ {
/* remove current entry */ rt_slist_remove(&_pm.device_list, &device_pm->list);
for (; index < _pm.device_pm_number - 1; index ++) RT_KERNEL_FREE(device_pm);
{
_pm.device_pm[index] = _pm.device_pm[index + 1];
}
_pm.device_pm[_pm.device_pm_number - 1].device = RT_NULL;
_pm.device_pm[_pm.device_pm_number - 1].ops = RT_NULL;
_pm.device_pm_number -= 1;
/* break out and not touch memory */
break; break;
} }
} }
rt_hw_interrupt_enable(level);
} }
/** /**
@ -914,10 +935,11 @@ static rt_err_t _rt_pm_device_control(rt_device_t dev,
return RT_EOK; return RT_EOK;
} }
int rt_pm_run_enter(rt_uint8_t mode) rt_err_t rt_pm_run_enter(rt_uint8_t mode)
{ {
rt_base_t level; rt_base_t level = 0;
struct rt_pm *pm; struct rt_pm *pm = RT_NULL;
rt_err_t ret = RT_EOK;
if (_pm_init_flag == 0) if (_pm_init_flag == 0)
return -RT_EIO; return -RT_EIO;
@ -925,12 +947,16 @@ int rt_pm_run_enter(rt_uint8_t mode)
if (mode > PM_RUN_MODE_MAX) if (mode > PM_RUN_MODE_MAX)
return -RT_EINVAL; return -RT_EINVAL;
level = rt_hw_interrupt_disable();
pm = &_pm; pm = &_pm;
level = rt_hw_interrupt_disable();
if (mode < pm->run_mode) if (mode < pm->run_mode)
{ {
/* change system runing mode */ /* change system runing mode */
if(pm->ops != RT_NULL && pm->ops->run != RT_NULL)
{
pm->ops->run(pm, mode); pm->ops->run(pm, mode);
}
/* changer device frequency */ /* changer device frequency */
_pm_device_frequency_change(mode); _pm_device_frequency_change(mode);
} }
@ -941,7 +967,7 @@ int rt_pm_run_enter(rt_uint8_t mode)
pm->run_mode = mode; pm->run_mode = mode;
rt_hw_interrupt_enable(level); rt_hw_interrupt_enable(level);
return RT_EOK; return ret;
} }
#ifdef RT_USING_DEVICE_OPS #ifdef RT_USING_DEVICE_OPS
@ -1004,7 +1030,8 @@ void rt_system_pm_init(const struct rt_pm_ops *ops,
pm->ops = ops; pm->ops = ops;
pm->device_pm = RT_NULL; pm->device_pm = RT_NULL;
pm->device_pm_number = 0;
rt_slist_init(&pm->device_list);
#if IDLE_THREAD_STACK_SIZE <= 256 #if IDLE_THREAD_STACK_SIZE <= 256
#error "[pm.c ERR] IDLE Stack Size Too Small!" #error "[pm.c ERR] IDLE Stack Size Too Small!"