1 /*
2 * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <nrfx.h>
33
34 #if NRFX_CHECK(NRFX_POWER_ENABLED)
35
36 #include <nrfx_power.h>
37 #if defined(REGULATORS_PRESENT)
38 #include <hal/nrf_regulators.h>
39 #endif
40
41 #if NRFX_CHECK(NRFX_CLOCK_ENABLED)
42 extern bool nrfx_clock_irq_enabled;
43 extern void nrfx_clock_irq_handler(void);
44 #endif
45
46 /**
47 * @internal
48 * @defgroup nrfx_power_internals POWER driver internals
49 * @ingroup nrfx_power
50 *
51 * Internal variables, auxiliary macros and functions of POWER driver.
52 * @{
53 */
54
55 /**
56 * This variable is used to check whether common POWER_CLOCK common interrupt
57 * should be disabled or not if @ref nrfx_clock tries to disable the interrupt.
58 */
59
60 bool nrfx_power_irq_enabled;
61
62 /**
63 * @brief The initialization flag
64 */
65
66 #define m_initialized nrfx_power_irq_enabled
67
68 /**
69 * @brief The handler of power fail comparator warning event
70 */
71 static nrfx_power_pofwarn_event_handler_t m_pofwarn_handler;
72
73 #if NRF_POWER_HAS_SLEEPEVT
74 /**
75 * @brief The handler of sleep event handler
76 */
77 static nrfx_power_sleep_event_handler_t m_sleepevt_handler;
78 #endif
79
80 #if NRF_POWER_HAS_USBREG
81 /**
82 * @brief The handler of USB power events
83 */
84 static nrfx_power_usb_event_handler_t m_usbevt_handler;
85 #endif
86
87 /** @} */
88
nrfx_power_pof_handler_get(void)89 nrfx_power_pofwarn_event_handler_t nrfx_power_pof_handler_get(void)
90 {
91 return m_pofwarn_handler;
92 }
93
94 #if NRF_POWER_HAS_USBREG
nrfx_power_usb_handler_get(void)95 nrfx_power_usb_event_handler_t nrfx_power_usb_handler_get(void)
96 {
97 return m_usbevt_handler;
98 }
99 #endif
100
nrfx_power_init(nrfx_power_config_t const * p_config)101 nrfx_err_t nrfx_power_init(nrfx_power_config_t const * p_config)
102 {
103 NRFX_ASSERT(p_config);
104 if (m_initialized)
105 {
106 return NRFX_ERROR_ALREADY_INITIALIZED;
107 }
108
109 #if NRF_POWER_HAS_VDDH
110 nrf_power_dcdcen_vddh_set(p_config->dcdcenhv);
111 #endif
112 #if NRF_POWER_HAS_DCDCEN
113 nrf_power_dcdcen_set(p_config->dcdcen);
114 #else
115 nrf_regulators_dcdcen_set(NRF_REGULATORS, p_config->dcdcen);
116 #endif
117
118 nrfx_power_clock_irq_init();
119
120 m_initialized = true;
121 return NRFX_SUCCESS;
122 }
123
124
nrfx_power_uninit(void)125 void nrfx_power_uninit(void)
126 {
127 NRFX_ASSERT(m_initialized);
128
129 #if NRFX_CHECK(NRFX_CLOCK_ENABLED)
130 if (!nrfx_clock_irq_enabled)
131 #endif
132 {
133 NRFX_IRQ_DISABLE(nrfx_get_irq_number(NRF_POWER));
134 }
135 #if NRF_POWER_HAS_POFCON
136 nrfx_power_pof_uninit();
137 #endif
138 #if NRF_POWER_HAS_SLEEPEVT
139 nrfx_power_sleepevt_uninit();
140 #endif
141 #if NRF_POWER_HAS_USBREG
142 nrfx_power_usbevt_uninit();
143 #endif
144 m_initialized = false;
145 }
146
147 #if NRF_POWER_HAS_POFCON
nrfx_power_pof_init(nrfx_power_pofwarn_config_t const * p_config)148 void nrfx_power_pof_init(nrfx_power_pofwarn_config_t const * p_config)
149 {
150 NRFX_ASSERT(p_config != NULL);
151
152 nrfx_power_pof_uninit();
153
154 if (p_config->handler != NULL)
155 {
156 m_pofwarn_handler = p_config->handler;
157 }
158 }
159
nrfx_power_pof_enable(nrfx_power_pofwarn_config_t const * p_config)160 void nrfx_power_pof_enable(nrfx_power_pofwarn_config_t const * p_config)
161 {
162 nrf_power_pofcon_set(true, p_config->thr);
163 #if NRF_POWER_HAS_VDDH
164 nrf_power_pofcon_vddh_set(p_config->thrvddh);
165 #endif
166 if (m_pofwarn_handler != NULL)
167 {
168 nrf_power_int_enable(NRF_POWER_INT_POFWARN_MASK);
169 }
170 }
171
nrfx_power_pof_disable(void)172 void nrfx_power_pof_disable(void)
173 {
174 nrf_power_pofcon_set(false, NRF_POWER_POFTHR_V27);
175 nrf_power_int_disable(NRF_POWER_INT_POFWARN_MASK);
176 }
177
nrfx_power_pof_uninit(void)178 void nrfx_power_pof_uninit(void)
179 {
180 m_pofwarn_handler = NULL;
181 }
182 #endif // NRF_POWER_HAS_POFCON
183
184 #if NRF_POWER_HAS_SLEEPEVT
nrfx_power_sleepevt_init(nrfx_power_sleepevt_config_t const * p_config)185 void nrfx_power_sleepevt_init(nrfx_power_sleepevt_config_t const * p_config)
186 {
187 NRFX_ASSERT(p_config != NULL);
188
189 nrfx_power_sleepevt_uninit();
190 if (p_config->handler != NULL)
191 {
192 m_sleepevt_handler = p_config->handler;
193 }
194 }
195
nrfx_power_sleepevt_enable(nrfx_power_sleepevt_config_t const * p_config)196 void nrfx_power_sleepevt_enable(nrfx_power_sleepevt_config_t const * p_config)
197 {
198 uint32_t enmask = 0;
199 if (p_config->en_enter)
200 {
201 enmask |= NRF_POWER_INT_SLEEPENTER_MASK;
202 nrf_power_event_clear(NRF_POWER_EVENT_SLEEPENTER);
203 }
204 if (p_config->en_exit)
205 {
206 enmask |= NRF_POWER_INT_SLEEPEXIT_MASK;
207 nrf_power_event_clear(NRF_POWER_EVENT_SLEEPEXIT);
208 }
209 nrf_power_int_enable(enmask);
210 }
211
nrfx_power_sleepevt_disable(void)212 void nrfx_power_sleepevt_disable(void)
213 {
214 nrf_power_int_disable(
215 NRF_POWER_INT_SLEEPENTER_MASK |
216 NRF_POWER_INT_SLEEPEXIT_MASK);
217 }
218
nrfx_power_sleepevt_uninit(void)219 void nrfx_power_sleepevt_uninit(void)
220 {
221 m_sleepevt_handler = NULL;
222 }
223 #endif /* NRF_POWER_HAS_SLEEPEVT */
224
225 #if NRF_POWER_HAS_USBREG
nrfx_power_usbevt_init(nrfx_power_usbevt_config_t const * p_config)226 void nrfx_power_usbevt_init(nrfx_power_usbevt_config_t const * p_config)
227 {
228 nrfx_power_usbevt_uninit();
229 if (p_config->handler != NULL)
230 {
231 m_usbevt_handler = p_config->handler;
232 }
233 }
234
nrfx_power_usbevt_enable(void)235 void nrfx_power_usbevt_enable(void)
236 {
237 nrf_power_int_enable(
238 NRF_POWER_INT_USBDETECTED_MASK |
239 NRF_POWER_INT_USBREMOVED_MASK |
240 NRF_POWER_INT_USBPWRRDY_MASK);
241 }
242
nrfx_power_usbevt_disable(void)243 void nrfx_power_usbevt_disable(void)
244 {
245 nrf_power_int_disable(
246 NRF_POWER_INT_USBDETECTED_MASK |
247 NRF_POWER_INT_USBREMOVED_MASK |
248 NRF_POWER_INT_USBPWRRDY_MASK);
249 }
250
nrfx_power_usbevt_uninit(void)251 void nrfx_power_usbevt_uninit(void)
252 {
253 m_usbevt_handler = NULL;
254 }
255 #endif /* NRF_POWER_HAS_USBREG */
256
257
nrfx_power_irq_handler(void)258 void nrfx_power_irq_handler(void)
259 {
260 uint32_t enabled = nrf_power_int_enable_get();
261
262 #if NRF_POWER_HAS_POFCON
263 if ((0 != (enabled & NRF_POWER_INT_POFWARN_MASK)) &&
264 nrf_power_event_get_and_clear(NRF_POWER_EVENT_POFWARN))
265 {
266 /* Cannot be null if event is enabled */
267 NRFX_ASSERT(m_pofwarn_handler != NULL);
268 m_pofwarn_handler();
269 }
270 #endif
271 #if NRF_POWER_HAS_SLEEPEVT
272 if ((0 != (enabled & NRF_POWER_INT_SLEEPENTER_MASK)) &&
273 nrf_power_event_get_and_clear(NRF_POWER_EVENT_SLEEPENTER))
274 {
275 /* Cannot be null if event is enabled */
276 NRFX_ASSERT(m_sleepevt_handler != NULL);
277 m_sleepevt_handler(NRFX_POWER_SLEEP_EVT_ENTER);
278 }
279 if ((0 != (enabled & NRF_POWER_INT_SLEEPEXIT_MASK)) &&
280 nrf_power_event_get_and_clear(NRF_POWER_EVENT_SLEEPEXIT))
281 {
282 /* Cannot be null if event is enabled */
283 NRFX_ASSERT(m_sleepevt_handler != NULL);
284 m_sleepevt_handler(NRFX_POWER_SLEEP_EVT_EXIT);
285 }
286 #endif
287 #if NRF_POWER_HAS_USBREG
288 if ((0 != (enabled & NRF_POWER_INT_USBDETECTED_MASK)) &&
289 nrf_power_event_get_and_clear(NRF_POWER_EVENT_USBDETECTED))
290 {
291 /* Cannot be null if event is enabled */
292 NRFX_ASSERT(m_usbevt_handler != NULL);
293 m_usbevt_handler(NRFX_POWER_USB_EVT_DETECTED);
294 }
295 if ((0 != (enabled & NRF_POWER_INT_USBREMOVED_MASK)) &&
296 nrf_power_event_get_and_clear(NRF_POWER_EVENT_USBREMOVED))
297 {
298 /* Cannot be null if event is enabled */
299 NRFX_ASSERT(m_usbevt_handler != NULL);
300 m_usbevt_handler(NRFX_POWER_USB_EVT_REMOVED);
301 }
302 if ((0 != (enabled & NRF_POWER_INT_USBPWRRDY_MASK)) &&
303 nrf_power_event_get_and_clear(NRF_POWER_EVENT_USBPWRRDY))
304 {
305 /* Cannot be null if event is enabled */
306 NRFX_ASSERT(m_usbevt_handler != NULL);
307 m_usbevt_handler(NRFX_POWER_USB_EVT_READY);
308 }
309 #endif
310 }
311
312 #if NRFX_CHECK(NRFX_CLOCK_ENABLED)
313 /*
314 * If both POWER and CLOCK drivers are used, a common IRQ handler function must
315 * be used that calls the handlers in these two drivers. This is because these
316 * two peripherals share one interrupt.
317 * This function is located here, not in a separate nrfx_power_clock.c file,
318 * so that it does not end up as the only symbol in a separate object when
319 * a library with nrfx is created. In such case, forcing a linker to use this
320 * function instead of another one defined as weak will require additional
321 * actions, and might be even impossible.
322 */
nrfx_power_clock_irq_handler(void)323 void nrfx_power_clock_irq_handler(void)
324 {
325 nrfx_power_irq_handler();
326 nrfx_clock_irq_handler();
327 }
328 #endif
329
330 #endif // NRFX_CHECK(NRFX_POWER_ENABLED)
331