EVE 1.0
pm.h
Go to the documentation of this file.
1 #ifndef EVE_PM_H_INCLUDED
2 #define EVE_PM_H_INCLUDED
3 /**********************************************************************/
4 /*
5  * Copyright (c) 2013-2015, Jetro AS
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without modification,
9  * are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice,
12  * this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  * derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONRIBUTORS ``AS IS'' AND ANY EXPRESS
20  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
22  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
24  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
28  * OF SUCH DAMAGE.
29  *
30  * This file is part of the EVE platform.
31  */
32 
33  /**
34  * \file
35  * \brief Header file for the EVE power management framework.
36  *
37  * \author DT, Jetro AS
38  */ /******************************************************************/
39 
40 /* #define DEBUG_PM */
41 
42 #include <stdbool.h>
43 #ifdef DEBUG_PM
44 #include <lib/dlist.h>
45 #endif
46 
47 /**
48  * \addtogroup pm
49  * @{
50  * EVE power management framework
51  */
52 
53 /**********************************************************************/
54 /**
55  * System power level.
56  */
58 {
59  PM_LEVEL_RUNNING, /**< System is kept spinning when idle. Høyest power consumption. */
60  PM_LEVEL_CONSTLAT, /**< System ON, Constant latency mode. */
61  PM_LEVEL_LOWPWR, /**< System ON, Low power mode. */
62  PM_LEVEL_CLOCKLESS, /**< System ON, Low power mode, 32 kHz clock off. */
63  PM_LEVEL_OFF, /**< System OFF. */
64  PM_LEVEL__COUNT, /**< Number of elements in the \ref pm_level_t enum. */
65 };
66 
67 /**********************************************************************/
68 /**
69  * System power lock structure.
70  *
71  * The power lock structure represents a request for a power level the system
72  * should be kept on while CPU is in idle.
73  *
74  * The structure must be instantiated in the RAM memory using
75  * one of \ref PM_LOCK_INIT() or \ref DECLARE_PM_LOCK().
76  * Note that the power request is not active unless \ref PM_LOCK() is called for it.
77  */
78 struct pm_lock_t
79 {
80 #ifdef DEBUG_PM
81  struct dlist_t link; /**< Linked list of all locked requests at all lock levels. */
82  const char *file; /**< Debug field: file name the lock was touched last time in. */
83  int line; /**< Debug field: line number the lock was touched last time at. */
84 #endif
85  struct pm_lock_t *next; /**< Linked list of the unlocked requests waiting for suspend. */
86  bool (*ready_cb)(uint32_t data); /**< Ready callback. \see PM_UNLOCK(), \see pm_relax() for details. */
87  uint32_t data; /**< User data for the ready callback */
88  uint8_t level; /**< \ref pm_level_t, the given power level */
89  uint8_t locked; /**< Lock counter for the lock request */
90 };
91 
92 /**********************************************************************/
93 /** \def PM_LOCK_INIT(l, pm, cb, d)
94  * Initializes a power lock structure.
95  *
96  * The macro is used to initialize a power lock structure instance.
97  *
98  * \param l power level
99  * \param pm power lock structure
100  * \param cb user callback to be called before the system goes suspend
101  * \param d data for the user callback
102  *
103  * Usage:
104  * \code
105  struct pm_lock_t MyConstLatPowerLock = PM_LOCK_INIT(PM_LEVEL_CONSTLAT, MyConstLatPowerLock, NULL, 0);
106  * \endcode
107  */
108 
109 /**********************************************************************/
110 /** \def DECLARE_PM_LOCK(l, pm, cb, d)
111  * Declares a power lock structure instance
112  *
113  * \param l power level
114  * \param pm power lock structure
115  * \param cb user callback to be called before the system goes suspend
116  * \param d data for the user callback
117  *
118  * Usage:
119  * \code
120  DECLARE_PM_LOCK(PM_LEVEL_CONSTLAT, MyConstLatPowerLock, NULL, 0);
121  // The above line is an equivalint of
122  struct pm_lock_t MyConstLatPowerLock = PM_LOCK_INIT(PM_LEVEL_CONSTLAT, MyConstLatPowerLock, NULL, 0);
123  * \endcode
124  */
125 
126 /**********************************************************************/
127 /** \def PM_LOCK(pm)
128  * Request the power level
129  *
130  * The macro is used to request power at the given power level.
131  *
132  * \param pm power lock structure
133  *
134  * Usage:
135  * \code
136  PM_LOCK(MyConstLatPowerLock);
137  * \endcode
138  */
139 
140 /**********************************************************************/
141 /** \def PM_UNLOCK(pm)
142  * Release the power
143  *
144  * The macro is used to release previously taken power request at the given power level.
145  *
146  * If the power lock structure provides a user-defined callback, the PM_UNLOCK() puts
147  * the structure into a linked list of unlocked requests, waiting for suspend.
148  * During the following suspend (\ref pm_relax()), the list is traversed and the callbacks
149  * are called by the framework. The callbacks can prevent system from suspend by returning
150  * `false`.
151  *
152  * \param pm power lock structure
153  *
154  * Usage:
155  * \code
156  PM_UNLOCK(MyConstLatPowerLock);
157  * \endcode
158  */
159 
160 /**********************************************************************/
161 /** \def PM_AUTO_LOCK(l)
162  * Declares an anonymous auto lock, which holds power request in the auto variable visibility block
163  *
164  * \param l power level
165  *
166  * Usage:
167  * \code
168  {
169  PM_AUTO_LOCK(PM_LEVEL_CONSTLAT);
170  clock_delay(MS_TO_TICKS(10)); // The delay will be executed at at least CONSTLAT level.
171  }
172  // The lock is released here
173  * \endcode
174  */
175 
176 #ifdef DEBUG_PM
177  #define PM_LOCK_INIT(l, pm, cb, d) \
178  { \
179  .link = DLIST_INIT(pm.link), \
180  .file = __FILE__, \
181  .line = __LINE__, \
182  .next = NULL, \
183  .level = l, \
184  .ready_cb = cb, \
185  .data = d, \
186  .locked = 0, \
187  }
188  #define PM_LOCK(pm) pm_lock_dbg(&pm, __FILE__, __LINE__)
189  #define PM_UNLOCK(pm) pm_unlock_dbg(&pm, __FILE__, __LINE__)
190  #define PM_AUTO_LOCK(l) \
191  inline void pm_unlock_dbg_adapter(struct pm_lock_t *pm) { pm_unlock_dbg(pm, __FILE__, __LINE__); } \
192  struct pm_lock_t EvePmAutoLock __attribute__((cleanup(pm_unlock_dbg_adapter))); \
193  do { EvePmAutoLock = (struct pm_lock_t) PM_LOCK_INIT(l, EvePmAutoLock, NULL, 0); } while (0)
194 #else
195  #define PM_LOCK_INIT(l, pm, cb, d) \
196  { \
197  .next = NULL, \
198  .level = l, \
199  .ready_cb = cb, \
200  .data = d, \
201  .locked = 0, \
202  }
203  #define PM_LOCK(pm) pm_lock(&pm)
204  #define PM_UNLOCK(pm) pm_unlock(&pm)
205  #define PM_AUTO_LOCK(l) \
206  struct pm_lock_t EvePmAutoLock __attribute__((cleanup(pm_unlock))); \
207  do { EvePmAutoLock = (struct pm_lock_t) PM_LOCK_INIT(l, EvePmAutoLock, NULL, 0); } while (0)
208 #endif
209 
210 #define DECLARE_PM_LOCK(l, pm, cb, d) \
211  static struct pm_lock_t pm = PM_LOCK_INIT(l, pm, cb, d)
212 
213 /**********************************************************************/
214 /**
215  * Enters the lowest power level.
216  *
217  * Before entring low-power mode, pm_relax() traverses via the list of
218  * lock structures, registered by PM_UNLOCK(), and calls user-defined callbacks.
219  * If a callback returns `false`, then the ongoing suspend is cancelled.
220  *
221  * While interrupt handling is performed, pm_relax() does not return to the
222  * operating system until a wakeup is requested by pm_wakeup() call.
223  */
224 void pm_relax(void);
225 
226 /**********************************************************************/
227 /**
228  * Wakeups the system from suspend state.
229  *
230  * Interrupt handlers must call this function if they want to wake up
231  * operating system from suspend state.
232  */
233 void pm_wakeup(void);
234 
235 /**********************************************************************/
236 /**
237  * \internal
238  *
239  */ /******************************************************************/
240 
241 /**********************************************************************/
242 /**
243  * Restrict deepness of suspend to the given power level
244  *
245  * \param pm pointer to the power lock structure
246  */
247 void pm_lock(struct pm_lock_t *pm);
248 
249 /**********************************************************************/
250 /**
251  * Release a previously taken power lock
252  *
253  * \param pm pointer to the power lock structure
254  */
255 void pm_unlock(struct pm_lock_t *pm);
256 
257 /**********************************************************************/
258 /**
259  * Query the level the system can be put down to sleep taking in mind currently taken locks.
260  */
261 enum pm_level_t pm_waterlevel(void);
262 
263 #ifdef DEBUG_PM
264 /**********************************************************************/
265 /**
266  * Requests the power lock: debug version
267  *
268  * \param pm pointer to the power lock structure
269  * \param file current file name
270  * \param line current line number
271  */
272  void pm_lock_dbg(struct pm_lock_t *pm, const char *file, int line);
273 
274 /**********************************************************************/
275 /**
276  * Release the power lock: debug version
277  *
278  * \param pm pointer to the power lock structure
279  * \param file current file name
280  * \param line current line number
281  */
282  void pm_unlock_dbg(struct pm_lock_t *pm, const char *file, int line);
283 #endif
284 
285 /** @} */ /* pm */
286 
287 #endif
uint8_t locked
Definition: pm.h:89
enum pm_level_t pm_waterlevel(void)
The code implements Dummy Headed Doubly Linked Circularlist (DHDLC) primitive.
Definition: pm.h:78
void pm_relax(void)
void pm_lock(struct pm_lock_t *pm)
uint8_t level
Definition: pm.h:88
Definition: dlist.h:66
uint32_t data
Definition: pm.h:87
bool(* ready_cb)(uint32_t data)
Definition: pm.h:86
void pm_wakeup(void)
void pm_unlock(struct pm_lock_t *pm)
pm_level_t
Definition: pm.h:57
struct pm_lock_t * next
Definition: pm.h:85