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