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