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