xref: /nrf52832-nimble/rt-thread/components/drivers/pm/pm.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero  *
4*10465441SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero  *
6*10465441SEvalZero  * Change Logs:
7*10465441SEvalZero  * Date           Author       Notes
8*10465441SEvalZero  * 2012-06-02     Bernard      the first version
9*10465441SEvalZero  * 2018-08-02     Tanek        split run and sleep modes, support custom mode
10*10465441SEvalZero  */
11*10465441SEvalZero 
12*10465441SEvalZero #include <rthw.h>
13*10465441SEvalZero #include <rtthread.h>
14*10465441SEvalZero #include <drivers/pm.h>
15*10465441SEvalZero 
16*10465441SEvalZero #ifdef RT_USING_PM
17*10465441SEvalZero 
18*10465441SEvalZero static struct rt_pm _pm;
19*10465441SEvalZero 
20*10465441SEvalZero /**
21*10465441SEvalZero  * This function will suspend all registered devices
22*10465441SEvalZero  */
_pm_device_suspend(void)23*10465441SEvalZero static void _pm_device_suspend(void)
24*10465441SEvalZero {
25*10465441SEvalZero     int index;
26*10465441SEvalZero 
27*10465441SEvalZero     for (index = 0; index < _pm.device_pm_number; index++)
28*10465441SEvalZero     {
29*10465441SEvalZero         if (_pm.device_pm[index].ops->suspend != RT_NULL)
30*10465441SEvalZero         {
31*10465441SEvalZero             _pm.device_pm[index].ops->suspend(_pm.device_pm[index].device);
32*10465441SEvalZero         }
33*10465441SEvalZero     }
34*10465441SEvalZero }
35*10465441SEvalZero 
36*10465441SEvalZero /**
37*10465441SEvalZero  * This function will resume all registered devices
38*10465441SEvalZero  */
_pm_device_resume(void)39*10465441SEvalZero static void _pm_device_resume(void)
40*10465441SEvalZero {
41*10465441SEvalZero     int index;
42*10465441SEvalZero 
43*10465441SEvalZero     for (index = 0; index < _pm.device_pm_number; index++)
44*10465441SEvalZero     {
45*10465441SEvalZero         if (_pm.device_pm[index].ops->resume != RT_NULL)
46*10465441SEvalZero         {
47*10465441SEvalZero             _pm.device_pm[index].ops->resume(_pm.device_pm[index].device);
48*10465441SEvalZero         }
49*10465441SEvalZero     }
50*10465441SEvalZero }
51*10465441SEvalZero 
52*10465441SEvalZero #if PM_RUN_MODE_COUNT > 1
53*10465441SEvalZero /**
54*10465441SEvalZero  * This function will update the frequency of all registered devices
55*10465441SEvalZero  */
_pm_device_frequency_change(void)56*10465441SEvalZero static void _pm_device_frequency_change(void)
57*10465441SEvalZero {
58*10465441SEvalZero     rt_uint32_t index;
59*10465441SEvalZero 
60*10465441SEvalZero     /* make the frequency change */
61*10465441SEvalZero     for (index = 0; index < _pm.device_pm_number; index ++)
62*10465441SEvalZero     {
63*10465441SEvalZero         if (_pm.device_pm[index].ops->frequency_change != RT_NULL)
64*10465441SEvalZero             _pm.device_pm[index].ops->frequency_change(_pm.device_pm[index].device);
65*10465441SEvalZero     }
66*10465441SEvalZero }
67*10465441SEvalZero #endif
68*10465441SEvalZero 
69*10465441SEvalZero /**
70*10465441SEvalZero  * This function will enter corresponding power mode.
71*10465441SEvalZero  */
rt_pm_enter(void)72*10465441SEvalZero void rt_pm_enter(void)
73*10465441SEvalZero {
74*10465441SEvalZero     rt_ubase_t level;
75*10465441SEvalZero     struct rt_pm *pm;
76*10465441SEvalZero     rt_uint32_t index;
77*10465441SEvalZero     rt_tick_t timeout_tick;
78*10465441SEvalZero 
79*10465441SEvalZero     pm = &_pm;
80*10465441SEvalZero 
81*10465441SEvalZero     /* disable interrupt before check run modes */
82*10465441SEvalZero     level = rt_hw_interrupt_disable();
83*10465441SEvalZero     /* check each run mode, and decide to swithc to run mode or sleep mode */
84*10465441SEvalZero     for (index = 0; index < PM_RUN_MODE_COUNT; index++)
85*10465441SEvalZero     {
86*10465441SEvalZero         if (pm->modes[index])
87*10465441SEvalZero         {
88*10465441SEvalZero             if (index > pm->current_mode)
89*10465441SEvalZero             {
90*10465441SEvalZero                 pm->ops->exit(pm);
91*10465441SEvalZero                 pm->current_mode = index;
92*10465441SEvalZero                 pm->ops->enter(pm);
93*10465441SEvalZero #if PM_RUN_MODE_COUNT > 1
94*10465441SEvalZero                 pm->ops->frequency_change(pm, 0);
95*10465441SEvalZero                 _pm_device_frequency_change();
96*10465441SEvalZero #endif
97*10465441SEvalZero             }
98*10465441SEvalZero 
99*10465441SEvalZero             rt_hw_interrupt_enable(level);
100*10465441SEvalZero             /* The current mode is run mode, no need to check sleep mode */
101*10465441SEvalZero             return ;
102*10465441SEvalZero         }
103*10465441SEvalZero     }
104*10465441SEvalZero     /* enable interrupt after check run modes */
105*10465441SEvalZero     rt_hw_interrupt_enable(level);
106*10465441SEvalZero 
107*10465441SEvalZero     level = rt_hw_interrupt_disable();
108*10465441SEvalZero     /* check each sleep mode to decide which mode can system sleep. */
109*10465441SEvalZero     for (index = PM_SLEEP_MODE_START; index < PM_SLEEP_MODE_START + PM_SLEEP_MODE_COUNT; index++)
110*10465441SEvalZero     {
111*10465441SEvalZero         if (pm->modes[index])
112*10465441SEvalZero         {
113*10465441SEvalZero             /* let mcu sleep when system is idle */
114*10465441SEvalZero 
115*10465441SEvalZero             /* run mode to sleep mode */
116*10465441SEvalZero             if (pm->current_mode < PM_SLEEP_MODE_START)
117*10465441SEvalZero             {
118*10465441SEvalZero                 /* exit run mode */
119*10465441SEvalZero                 pm->ops->exit(pm);
120*10465441SEvalZero             }
121*10465441SEvalZero 
122*10465441SEvalZero             /* set current power mode */
123*10465441SEvalZero             pm->current_mode = index;
124*10465441SEvalZero             pm->exit_count = 1;
125*10465441SEvalZero 
126*10465441SEvalZero             /* suspend all of devices with PM feature */
127*10465441SEvalZero             _pm_device_suspend();
128*10465441SEvalZero 
129*10465441SEvalZero             /* should start pm timer */
130*10465441SEvalZero             if (pm->timer_mask & (1 << index))
131*10465441SEvalZero             {
132*10465441SEvalZero                 /* get next os tick */
133*10465441SEvalZero                 timeout_tick = rt_timer_next_timeout_tick();
134*10465441SEvalZero                 if (timeout_tick != RT_TICK_MAX)
135*10465441SEvalZero                 {
136*10465441SEvalZero                     timeout_tick -= rt_tick_get();
137*10465441SEvalZero 
138*10465441SEvalZero #if defined(PM_MIN_ENTER_SLEEP_TICK) && PM_MIN_ENTER_SLEEP_TICK > 0
139*10465441SEvalZero                     if (timeout_tick < PM_MIN_ENTER_SLEEP_TICK)
140*10465441SEvalZero                     {
141*10465441SEvalZero                         rt_hw_interrupt_enable(level);
142*10465441SEvalZero                         /* limit the minimum time to enter timer sleep mode */
143*10465441SEvalZero                         return ;
144*10465441SEvalZero                     }
145*10465441SEvalZero #endif
146*10465441SEvalZero                 }
147*10465441SEvalZero                 /* startup pm timer */
148*10465441SEvalZero                 pm->ops->timer_start(pm, timeout_tick);
149*10465441SEvalZero             }
150*10465441SEvalZero 
151*10465441SEvalZero             /* enter sleep and wait to be waken up */
152*10465441SEvalZero             pm->ops->enter(pm);
153*10465441SEvalZero 
154*10465441SEvalZero             /* exit from low power mode */
155*10465441SEvalZero             rt_pm_exit();
156*10465441SEvalZero 
157*10465441SEvalZero             rt_hw_interrupt_enable(level);
158*10465441SEvalZero             return ;
159*10465441SEvalZero         }
160*10465441SEvalZero     }
161*10465441SEvalZero 
162*10465441SEvalZero     rt_hw_interrupt_enable(level);
163*10465441SEvalZero }
164*10465441SEvalZero 
165*10465441SEvalZero /**
166*10465441SEvalZero  * This function exits from sleep mode.
167*10465441SEvalZero  */
rt_pm_exit(void)168*10465441SEvalZero void rt_pm_exit(void)
169*10465441SEvalZero {
170*10465441SEvalZero     rt_ubase_t level;
171*10465441SEvalZero     struct rt_pm *pm;
172*10465441SEvalZero     rt_tick_t delta_tick;
173*10465441SEvalZero 
174*10465441SEvalZero     pm = &_pm;
175*10465441SEvalZero 
176*10465441SEvalZero     level = rt_hw_interrupt_disable();
177*10465441SEvalZero 
178*10465441SEvalZero     if (pm->exit_count)
179*10465441SEvalZero     {
180*10465441SEvalZero         pm->exit_count = 0;
181*10465441SEvalZero 
182*10465441SEvalZero         if (pm->current_mode >= PM_SLEEP_MODE_START)
183*10465441SEvalZero         {
184*10465441SEvalZero             /* sleep mode with timer */
185*10465441SEvalZero             if (pm->timer_mask & (1 << pm->current_mode))
186*10465441SEvalZero             {
187*10465441SEvalZero                 /* get the tick of pm timer */
188*10465441SEvalZero                 delta_tick = pm->ops->timer_get_tick(pm);
189*10465441SEvalZero 
190*10465441SEvalZero                 /* stop pm timer */
191*10465441SEvalZero                 pm->ops->timer_stop(pm);
192*10465441SEvalZero 
193*10465441SEvalZero                 if (delta_tick)
194*10465441SEvalZero                 {
195*10465441SEvalZero                     /* adjust OS tick */
196*10465441SEvalZero                     rt_tick_set(rt_tick_get() + delta_tick);
197*10465441SEvalZero                     /* check system timer */
198*10465441SEvalZero                     rt_timer_check();
199*10465441SEvalZero                 }
200*10465441SEvalZero             }
201*10465441SEvalZero 
202*10465441SEvalZero             /* exit from sleep mode */
203*10465441SEvalZero             pm->ops->exit(pm);
204*10465441SEvalZero             /* resume the device with PM feature */
205*10465441SEvalZero             _pm_device_resume();
206*10465441SEvalZero         }
207*10465441SEvalZero     }
208*10465441SEvalZero 
209*10465441SEvalZero     rt_hw_interrupt_enable(level);
210*10465441SEvalZero }
211*10465441SEvalZero 
212*10465441SEvalZero /**
213*10465441SEvalZero  * Upper application or device driver requests the system
214*10465441SEvalZero  * stall in corresponding power mode.
215*10465441SEvalZero  *
216*10465441SEvalZero  * @param parameter the parameter of run mode or sleep mode
217*10465441SEvalZero  */
rt_pm_request(rt_ubase_t mode)218*10465441SEvalZero void rt_pm_request(rt_ubase_t mode)
219*10465441SEvalZero {
220*10465441SEvalZero     rt_ubase_t level;
221*10465441SEvalZero     struct rt_pm *pm;
222*10465441SEvalZero 
223*10465441SEvalZero     pm = &_pm;
224*10465441SEvalZero 
225*10465441SEvalZero     if (mode > PM_MODE_MAX)
226*10465441SEvalZero         return;
227*10465441SEvalZero 
228*10465441SEvalZero     level = rt_hw_interrupt_disable();
229*10465441SEvalZero 
230*10465441SEvalZero     /* update pm modes table */
231*10465441SEvalZero     pm->modes[mode] ++;
232*10465441SEvalZero 
233*10465441SEvalZero     /* request higter mode with a smaller mode value*/
234*10465441SEvalZero     if (mode < pm->current_mode)
235*10465441SEvalZero     {
236*10465441SEvalZero         /* the old current mode is RUN mode, need to all pm->ops->exit(),
237*10465441SEvalZero          * if not, it has already called in rt_pm_exit()
238*10465441SEvalZero          */
239*10465441SEvalZero         if (pm->current_mode < PM_SLEEP_MODE_START)
240*10465441SEvalZero         {
241*10465441SEvalZero             pm->ops->exit(pm);
242*10465441SEvalZero         }
243*10465441SEvalZero         else if (pm->exit_count)
244*10465441SEvalZero         {
245*10465441SEvalZero             /* call exeit when global interrupt is disable */
246*10465441SEvalZero             pm->ops->exit(pm);
247*10465441SEvalZero             pm->exit_count = 0;
248*10465441SEvalZero         }
249*10465441SEvalZero 
250*10465441SEvalZero         /* update current mode */
251*10465441SEvalZero         pm->current_mode = mode;
252*10465441SEvalZero 
253*10465441SEvalZero         /* current mode is higher run mode */
254*10465441SEvalZero         if (mode < PM_SLEEP_MODE_START)
255*10465441SEvalZero         {
256*10465441SEvalZero             /* enter run mode */
257*10465441SEvalZero             pm->ops->enter(pm);
258*10465441SEvalZero #if PM_RUN_MODE_COUNT > 1
259*10465441SEvalZero             /* frequency change */
260*10465441SEvalZero             pm->ops->frequency_change(pm, 0);
261*10465441SEvalZero             _pm_device_frequency_change();
262*10465441SEvalZero #endif
263*10465441SEvalZero         }
264*10465441SEvalZero         else
265*10465441SEvalZero         {
266*10465441SEvalZero             /* do nothing when request higher sleep mode,
267*10465441SEvalZero              * and swithc to new sleep mode in rt_pm_enter()
268*10465441SEvalZero              */
269*10465441SEvalZero         }
270*10465441SEvalZero     }
271*10465441SEvalZero 
272*10465441SEvalZero     rt_hw_interrupt_enable(level);
273*10465441SEvalZero }
274*10465441SEvalZero 
275*10465441SEvalZero /**
276*10465441SEvalZero  * Upper application or device driver releases the stall
277*10465441SEvalZero  * of corresponding power mode.
278*10465441SEvalZero  *
279*10465441SEvalZero  * @param parameter the parameter of run mode or sleep mode
280*10465441SEvalZero  *
281*10465441SEvalZero  */
rt_pm_release(rt_ubase_t mode)282*10465441SEvalZero void rt_pm_release(rt_ubase_t mode)
283*10465441SEvalZero {
284*10465441SEvalZero     rt_ubase_t level;
285*10465441SEvalZero     struct rt_pm *pm;
286*10465441SEvalZero 
287*10465441SEvalZero     pm = &_pm;
288*10465441SEvalZero 
289*10465441SEvalZero     if (mode > PM_MODE_MAX)
290*10465441SEvalZero         return;
291*10465441SEvalZero 
292*10465441SEvalZero     level = rt_hw_interrupt_disable();
293*10465441SEvalZero 
294*10465441SEvalZero     if (pm->modes[mode] > 0)
295*10465441SEvalZero         pm->modes[mode] --;
296*10465441SEvalZero 
297*10465441SEvalZero     rt_hw_interrupt_enable(level);
298*10465441SEvalZero }
299*10465441SEvalZero 
300*10465441SEvalZero /**
301*10465441SEvalZero  * Register a device with PM feature
302*10465441SEvalZero  *
303*10465441SEvalZero  * @param device the device with PM feature
304*10465441SEvalZero  * @param ops the PM ops for device
305*10465441SEvalZero  */
rt_pm_register_device(struct rt_device * device,const struct rt_device_pm_ops * ops)306*10465441SEvalZero void rt_pm_register_device(struct rt_device *device, const struct rt_device_pm_ops *ops)
307*10465441SEvalZero {
308*10465441SEvalZero     rt_ubase_t level;
309*10465441SEvalZero     struct rt_device_pm *device_pm;
310*10465441SEvalZero 
311*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
312*10465441SEvalZero 
313*10465441SEvalZero     level = rt_hw_interrupt_disable();
314*10465441SEvalZero 
315*10465441SEvalZero     device_pm = (struct rt_device_pm *)RT_KERNEL_REALLOC(_pm.device_pm,
316*10465441SEvalZero                 (_pm.device_pm_number + 1) * sizeof(struct rt_device_pm));
317*10465441SEvalZero     if (device_pm != RT_NULL)
318*10465441SEvalZero     {
319*10465441SEvalZero         _pm.device_pm = device_pm;
320*10465441SEvalZero         _pm.device_pm[_pm.device_pm_number].device = device;
321*10465441SEvalZero         _pm.device_pm[_pm.device_pm_number].ops    = ops;
322*10465441SEvalZero         _pm.device_pm_number += 1;
323*10465441SEvalZero     }
324*10465441SEvalZero 
325*10465441SEvalZero     rt_sem_release(&(_pm.device_lock));
326*10465441SEvalZero 
327*10465441SEvalZero     rt_hw_interrupt_enable(level);
328*10465441SEvalZero }
329*10465441SEvalZero 
330*10465441SEvalZero /**
331*10465441SEvalZero  * Unregister device from PM manager.
332*10465441SEvalZero  *
333*10465441SEvalZero  * @param device the device with PM feature
334*10465441SEvalZero  */
rt_pm_unregister_device(struct rt_device * device)335*10465441SEvalZero void rt_pm_unregister_device(struct rt_device *device)
336*10465441SEvalZero {
337*10465441SEvalZero     rt_ubase_t level;
338*10465441SEvalZero     rt_uint32_t index;
339*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
340*10465441SEvalZero 
341*10465441SEvalZero     level = rt_hw_interrupt_disable();
342*10465441SEvalZero 
343*10465441SEvalZero     for (index = 0; index < _pm.device_pm_number; index ++)
344*10465441SEvalZero     {
345*10465441SEvalZero         if (_pm.device_pm[index].device == device)
346*10465441SEvalZero         {
347*10465441SEvalZero             /* remove current entry */
348*10465441SEvalZero             for (; index < _pm.device_pm_number - 1; index ++)
349*10465441SEvalZero             {
350*10465441SEvalZero                 _pm.device_pm[index] = _pm.device_pm[index + 1];
351*10465441SEvalZero             }
352*10465441SEvalZero 
353*10465441SEvalZero             _pm.device_pm[_pm.device_pm_number - 1].device = RT_NULL;
354*10465441SEvalZero             _pm.device_pm[_pm.device_pm_number - 1].ops = RT_NULL;
355*10465441SEvalZero 
356*10465441SEvalZero             _pm.device_pm_number -= 1;
357*10465441SEvalZero             /* break out and not touch memory */
358*10465441SEvalZero             break;
359*10465441SEvalZero         }
360*10465441SEvalZero     }
361*10465441SEvalZero 
362*10465441SEvalZero     rt_hw_interrupt_enable(level);
363*10465441SEvalZero }
364*10465441SEvalZero 
365*10465441SEvalZero /**
366*10465441SEvalZero  * RT-Thread device interface for PM device
367*10465441SEvalZero  */
_rt_pm_device_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)368*10465441SEvalZero static rt_size_t _rt_pm_device_read(rt_device_t dev,
369*10465441SEvalZero                                     rt_off_t    pos,
370*10465441SEvalZero                                     void       *buffer,
371*10465441SEvalZero                                     rt_size_t   size)
372*10465441SEvalZero {
373*10465441SEvalZero     struct rt_pm *pm;
374*10465441SEvalZero     rt_size_t length;
375*10465441SEvalZero 
376*10465441SEvalZero     length = 0;
377*10465441SEvalZero     pm = (struct rt_pm *)dev;
378*10465441SEvalZero     RT_ASSERT(pm != RT_NULL);
379*10465441SEvalZero 
380*10465441SEvalZero     if (pos <= PM_MODE_MAX)
381*10465441SEvalZero     {
382*10465441SEvalZero         int mode;
383*10465441SEvalZero 
384*10465441SEvalZero         mode = pm->modes[pos];
385*10465441SEvalZero         length = rt_snprintf(buffer, size, "%d", mode);
386*10465441SEvalZero     }
387*10465441SEvalZero 
388*10465441SEvalZero     return length;
389*10465441SEvalZero }
390*10465441SEvalZero 
_rt_pm_device_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)391*10465441SEvalZero static rt_size_t _rt_pm_device_write(rt_device_t dev,
392*10465441SEvalZero                                      rt_off_t    pos,
393*10465441SEvalZero                                      const void *buffer,
394*10465441SEvalZero                                      rt_size_t   size)
395*10465441SEvalZero {
396*10465441SEvalZero     unsigned char request;
397*10465441SEvalZero 
398*10465441SEvalZero     if (size)
399*10465441SEvalZero     {
400*10465441SEvalZero         /* get request */
401*10465441SEvalZero         request = *(unsigned char *)buffer;
402*10465441SEvalZero         if (request == '1')
403*10465441SEvalZero         {
404*10465441SEvalZero             rt_pm_request(pos);
405*10465441SEvalZero         }
406*10465441SEvalZero         else if (request == '0')
407*10465441SEvalZero         {
408*10465441SEvalZero             rt_pm_release(pos);
409*10465441SEvalZero         }
410*10465441SEvalZero     }
411*10465441SEvalZero 
412*10465441SEvalZero     return 1;
413*10465441SEvalZero }
414*10465441SEvalZero 
_rt_pm_device_control(rt_device_t dev,int cmd,void * args)415*10465441SEvalZero static rt_err_t _rt_pm_device_control(rt_device_t dev,
416*10465441SEvalZero                                       int         cmd,
417*10465441SEvalZero                                       void       *args)
418*10465441SEvalZero {
419*10465441SEvalZero     rt_uint32_t mode;
420*10465441SEvalZero 
421*10465441SEvalZero     switch (cmd)
422*10465441SEvalZero     {
423*10465441SEvalZero     case RT_PM_DEVICE_CTRL_REQUEST:
424*10465441SEvalZero         mode = (rt_uint32_t)args;
425*10465441SEvalZero         rt_pm_request(mode);
426*10465441SEvalZero         break;
427*10465441SEvalZero 
428*10465441SEvalZero     case RT_PM_DEVICE_CTRL_RELEASE:
429*10465441SEvalZero         mode = (rt_uint32_t)args;
430*10465441SEvalZero         rt_pm_release(mode);
431*10465441SEvalZero         break;
432*10465441SEvalZero     }
433*10465441SEvalZero 
434*10465441SEvalZero     return RT_EOK;
435*10465441SEvalZero }
436*10465441SEvalZero 
437*10465441SEvalZero /**
438*10465441SEvalZero  * This function will initialize power management.
439*10465441SEvalZero  *
440*10465441SEvalZero  * @param ops the PM operations.
441*10465441SEvalZero  * @param timer_mask indicates which mode has timer feature.
442*10465441SEvalZero  * @param user_data user data
443*10465441SEvalZero  */
rt_system_pm_init(const struct rt_pm_ops * ops,rt_uint8_t timer_mask,void * user_data)444*10465441SEvalZero void rt_system_pm_init(const struct rt_pm_ops *ops,
445*10465441SEvalZero                        rt_uint8_t              timer_mask,
446*10465441SEvalZero                        void                   *user_data)
447*10465441SEvalZero {
448*10465441SEvalZero     struct rt_device *device;
449*10465441SEvalZero     struct rt_pm *pm;
450*10465441SEvalZero 
451*10465441SEvalZero     pm = &_pm;
452*10465441SEvalZero     device = &(_pm.parent);
453*10465441SEvalZero 
454*10465441SEvalZero     device->type        = RT_Device_Class_PM;
455*10465441SEvalZero     device->rx_indicate = RT_NULL;
456*10465441SEvalZero     device->tx_complete = RT_NULL;
457*10465441SEvalZero 
458*10465441SEvalZero     device->init        = RT_NULL;
459*10465441SEvalZero     device->open        = RT_NULL;
460*10465441SEvalZero     device->close       = RT_NULL;
461*10465441SEvalZero     device->read        = _rt_pm_device_read;
462*10465441SEvalZero     device->write       = _rt_pm_device_write;
463*10465441SEvalZero     device->control     = _rt_pm_device_control;
464*10465441SEvalZero     device->user_data   = user_data;
465*10465441SEvalZero 
466*10465441SEvalZero     /* register PM device to the system */
467*10465441SEvalZero     rt_device_register(device, "pm", RT_DEVICE_FLAG_RDWR);
468*10465441SEvalZero 
469*10465441SEvalZero     /* todo : add to kernel source code */
470*10465441SEvalZero     rt_thread_idle_sethook(rt_pm_enter);
471*10465441SEvalZero 
472*10465441SEvalZero     rt_memset(pm->modes, 0, sizeof(pm->modes));
473*10465441SEvalZero     pm->current_mode = PM_RUN_MODE_DEFAULT;
474*10465441SEvalZero 
475*10465441SEvalZero     pm->timer_mask = timer_mask;
476*10465441SEvalZero 
477*10465441SEvalZero     pm->ops = ops;
478*10465441SEvalZero 
479*10465441SEvalZero     pm->device_pm = RT_NULL;
480*10465441SEvalZero     pm->device_pm_number = 0;
481*10465441SEvalZero 
482*10465441SEvalZero     /* initialize semaphore */
483*10465441SEvalZero     rt_sem_init(&(pm->device_lock), "pm", 1, RT_IPC_FLAG_FIFO);
484*10465441SEvalZero 
485*10465441SEvalZero     /* request in default running mode */
486*10465441SEvalZero     rt_pm_request(PM_RUN_MODE_DEFAULT);
487*10465441SEvalZero 
488*10465441SEvalZero #ifdef PM_SLEEP_MODE_DEFAULT
489*10465441SEvalZero     /* request in default sleep mode */
490*10465441SEvalZero     rt_pm_request(PM_SLEEP_MODE_DEFAULT);
491*10465441SEvalZero #endif
492*10465441SEvalZero 
493*10465441SEvalZero     /* must hold on deep shutdown mode */
494*10465441SEvalZero     rt_pm_request(PM_MODE_MAX);
495*10465441SEvalZero }
496*10465441SEvalZero 
497*10465441SEvalZero #ifdef RT_USING_FINSH
498*10465441SEvalZero #include <finsh.h>
499*10465441SEvalZero 
rt_pm_release_mode(int argc,char ** argv)500*10465441SEvalZero static void rt_pm_release_mode(int argc, char **argv)
501*10465441SEvalZero {
502*10465441SEvalZero     int mode = 0;
503*10465441SEvalZero     if (argc >= 2)
504*10465441SEvalZero     {
505*10465441SEvalZero         mode = atoi(argv[1]);
506*10465441SEvalZero     }
507*10465441SEvalZero 
508*10465441SEvalZero     rt_pm_release(mode);
509*10465441SEvalZero }
510*10465441SEvalZero MSH_CMD_EXPORT_ALIAS(rt_pm_release_mode, pm_release, release power management mode);
511*10465441SEvalZero 
rt_pm_request_mode(int argc,char ** argv)512*10465441SEvalZero static void rt_pm_request_mode(int argc, char **argv)
513*10465441SEvalZero {
514*10465441SEvalZero     int mode = 0;
515*10465441SEvalZero     if (argc >= 2)
516*10465441SEvalZero     {
517*10465441SEvalZero         mode = atoi(argv[1]);
518*10465441SEvalZero     }
519*10465441SEvalZero 
520*10465441SEvalZero     rt_pm_request(mode);
521*10465441SEvalZero }
522*10465441SEvalZero MSH_CMD_EXPORT_ALIAS(rt_pm_request_mode, pm_request, request power management mode);
523*10465441SEvalZero 
rt_pm_dump_status(void)524*10465441SEvalZero static void rt_pm_dump_status(void)
525*10465441SEvalZero {
526*10465441SEvalZero     static const char *pm_str[] = PM_MODE_NAMES;
527*10465441SEvalZero     rt_uint32_t index;
528*10465441SEvalZero     struct rt_pm *pm;
529*10465441SEvalZero 
530*10465441SEvalZero     pm = &_pm;
531*10465441SEvalZero 
532*10465441SEvalZero     rt_kprintf("| Power Management Mode | Counter | Timer |\n");
533*10465441SEvalZero     rt_kprintf("+-----------------------+---------+-------+\n");
534*10465441SEvalZero     for (index = 0; index <= PM_MODE_MAX; index ++)
535*10465441SEvalZero     {
536*10465441SEvalZero         int has_timer = 0;
537*10465441SEvalZero         if (pm->timer_mask & (1 << index))
538*10465441SEvalZero             has_timer = 1;
539*10465441SEvalZero 
540*10465441SEvalZero         rt_kprintf("| %021s | %7d | %5d |\n", pm_str[index], pm->modes[index], has_timer);
541*10465441SEvalZero     }
542*10465441SEvalZero     rt_kprintf("+-----------------------+---------+-------+\n");
543*10465441SEvalZero 
544*10465441SEvalZero     rt_kprintf("pm current mode: %s\n", pm_str[pm->current_mode]);
545*10465441SEvalZero }
546*10465441SEvalZero FINSH_FUNCTION_EXPORT_ALIAS(rt_pm_dump_status, pm_dump, dump power management status);
547*10465441SEvalZero MSH_CMD_EXPORT_ALIAS(rt_pm_dump_status, pm_dump, dump power management status);
548*10465441SEvalZero #endif
549*10465441SEvalZero 
550*10465441SEvalZero #endif /* RT_USING_PM */
551