1 /*
2  * Copyright (c) 2006-2024 RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2012-06-02     Bernard      the first version
9  * 2018-08-02     Tanek        split run and sleep modes, support custom mode
10  * 2019-04-28     Zero-Free    improve PM mode and device ops interface
11  * 2020-11-23     zhangsz      update pm mode select
12  * 2020-11-27     zhangsz      update pm 2.0
13  * 2024-07-04     wdfk-prog    The device is registered and uninstalled by linked list
14  */
15 
16 #include <rthw.h>
17 #include <rtthread.h>
18 #include <drivers/pm.h>
19 #include <stdlib.h>
20 
21 #ifdef RT_USING_PM
22 
23 /* tickless threshold time */
24 #ifndef PM_TICKLESS_THRESHOLD_TIME
25 #define PM_TICKLESS_THRESHOLD_TIME          2
26 #endif
27 
28 /* tickless threshold : sleep mode */
29 #ifndef PM_TICKLESS_THRESHOLD_MODE
30 #define PM_TICKLESS_THRESHOLD_MODE          PM_SLEEP_MODE_IDLE
31 #endif
32 
33 /* busy : sleep mode */
34 #ifndef PM_BUSY_SLEEP_MODE
35 #define PM_BUSY_SLEEP_MODE                  PM_SLEEP_MODE_IDLE
36 #endif
37 
38 /* suspend : suspend sleep mode */
39 #ifndef PM_SUSPEND_SLEEP_MODE
40 #define PM_SUSPEND_SLEEP_MODE               PM_SLEEP_MODE_IDLE
41 #endif
42 
43 #ifdef PM_ENABLE_THRESHOLD_SLEEP_MODE
44 #ifndef PM_LIGHT_THRESHOLD_TIME
45 #define PM_LIGHT_THRESHOLD_TIME             5
46 #endif
47 
48 #ifndef PM_DEEP_THRESHOLD_TIME
49 #define PM_DEEP_THRESHOLD_TIME              20
50 #endif
51 
52 #ifndef PM_STANDBY_THRESHOLD_TIME
53 #define PM_STANDBY_THRESHOLD_TIME           100
54 #endif
55 #endif
56 
57 static struct rt_pm _pm;
58 
59 /* default mode : system power on */
60 static rt_uint8_t _pm_default_sleep = RT_PM_DEFAULT_SLEEP_MODE;
61 
62 /* default deepsleep mode : tick-less mode */
63 static rt_uint8_t _pm_default_deepsleep = RT_PM_DEFAULT_DEEPSLEEP_MODE;
64 
65 static struct rt_pm_notify _pm_notify;
66 static rt_uint8_t _pm_init_flag = 0;
67 
rt_pm_enter_critical(rt_uint8_t sleep_mode)68 rt_weak rt_uint32_t rt_pm_enter_critical(rt_uint8_t sleep_mode)
69 {
70     return rt_hw_interrupt_disable();
71 }
72 
rt_pm_exit_critical(rt_uint32_t ctx,rt_uint8_t sleep_mode)73 rt_weak void rt_pm_exit_critical(rt_uint32_t ctx, rt_uint8_t sleep_mode)
74 {
75     rt_hw_interrupt_enable(ctx);
76 }
77 
78 /* lptimer start */
pm_lptimer_start(struct rt_pm * pm,uint32_t timeout)79 static void pm_lptimer_start(struct rt_pm *pm, uint32_t timeout)
80 {
81     if (_pm.ops->timer_start != RT_NULL)
82         _pm.ops->timer_start(pm, timeout);
83 }
84 
85 /* lptimer stop */
pm_lptimer_stop(struct rt_pm * pm)86 static void pm_lptimer_stop(struct rt_pm *pm)
87 {
88     if (_pm.ops->timer_stop != RT_NULL)
89         _pm.ops->timer_stop(pm);
90 }
91 
92 /* lptimer get timeout tick */
pm_lptimer_get_timeout(struct rt_pm * pm)93 static rt_tick_t pm_lptimer_get_timeout(struct rt_pm *pm)
94 {
95     if (_pm.ops->timer_get_tick != RT_NULL)
96         return _pm.ops->timer_get_tick(pm);
97 
98     return RT_TICK_MAX;
99 }
100 
101 /* enter sleep mode */
pm_sleep(struct rt_pm * pm,uint8_t sleep_mode)102 static void pm_sleep(struct rt_pm *pm, uint8_t sleep_mode)
103 {
104     if (_pm.ops->sleep != RT_NULL)
105         _pm.ops->sleep(pm, sleep_mode);
106 }
107 
108 /**
109  * This function will suspend all registered devices
110  */
_pm_device_suspend(rt_uint8_t mode)111 static rt_err_t _pm_device_suspend(rt_uint8_t mode)
112 {
113     rt_err_t ret = RT_EOK;
114     struct rt_device_pm *device_pm = RT_NULL;
115     rt_slist_t *node = RT_NULL;
116 
117     for (node = rt_slist_first(&_pm.device_list); node; node = rt_slist_next(node))
118     {
119         device_pm = rt_slist_entry(node, struct rt_device_pm, list);
120         if (device_pm->ops != RT_NULL && device_pm->ops->suspend != RT_NULL)
121         {
122             ret = device_pm->ops->suspend(device_pm->device, mode);
123             if(ret != RT_EOK)
124             {
125                 break;
126             }
127         }
128     }
129 
130     return ret;
131 }
132 
133 /**
134  * This function will resume all registered devices
135  */
_pm_device_resume(rt_uint8_t mode)136 static void _pm_device_resume(rt_uint8_t mode)
137 {
138     struct rt_device_pm *device_pm = RT_NULL;
139     rt_slist_t *node = RT_NULL;
140 
141     for (node = rt_slist_first(&_pm.device_list); node; node = rt_slist_next(node))
142     {
143         device_pm = rt_slist_entry(node, struct rt_device_pm, list);
144         if (device_pm->ops != RT_NULL && device_pm->ops->resume != RT_NULL)
145         {
146             device_pm->ops->resume(device_pm->device, mode);
147         }
148     }
149 }
150 
151 /**
152  * This function will update the frequency of all registered devices
153  */
_pm_device_frequency_change(rt_uint8_t mode)154 static void _pm_device_frequency_change(rt_uint8_t mode)
155 {
156     struct rt_device_pm *device_pm = RT_NULL;
157     rt_slist_t *node = RT_NULL;
158 
159     for (node = rt_slist_first(&_pm.device_list); node; node = rt_slist_next(node))
160     {
161         device_pm = rt_slist_entry(node, struct rt_device_pm, list);
162         if (device_pm->ops->frequency_change != RT_NULL)
163         {
164             device_pm->ops->frequency_change(device_pm->device, mode);
165         }
166     }
167 }
168 
169 /**
170  * This function will update the system clock frequency when idle
171  */
_pm_frequency_scaling(struct rt_pm * pm)172 static void _pm_frequency_scaling(struct rt_pm *pm)
173 {
174     rt_base_t level = 0;
175 
176     if (pm->flags & RT_PM_FREQUENCY_PENDING)
177     {
178         level = rt_hw_interrupt_disable();
179         /* change system runing mode */
180         if(pm->ops->run != RT_NULL)
181         {
182             pm->ops->run(pm, pm->run_mode);
183         }
184         /* changer device frequency */
185         _pm_device_frequency_change(pm->run_mode);
186         pm->flags &= ~RT_PM_FREQUENCY_PENDING;
187         rt_hw_interrupt_enable(level);
188     }
189 }
190 
191 /**
192  * judge sleep mode from sleep request
193  *
194  * @param none
195  *
196  * @return sleep mode
197  */
_judge_sleep_mode(void)198 static rt_uint8_t _judge_sleep_mode(void)
199 {
200     rt_uint16_t index;
201     rt_uint16_t len;
202 
203     for (index = 0; index < PM_SLEEP_MODE_MAX -1; index++)
204     {
205         for (len = 0; len < ((PM_MODULE_MAX_ID + 31) / 32); len++)
206         {
207             if (_pm.sleep_status[index][len] != 0x00)
208                 return index;
209         }
210     }
211 
212     return PM_SLEEP_MODE_MAX;  /* default sleep mode */
213 }
214 
215 /**
216  * This function selects the sleep mode according to the rt_pm_request/rt_pm_release count.
217  */
_pm_select_sleep_mode(struct rt_pm * pm)218 static rt_uint8_t _pm_select_sleep_mode(struct rt_pm *pm)
219 {
220     int index;
221     rt_uint8_t mode;
222 
223     mode = _pm_default_deepsleep;
224     rt_uint8_t request_mode = _judge_sleep_mode();
225     for (index = PM_SLEEP_MODE_NONE; index < PM_SLEEP_MODE_MAX; index ++)
226     {
227         if (pm->modes[index])
228         {
229             mode = index;
230             break;
231         }
232     }
233 
234     /* select the high power mode */
235     if (request_mode < mode)
236         mode = request_mode;
237 
238     return mode;
239 }
240 
241 /**
242  * pm module request delay sleep.
243  */
rt_pm_module_delay_sleep(rt_uint8_t module_id,rt_tick_t timeout)244 void rt_pm_module_delay_sleep(rt_uint8_t module_id, rt_tick_t timeout)
245 {
246     rt_base_t level;
247     struct rt_pm *pm;
248 
249     if (_pm_init_flag == 0)
250         return;
251 
252     if (module_id > (PM_MODULE_MAX_ID - 1))
253         return;
254 
255     level = rt_hw_interrupt_disable();
256     pm = &_pm;
257     pm->module_status[module_id].busy_flag = RT_TRUE;
258     pm->module_status[module_id].timeout = timeout;
259     pm->module_status[module_id].start_time = rt_tick_get();
260     rt_hw_interrupt_enable(level);
261 }
262 
263 /**
264  * This function check if all modules in idle status.
265  */
_pm_device_check_idle(void)266 static rt_bool_t _pm_device_check_idle(void)
267 {
268     struct rt_pm *pm;
269 
270     if (_pm_init_flag == 0)
271         return RT_TRUE;
272 
273     pm = &_pm;
274     for (int i = 0; i < PM_MODULE_MAX_ID; i++)
275     {
276         if (pm->module_status[i].busy_flag == RT_TRUE)
277         {
278             if (rt_tick_get() - pm->module_status[i].start_time > pm->module_status[i].timeout)
279             {
280                 pm->module_status[i].busy_flag = RT_FALSE;
281                 pm->module_status[i].timeout = 0x00;
282             }
283         }
284         if (pm->module_status[i].busy_flag == RT_TRUE)
285         {
286             return RT_FALSE;
287         }
288     }
289 
290     return RT_TRUE;
291 }
292 
293 /**
294  * @brief  Get the next system wake-up time
295  * @note   When used by default, it goes into STANDBY mode and sleeps forever. tickless external rewriting is required
296  * @param  mode: sleep mode
297  * @retval timeout_tick
298  */
pm_timer_next_timeout_tick(rt_uint8_t mode)299 rt_weak rt_tick_t pm_timer_next_timeout_tick(rt_uint8_t mode)
300 {
301     switch (mode)
302     {
303         case PM_SLEEP_MODE_LIGHT:
304             return rt_timer_next_timeout_tick();
305         case PM_SLEEP_MODE_DEEP:
306         case PM_SLEEP_MODE_STANDBY:
307             return rt_lptimer_next_timeout_tick();
308     }
309 
310     return RT_TICK_MAX;
311 }
312 
313 /**
314  * This function will judge sleep mode from threshold timeout.
315  *
316  * @param cur_mode the current pm sleep mode
317  * @param timeout_tick the threshold timeout
318  *
319  * @return none
320  */
pm_get_sleep_threshold_mode(rt_uint8_t cur_mode,rt_tick_t timeout_tick)321 rt_weak rt_uint8_t pm_get_sleep_threshold_mode(rt_uint8_t cur_mode, rt_tick_t timeout_tick)
322 {
323     rt_uint8_t sleep_mode = cur_mode;
324 
325     if (_pm_init_flag == 0)
326         return sleep_mode;
327 
328     if (cur_mode >= PM_SLEEP_MODE_MAX)
329         return sleep_mode;
330 
331 #ifdef PM_ENABLE_THRESHOLD_SLEEP_MODE
332     switch (cur_mode)
333     {
334     case PM_SLEEP_MODE_NONE:
335     case PM_SLEEP_MODE_IDLE:
336         break;
337     case PM_SLEEP_MODE_LIGHT:
338         if (timeout_tick < PM_LIGHT_THRESHOLD_TIME)
339             sleep_mode = PM_SLEEP_MODE_IDLE;
340         break;
341     case PM_SLEEP_MODE_DEEP:
342         if (timeout_tick < PM_LIGHT_THRESHOLD_TIME)
343             sleep_mode = PM_SLEEP_MODE_IDLE;
344         else if (timeout_tick < PM_DEEP_THRESHOLD_TIME)
345             sleep_mode = PM_SLEEP_MODE_LIGHT;
346         break;
347     case PM_SLEEP_MODE_STANDBY:
348         if (timeout_tick < PM_LIGHT_THRESHOLD_TIME)
349             sleep_mode = PM_SLEEP_MODE_IDLE;
350         else if (timeout_tick < PM_DEEP_THRESHOLD_TIME)
351             sleep_mode = PM_SLEEP_MODE_LIGHT;
352         else if (timeout_tick < PM_STANDBY_THRESHOLD_TIME)
353             sleep_mode = PM_SLEEP_MODE_DEEP;
354     }
355     cur_mode = sleep_mode;
356 #else
357     if (timeout_tick < PM_TICKLESS_THRESHOLD_TIME)
358     {
359         cur_mode = PM_SLEEP_MODE_IDLE;
360     }
361 #endif
362 
363     return cur_mode;
364 }
365 
366 /**
367  * This function changes the power sleep mode base on the result of selection
368  */
_pm_change_sleep_mode(struct rt_pm * pm)369 static void _pm_change_sleep_mode(struct rt_pm *pm)
370 {
371     rt_tick_t timeout_tick = 0, delta_tick = 0;
372     rt_base_t level = 0;
373     uint8_t sleep_mode = PM_SLEEP_MODE_DEEP;
374 
375     level = rt_pm_enter_critical(pm->sleep_mode);
376 
377     /* judge sleep mode from module request */
378     pm->sleep_mode = _pm_select_sleep_mode(pm);
379 
380     /* module busy request check */
381     if (_pm_device_check_idle() == RT_FALSE)
382     {
383         sleep_mode = PM_BUSY_SLEEP_MODE;
384         if (sleep_mode < pm->sleep_mode)
385         {
386             pm->sleep_mode = sleep_mode; /* judge the highest sleep mode */
387         }
388     }
389 
390     if (_pm.sleep_mode == PM_SLEEP_MODE_NONE)
391     {
392         pm_sleep(pm, PM_SLEEP_MODE_NONE);
393         rt_pm_exit_critical(level, pm->sleep_mode);
394     }
395     else
396     {
397         /* Notify app will enter sleep mode */
398         if (_pm_notify.notify)
399         {
400             _pm_notify.notify(RT_PM_ENTER_SLEEP, pm->sleep_mode, _pm_notify.data);
401         }
402 
403         /* Suspend all peripheral device */
404 #ifdef PM_ENABLE_SUSPEND_SLEEP_MODE
405         rt_err_t ret = _pm_device_suspend(pm->sleep_mode);
406         if (ret != RT_EOK)
407         {
408             _pm_device_resume(pm->sleep_mode);
409             if (_pm_notify.notify)
410             {
411                 _pm_notify.notify(RT_PM_EXIT_SLEEP, pm->sleep_mode, _pm_notify.data);
412             }
413             if (pm->sleep_mode > PM_SUSPEND_SLEEP_MODE)
414             {
415                 pm->sleep_mode = PM_SUSPEND_SLEEP_MODE;
416             }
417             pm->ops->sleep(pm, pm->sleep_mode); /* suspend failed */
418             rt_pm_exit_critical(level, pm->sleep_mode);
419             return;
420         }
421 #else
422         _pm_device_suspend(pm->sleep_mode);
423 #endif
424         /* Tickless*/
425         if (pm->timer_mask & (0x01 << pm->sleep_mode))
426         {
427             timeout_tick = pm_timer_next_timeout_tick(pm->sleep_mode);
428             timeout_tick = timeout_tick - rt_tick_get();
429 
430             /* Judge sleep_mode from threshold time */
431             pm->sleep_mode = pm_get_sleep_threshold_mode(pm->sleep_mode, timeout_tick);
432 
433             if (pm->timer_mask & (0x01 << pm->sleep_mode))
434             {
435                 pm_lptimer_start(pm, timeout_tick);
436             }
437         }
438 
439         /* enter lower power state */
440         pm_sleep(pm, pm->sleep_mode);
441 
442         /* wake up from lower power state*/
443         if (pm->timer_mask & (0x01 << pm->sleep_mode))
444         {
445             delta_tick = pm_lptimer_get_timeout(pm);
446             pm_lptimer_stop(pm);
447             if (delta_tick)
448             {
449                 rt_interrupt_enter();
450                 rt_tick_increase_tick(delta_tick);
451                 rt_interrupt_leave();
452             }
453         }
454 
455         /* resume all device */
456         _pm_device_resume(pm->sleep_mode);
457 
458         if (_pm_notify.notify)
459             _pm_notify.notify(RT_PM_EXIT_SLEEP, pm->sleep_mode, _pm_notify.data);
460 
461         rt_pm_exit_critical(level, pm->sleep_mode);
462     }
463 }
464 
465 /**
466  * This function will enter corresponding power mode.
467  */
rt_system_power_manager(void)468 void rt_system_power_manager(void)
469 {
470     if (_pm_init_flag == 0 || _pm.ops == RT_NULL)
471     {
472         return;
473     }
474 
475     /* CPU frequency scaling according to the runing mode settings */
476     _pm_frequency_scaling(&_pm);
477 
478     /* Low Power Mode Processing */
479     _pm_change_sleep_mode(&_pm);
480 }
481 
482 /**
483  * Upper application or device driver requests the system
484  * stall in corresponding power mode.
485  *
486  * @param parameter the parameter of run mode or sleep mode
487  */
rt_pm_request(rt_uint8_t mode)488 rt_err_t rt_pm_request(rt_uint8_t mode)
489 {
490     rt_base_t level;
491     struct rt_pm *pm;
492 
493     if (_pm_init_flag == 0)
494     {
495         return -RT_EPERM;
496     }
497 
498     if (mode > (PM_SLEEP_MODE_MAX - 1))
499     {
500         return -RT_EINVAL;
501     }
502 
503     level = rt_hw_interrupt_disable();
504     pm = &_pm;
505     if (pm->modes[mode] < 255)
506         pm->modes[mode] ++;
507     rt_hw_interrupt_enable(level);
508 
509     return RT_EOK;
510 }
511 
512 /**
513  * Upper application or device driver releases the stall
514  * of corresponding power mode.
515  *
516  * @param parameter the parameter of run mode or sleep mode
517  *
518  */
rt_pm_release(rt_uint8_t mode)519 rt_err_t rt_pm_release(rt_uint8_t mode)
520 {
521     rt_base_t level;
522     struct rt_pm *pm;
523 
524     if (_pm_init_flag == 0)
525     {
526         return -RT_EPERM;
527     }
528 
529     if (mode > (PM_SLEEP_MODE_MAX - 1))
530     {
531         return -RT_EINVAL;
532     }
533 
534     level = rt_hw_interrupt_disable();
535     pm = &_pm;
536     if (pm->modes[mode] > 0)
537         pm->modes[mode] --;
538     rt_hw_interrupt_enable(level);
539 
540     return RT_EOK;
541 }
542 
543 /**
544  * Upper application or device driver releases all the stall
545  * of corresponding power mode.
546  *
547  * @param parameter the parameter of run mode or sleep mode
548  *
549  */
rt_pm_release_all(rt_uint8_t mode)550 rt_err_t rt_pm_release_all(rt_uint8_t mode)
551 {
552     rt_base_t level;
553     struct rt_pm *pm;
554 
555     if (_pm_init_flag == 0)
556     {
557         return -RT_EPERM;
558     }
559 
560     if (mode > (PM_SLEEP_MODE_MAX - 1))
561     {
562         return -RT_EINVAL;
563     }
564 
565     level = rt_hw_interrupt_disable();
566     pm = &_pm;
567     pm->modes[mode] = 0;
568     rt_hw_interrupt_enable(level);
569 
570     return RT_EOK;
571 }
572 
573 /**
574  * Upper application or device driver requests the system
575  * stall in corresponding power mode.
576  *
577  * @param module_id the application or device module id
578  * @param mode the system power sleep mode
579  */
rt_pm_module_request(uint8_t module_id,rt_uint8_t mode)580 rt_err_t rt_pm_module_request(uint8_t module_id, rt_uint8_t mode)
581 {
582     rt_base_t level;
583     struct rt_pm *pm;
584 
585     if (_pm_init_flag == 0)
586     {
587         return -RT_EPERM;
588     }
589 
590     if (mode > (PM_SLEEP_MODE_MAX - 1))
591     {
592         return -RT_EINVAL;
593     }
594 
595     if (module_id > (PM_MODULE_MAX_ID - 1))
596     {
597         return -RT_EINVAL;
598     }
599 
600     level = rt_hw_interrupt_disable();
601     pm = &_pm;
602     pm->module_status[module_id].req_status = 0x01;
603     if (pm->modes[mode] < 255)
604         pm->modes[mode] ++;
605     rt_hw_interrupt_enable(level);
606 
607     return RT_EOK;
608 }
609 
610 /**
611  * Upper application or device driver releases the stall
612  * of corresponding power mode.
613  *
614  * @param module_id the application or device module id
615  * @param mode the system power sleep mode
616  *
617  */
rt_pm_module_release(uint8_t module_id,rt_uint8_t mode)618 rt_err_t rt_pm_module_release(uint8_t module_id, rt_uint8_t mode)
619 {
620     rt_base_t level;
621     struct rt_pm *pm;
622 
623     if (_pm_init_flag == 0)
624     {
625         return -RT_EPERM;
626     }
627 
628     if (mode > (PM_SLEEP_MODE_MAX - 1))
629     {
630         return -RT_EINVAL;
631     }
632 
633     if (module_id > (PM_MODULE_MAX_ID - 1))
634     {
635         return -RT_EINVAL;
636     }
637 
638     level = rt_hw_interrupt_disable();
639     pm = &_pm;
640     if (pm->modes[mode] > 0)
641         pm->modes[mode] --;
642     if (pm->modes[mode] == 0)
643         pm->module_status[module_id].req_status = 0x00;
644     rt_hw_interrupt_enable(level);
645 
646     return RT_EOK;
647 }
648 
649 /**
650  * Upper application or device driver releases all the stall
651  * of corresponding power mode.
652  *
653  * @param module_id the application or device module id
654  * @param mode the system power sleep mode
655  *
656  */
rt_pm_module_release_all(uint8_t module_id,rt_uint8_t mode)657 rt_err_t rt_pm_module_release_all(uint8_t module_id, rt_uint8_t mode)
658 {
659     rt_base_t level;
660     struct rt_pm *pm;
661 
662     if (_pm_init_flag == 0)
663     {
664         return -RT_EPERM;
665     }
666 
667     if (mode > (PM_SLEEP_MODE_MAX - 1))
668     {
669         return -RT_EINVAL;
670     }
671 
672     level = rt_hw_interrupt_disable();
673     pm = &_pm;
674     pm->modes[mode] = 0;
675     pm->module_status[module_id].req_status = 0x00;
676     rt_hw_interrupt_enable(level);
677 
678     return RT_EOK;
679 }
680 
681 /**
682  * This function will let current module work with specified sleep mode.
683  *
684  * @param module_id the pm module id
685  * @param mode the pm sleep mode
686  *
687  * @return none
688  */
rt_pm_sleep_request(rt_uint16_t module_id,rt_uint8_t mode)689 rt_err_t rt_pm_sleep_request(rt_uint16_t module_id, rt_uint8_t mode)
690 {
691     rt_base_t level;
692 
693     if (module_id >= PM_MODULE_MAX_ID)
694     {
695         return -RT_EINVAL;
696     }
697 
698     if (mode >= (PM_SLEEP_MODE_MAX - 1))
699     {
700         return -RT_EINVAL;
701     }
702 
703     level = rt_hw_interrupt_disable();
704     _pm.sleep_status[mode][module_id / 32] |= 1 << (module_id % 32);
705     rt_hw_interrupt_enable(level);
706     return RT_EOK;
707 }
708 
709 /**
710  * This function will let current module work with PM_SLEEP_MODE_NONE mode.
711  *
712  * @param module_id the pm module id
713  *
714  * @return NULL
715  */
rt_pm_sleep_none_request(rt_uint16_t module_id)716 rt_err_t rt_pm_sleep_none_request(rt_uint16_t module_id)
717 {
718     return rt_pm_sleep_request(module_id, PM_SLEEP_MODE_NONE);
719 }
720 
721 /**
722  * This function will let current module work with PM_SLEEP_MODE_IDLE mode.
723  *
724  * @param module_id the pm module id
725  *
726  * @return NULL
727  */
rt_pm_sleep_idle_request(rt_uint16_t module_id)728 rt_err_t rt_pm_sleep_idle_request(rt_uint16_t module_id)
729 {
730     return rt_pm_sleep_request(module_id, PM_SLEEP_MODE_IDLE);
731 }
732 
733 /**
734  * This function will let current module work with PM_SLEEP_MODE_LIGHT mode.
735  *
736  * @param module_id the pm module id
737  *
738  * @return NULL
739  */
rt_pm_sleep_light_request(rt_uint16_t module_id)740 rt_err_t rt_pm_sleep_light_request(rt_uint16_t module_id)
741 {
742     return rt_pm_sleep_request(module_id, PM_SLEEP_MODE_LIGHT);
743 }
744 
745 /**
746  * When current module don't work, release requested sleep mode.
747  *
748  * @param module_id the pm module id
749  * @param mode the pm sleep mode
750  *
751  * @return NULL
752  */
rt_pm_sleep_release(rt_uint16_t module_id,rt_uint8_t mode)753 rt_err_t rt_pm_sleep_release(rt_uint16_t module_id, rt_uint8_t mode)
754 {
755     rt_base_t level;
756 
757     if (module_id >= PM_MODULE_MAX_ID)
758     {
759         return -RT_EINVAL;
760     }
761 
762     if (mode >= (PM_SLEEP_MODE_MAX - 1))
763     {
764         return -RT_EINVAL;
765     }
766 
767     level = rt_hw_interrupt_disable();
768     _pm.sleep_status[mode][module_id / 32] &= ~(1 << (module_id % 32));
769     rt_hw_interrupt_enable(level);
770     return RT_EOK;
771 }
772 
773 /**
774  * The specified module release the requested PM_SLEEP_MODE_NONE mode
775  *
776  * @param module_id the pm module id
777  *
778  * @return none
779  */
rt_pm_sleep_none_release(rt_uint16_t module_id)780 rt_err_t rt_pm_sleep_none_release(rt_uint16_t module_id)
781 {
782     return rt_pm_sleep_release(module_id, PM_SLEEP_MODE_NONE);
783 }
784 
785 /**
786  * The specified module release the requested PM_SLEEP_MODE_IDLE mode
787  *
788  * @param module_id the pm module id
789  *
790  * @return none
791  */
rt_pm_sleep_idle_release(rt_uint16_t module_id)792 rt_err_t rt_pm_sleep_idle_release(rt_uint16_t module_id)
793 {
794     return rt_pm_sleep_release(module_id, PM_SLEEP_MODE_IDLE);
795 }
796 
797 /**
798  * The specified module release the requested PM_SLEEP_MODE_LIGHT mode
799  *
800  * @param module_id the pm module id
801  *
802  * @return none
803  */
rt_pm_sleep_light_release(rt_uint16_t module_id)804 rt_err_t rt_pm_sleep_light_release(rt_uint16_t module_id)
805 {
806     return rt_pm_sleep_release(module_id, PM_SLEEP_MODE_LIGHT);
807 }
808 
809 /**
810  * Register a device with PM feature
811  *
812  * @param device the device with PM feature
813  * @param ops the PM ops for device
814  */
rt_pm_device_register(struct rt_device * device,const struct rt_device_pm_ops * ops)815 void rt_pm_device_register(struct rt_device *device, const struct rt_device_pm_ops *ops)
816 {
817     struct rt_device_pm *device_pm;
818 
819     device_pm = RT_KERNEL_MALLOC(sizeof(struct rt_device_pm));
820     if (device_pm != RT_NULL)
821     {
822         rt_slist_append(&_pm.device_list, &device_pm->list);
823         device_pm->device = device;
824         device_pm->ops    = ops;
825     }
826 }
827 
828 /**
829  * Unregister device from PM manager.
830  *
831  * @param device the device with PM feature
832  */
rt_pm_device_unregister(struct rt_device * device)833 void rt_pm_device_unregister(struct rt_device *device)
834 {
835     struct rt_device_pm *device_pm = RT_NULL;
836     rt_slist_t *node = RT_NULL;
837     for (node = rt_slist_first(&_pm.device_list); node; node = rt_slist_next(node))
838     {
839         device_pm = rt_slist_entry(node, struct rt_device_pm, list);
840         if (device_pm->device == device)
841         {
842             rt_slist_remove(&_pm.device_list, &device_pm->list);
843             RT_KERNEL_FREE(device_pm);
844             break;
845         }
846     }
847 }
848 
849 /**
850  * This function set notification callback for application
851  */
rt_pm_notify_set(void (* notify)(rt_uint8_t event,rt_uint8_t mode,void * data),void * data)852 void rt_pm_notify_set(void (*notify)(rt_uint8_t event, rt_uint8_t mode, void *data), void *data)
853 {
854     _pm_notify.notify = notify;
855     _pm_notify.data = data;
856 }
857 
858 /**
859  * This function set default sleep mode when no pm_request
860  */
rt_pm_default_set(rt_uint8_t sleep_mode)861 void rt_pm_default_set(rt_uint8_t sleep_mode)
862 {
863     _pm_default_sleep = sleep_mode;
864 }
865 
866 /**
867  * RT-Thread device interface for PM device
868  */
_rt_pm_device_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)869 static rt_ssize_t _rt_pm_device_read(rt_device_t dev,
870                                     rt_off_t    pos,
871                                     void       *buffer,
872                                     rt_size_t   size)
873 {
874     struct rt_pm *pm;
875     rt_size_t length;
876 
877     length = 0;
878     pm = (struct rt_pm *)dev;
879     RT_ASSERT(pm != RT_NULL);
880 
881     if (pos < PM_SLEEP_MODE_MAX)
882     {
883         int mode;
884 
885         mode = pm->modes[pos];
886         length = rt_snprintf(buffer, size, "%d", mode);
887     }
888 
889     return length;
890 }
891 
_rt_pm_device_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)892 static rt_ssize_t _rt_pm_device_write(rt_device_t dev,
893                                      rt_off_t    pos,
894                                      const void *buffer,
895                                      rt_size_t   size)
896 {
897     unsigned char request;
898 
899     if (size)
900     {
901         /* get request */
902         request = *(unsigned char *)buffer;
903         if (request ==  0x01)
904         {
905             rt_pm_request(pos);
906         }
907         else if (request == 0x00)
908         {
909             rt_pm_release(pos);
910         }
911     }
912 
913     return 1;
914 }
915 
_rt_pm_device_control(rt_device_t dev,int cmd,void * args)916 static rt_err_t _rt_pm_device_control(rt_device_t dev,
917                                       int         cmd,
918                                       void       *args)
919 {
920     rt_uint32_t mode;
921 
922     switch (cmd)
923     {
924     case RT_PM_DEVICE_CTRL_REQUEST:
925         mode = (rt_uint32_t)(rt_ubase_t)args;
926         rt_pm_request(mode);
927         break;
928 
929     case RT_PM_DEVICE_CTRL_RELEASE:
930         mode = (rt_uint32_t)(rt_ubase_t)args;
931         rt_pm_release(mode);
932         break;
933     }
934 
935     return RT_EOK;
936 }
937 
rt_pm_run_enter(rt_uint8_t mode)938 rt_err_t rt_pm_run_enter(rt_uint8_t mode)
939 {
940     rt_base_t level = 0;
941     struct rt_pm *pm = RT_NULL;
942     rt_err_t ret = RT_EOK;
943 
944     if (_pm_init_flag == 0)
945         return -RT_EIO;
946 
947     if (mode > PM_RUN_MODE_MAX)
948         return -RT_EINVAL;
949 
950     pm = &_pm;
951 
952     level = rt_hw_interrupt_disable();
953     if (mode < pm->run_mode)
954     {
955         /* change system runing mode */
956         if(pm->ops != RT_NULL && pm->ops->run != RT_NULL)
957         {
958             pm->ops->run(pm, mode);
959         }
960         /* changer device frequency */
961         _pm_device_frequency_change(mode);
962     }
963     else
964     {
965         pm->flags |= RT_PM_FREQUENCY_PENDING;
966     }
967     pm->run_mode = mode;
968     rt_hw_interrupt_enable(level);
969 
970     return ret;
971 }
972 
973 #ifdef RT_USING_DEVICE_OPS
974 const static struct rt_device_ops pm_ops =
975 {
976     RT_NULL,
977     RT_NULL,
978     RT_NULL,
979     _rt_pm_device_read,
980     _rt_pm_device_write,
981     _rt_pm_device_control,
982 };
983 #endif
984 
985 /**
986  * This function will initialize power management.
987  *
988  * @param ops the PM operations.
989  * @param timer_mask indicates which mode has timer feature.
990  * @param user_data user data
991  */
rt_system_pm_init(const struct rt_pm_ops * ops,rt_uint8_t timer_mask,void * user_data)992 void rt_system_pm_init(const struct rt_pm_ops *ops,
993                        rt_uint8_t              timer_mask,
994                        void                   *user_data)
995 {
996     struct rt_device *device;
997     struct rt_pm *pm;
998 
999     pm = &_pm;
1000     device = &(_pm.parent);
1001 
1002     device->type        = RT_Device_Class_PM;
1003     device->rx_indicate = RT_NULL;
1004     device->tx_complete = RT_NULL;
1005 
1006 #ifdef RT_USING_DEVICE_OPS
1007     device->ops = &pm_ops;
1008 #else
1009     device->init        = RT_NULL;
1010     device->open        = RT_NULL;
1011     device->close       = RT_NULL;
1012     device->read        = _rt_pm_device_read;
1013     device->write       = _rt_pm_device_write;
1014     device->control     = _rt_pm_device_control;
1015 #endif
1016     device->user_data   = user_data;
1017 
1018     /* register PM device to the system */
1019     rt_device_register(device, "pm", RT_DEVICE_FLAG_RDWR);
1020 
1021     rt_memset(pm->modes, 0, sizeof(pm->modes));
1022     pm->sleep_mode = _pm_default_sleep;
1023 
1024     /* when system power on, set default sleep modes */
1025     pm->modes[pm->sleep_mode] = 1;
1026     pm->module_status[PM_POWER_ID].req_status = 1;
1027     pm->run_mode   = RT_PM_DEFAULT_RUN_MODE;
1028     pm->timer_mask = timer_mask;
1029 
1030     pm->ops = ops;
1031 
1032     pm->device_pm = RT_NULL;
1033 
1034     rt_slist_init(&pm->device_list);
1035 
1036 #if IDLE_THREAD_STACK_SIZE <= 256
1037     #error "[pm.c ERR] IDLE Stack Size Too Small!"
1038 #endif
1039 
1040     _pm_init_flag = 1;
1041 }
1042 
1043 #ifdef RT_USING_FINSH
1044 #include <finsh.h>
1045 
1046 static const char *_pm_sleep_str[] = PM_SLEEP_MODE_NAMES;
1047 static const char *_pm_run_str[] = PM_RUN_MODE_NAMES;
1048 
rt_pm_release_mode(int argc,char ** argv)1049 static void rt_pm_release_mode(int argc, char **argv)
1050 {
1051     int mode = 0;
1052     if (argc >= 2)
1053     {
1054         mode = atoi(argv[1]);
1055     }
1056 
1057     rt_pm_release(mode);
1058 }
1059 MSH_CMD_EXPORT_ALIAS(rt_pm_release_mode, pm_release, release power management mode);
1060 
rt_pm_release_mode_all(int argc,char ** argv)1061 static void rt_pm_release_mode_all(int argc, char **argv)
1062 {
1063     int mode = 0;
1064     if (argc >= 2)
1065     {
1066         mode = atoi(argv[1]);
1067     }
1068 
1069     rt_pm_release_all(mode);
1070 }
1071 MSH_CMD_EXPORT_ALIAS(rt_pm_release_mode_all, pm_release_all, release power management mode count);
1072 
rt_pm_request_mode(int argc,char ** argv)1073 static void rt_pm_request_mode(int argc, char **argv)
1074 {
1075     int mode = 0;
1076     if (argc >= 2)
1077     {
1078         mode = atoi(argv[1]);
1079     }
1080 
1081     rt_pm_request(mode);
1082 }
1083 MSH_CMD_EXPORT_ALIAS(rt_pm_request_mode, pm_request, request power management mode);
1084 
rt_module_release_mode(int argc,char ** argv)1085 static void rt_module_release_mode(int argc, char **argv)
1086 {
1087     int module = 0;
1088     int mode = 0;
1089 
1090     if (argc >= 3)
1091     {
1092         module = atoi(argv[1]);
1093         mode = atoi(argv[2]);
1094     }
1095 
1096     rt_pm_module_release(module, mode);
1097 }
1098 MSH_CMD_EXPORT_ALIAS(rt_module_release_mode, pm_module_release, release module power mode);
1099 
rt_module_release_mode_all(int argc,char ** argv)1100 static void rt_module_release_mode_all(int argc, char **argv)
1101 {
1102     int module = 0;
1103     int mode = 0;
1104 
1105     if (argc >= 3)
1106     {
1107         module = atoi(argv[1]);
1108         mode = atoi(argv[2]);
1109     }
1110 
1111     rt_pm_module_release_all(module, mode);
1112 }
1113 MSH_CMD_EXPORT_ALIAS(rt_module_release_mode_all, pm_module_release_all, release power management mode count);
1114 
rt_module_request_mode(int argc,char ** argv)1115 static void rt_module_request_mode(int argc, char **argv)
1116 {
1117     int module = 0;
1118     int mode = 0;
1119 
1120     if (argc >= 3)
1121     {
1122         module = atoi(argv[1]);
1123         mode = atoi(argv[2]);
1124     }
1125 
1126     rt_pm_module_request(module, mode);
1127 }
1128 MSH_CMD_EXPORT_ALIAS(rt_module_request_mode, pm_module_request, request power management mode);
1129 
rt_module_delay_sleep(int argc,char ** argv)1130 static void rt_module_delay_sleep(int argc, char **argv)
1131 {
1132     int module = 0;
1133     unsigned int timeout = 0;
1134 
1135     if (argc >= 3)
1136     {
1137         module = atoi(argv[1]);
1138         timeout = atoi(argv[2]);
1139     }
1140 
1141     rt_pm_module_delay_sleep(module, timeout);
1142 }
1143 MSH_CMD_EXPORT_ALIAS(rt_module_delay_sleep, pm_module_delay, module request delay sleep);
1144 
rt_pm_run_mode_switch(int argc,char ** argv)1145 static void rt_pm_run_mode_switch(int argc, char **argv)
1146 {
1147     int mode = 0;
1148     if (argc >= 2)
1149     {
1150         mode = atoi(argv[1]);
1151     }
1152 
1153     rt_pm_run_enter(mode);
1154 }
1155 MSH_CMD_EXPORT_ALIAS(rt_pm_run_mode_switch, pm_run, switch power management run mode);
1156 
rt_pm_module_get_status(void)1157 rt_uint32_t rt_pm_module_get_status(void)
1158 {
1159     rt_uint8_t index = 0;
1160     struct rt_pm *pm;
1161     rt_uint32_t req_status = 0x00;
1162     pm = &_pm;
1163 
1164     for (index = 0; index < PM_MODULE_MAX_ID; index ++)
1165     {
1166         if (pm->module_status[index].req_status == 0x01)
1167             req_status |= 1<<index;
1168     }
1169 
1170     return req_status;
1171 }
1172 
rt_pm_get_sleep_mode(void)1173 rt_uint8_t rt_pm_get_sleep_mode(void)
1174 {
1175     struct rt_pm *pm;
1176 
1177     pm = &_pm;
1178     return pm->sleep_mode;
1179 }
1180 
1181 /* get pm entity pointer */
rt_pm_get_handle(void)1182 struct rt_pm *rt_pm_get_handle(void)
1183 {
1184     return &_pm;
1185 }
1186 
1187 #ifdef PM_ENABLE_DEBUG
1188 /**
1189  * print current module sleep request list
1190  *
1191  * @param none
1192  *
1193  * @return none
1194  */
pm_sleep_dump(void)1195 void pm_sleep_dump(void)
1196 {
1197     uint8_t index;
1198     uint16_t len;
1199 
1200     rt_kprintf("+-------------+--------------+\n");
1201     rt_kprintf("| Sleep Mode  | Request List |\n");
1202     rt_kprintf("+-------------+--------------+\n");
1203     for (index = 0; index < PM_SLEEP_MODE_MAX -1; index++)
1204     {
1205         for (len = 0; len < ((PM_MODULE_MAX_ID + 31) / 32); len++)
1206         {
1207             rt_kprintf("| Mode[%d] : %d |  0x%08x  |\n", index, len,
1208                 _pm.sleep_status[index][len]);
1209         }
1210     }
1211     rt_kprintf("+-------------+--------------+\n");
1212 }
1213 MSH_CMD_EXPORT(pm_sleep_dump, dump pm request list);
1214 
pm_sleep_request(int argc,char ** argv)1215 static void pm_sleep_request(int argc, char **argv)
1216 {
1217     int module = 0;
1218     int mode = 0;
1219 
1220     if (argc >= 3)
1221     {
1222         module = atoi(argv[1]);
1223         mode = atoi(argv[2]);
1224         rt_pm_sleep_request(module, mode);
1225     }
1226 }
1227 MSH_CMD_EXPORT(pm_sleep_request, pm_sleep_request module sleep_mode);
1228 
pm_sleep_release(int argc,char ** argv)1229 static void pm_sleep_release(int argc, char **argv)
1230 {
1231     int module = 0;
1232     int mode = 0;
1233 
1234     if (argc >= 3)
1235     {
1236         module = atoi(argv[1]);
1237         mode = atoi(argv[2]);
1238         rt_pm_sleep_release(module, mode);
1239     }
1240 }
1241 MSH_CMD_EXPORT(pm_sleep_release, pm_sleep_release module sleep_mode);
1242 #endif
1243 
rt_pm_dump_status(void)1244 static void rt_pm_dump_status(void)
1245 {
1246     rt_uint32_t index;
1247     struct rt_pm *pm;
1248 
1249     pm = &_pm;
1250 
1251     rt_kprintf("| Power Management Mode | Counter | Timer |\n");
1252     rt_kprintf("+-----------------------+---------+-------+\n");
1253     for (index = 0; index < PM_SLEEP_MODE_MAX; index ++)
1254     {
1255         int has_timer = 0;
1256         if (pm->timer_mask & (1 << index))
1257             has_timer = 1;
1258 
1259         rt_kprintf("| %021s | %7d | %5d |\n", _pm_sleep_str[index], pm->modes[index], has_timer);
1260     }
1261     rt_kprintf("+-----------------------+---------+-------+\n");
1262 
1263     rt_kprintf("pm current sleep mode: %s\n", _pm_sleep_str[pm->sleep_mode]);
1264     rt_kprintf("pm current run mode:   %s\n", _pm_run_str[pm->run_mode]);
1265 
1266     rt_kprintf("\n");
1267     rt_kprintf("| module | busy | start time |  timeout  |\n");
1268     rt_kprintf("+--------+------+------------+-----------+\n");
1269     for (index = 0; index < PM_MODULE_MAX_ID; index ++)
1270     {
1271         if ((pm->module_status[index].busy_flag == RT_TRUE) ||
1272             (pm->module_status[index].req_status != 0x00))
1273         {
1274             rt_kprintf("|  %04d  |  %d   | 0x%08x | 0x%08x |\n",
1275                 index, pm->module_status[index].busy_flag,
1276                 pm->module_status[index].start_time,
1277                 pm->module_status[index].timeout);
1278         }
1279     }
1280     rt_kprintf("+--------+------+------------+-----------+\n");
1281 }
1282 FINSH_FUNCTION_EXPORT_ALIAS(rt_pm_dump_status, pm_dump, dump power management status);
1283 MSH_CMD_EXPORT_ALIAS(rt_pm_dump_status, pm_dump, dump power management status);
1284 #endif
1285 
1286 #endif /* RT_USING_PM */
1287