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