1 /*
2 * Copyright (c) 2017 - 2020, 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
38 #if NRFX_CHECK(NRFX_CLOCK_ENABLED)
39 extern bool nrfx_clock_irq_enabled;
40 extern void nrfx_clock_irq_handler(void);
41 #endif
42
43 /**
44 * @internal
45 * @defgroup nrfx_power_internals POWER driver internals
46 * @ingroup nrfx_power
47 *
48 * Internal variables, auxiliary macros and functions of POWER driver.
49 * @{
50 */
51
52 /**
53 * This variable is used to check whether common POWER_CLOCK common interrupt
54 * should be disabled or not if @ref nrfx_clock tries to disable the interrupt.
55 */
56
57 bool nrfx_power_irq_enabled;
58
59 /**
60 * @brief The initialization flag
61 */
62
63 #define m_initialized nrfx_power_irq_enabled
64
65 /**
66 * @brief The handler of power fail comparator warning event
67 */
68 static nrfx_power_pofwarn_event_handler_t m_pofwarn_handler;
69
70 #if NRF_POWER_HAS_SLEEPEVT
71 /**
72 * @brief The handler of sleep event handler
73 */
74 static nrfx_power_sleep_event_handler_t m_sleepevt_handler;
75 #endif
76
77 #if NRF_POWER_HAS_USBREG
78 /**
79 * @brief The handler of USB power events
80 */
81 static nrfx_power_usb_event_handler_t m_usbevt_handler;
82 #endif
83
84 /** @} */
85
nrfx_power_pof_handler_get(void)86 nrfx_power_pofwarn_event_handler_t nrfx_power_pof_handler_get(void)
87 {
88 return m_pofwarn_handler;
89 }
90
91 #if NRF_POWER_HAS_USBREG
nrfx_power_usb_handler_get(void)92 nrfx_power_usb_event_handler_t nrfx_power_usb_handler_get(void)
93 {
94 return m_usbevt_handler;
95 }
96 #endif
97
nrfx_power_init(nrfx_power_config_t const * p_config)98 nrfx_err_t nrfx_power_init(nrfx_power_config_t const * p_config)
99 {
100 NRFX_ASSERT(p_config);
101 if (m_initialized)
102 {
103 return NRFX_ERROR_ALREADY_INITIALIZED;
104 }
105
106 #if NRF_POWER_HAS_DCDCEN_VDDH
107 nrf_power_dcdcen_vddh_set(NRF_POWER, p_config->dcdcenhv);
108 #elif NRF_REGULATORS_HAS_DCDCEN_VDDH
109 nrf_regulators_dcdcen_vddh_set(NRF_REGULATORS, p_config->dcdcenhv);
110 #endif
111
112 #if NRF_POWER_HAS_DCDCEN
113 nrf_power_dcdcen_set(NRF_POWER, p_config->dcdcen);
114 #elif defined(REGULATORS_PRESENT)
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 NRFX_POWER_SUPPORTS_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 || defined(USBREG_PRESENT)
142 nrfx_power_usbevt_uninit();
143 #endif
144 m_initialized = false;
145 }
146
147 #if NRFX_POWER_SUPPORTS_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 #if NRF_POWER_HAS_POFCON
163 nrf_power_pofcon_set(NRF_POWER, true, p_config->thr);
164 #elif NRF_REGULATORS_HAS_POFCON
165 nrf_regulators_pofcon_set(NRF_REGULATORS, true, p_config->thr);
166 #endif
167
168 #if NRF_POWER_HAS_POFCON_VDDH
169 nrf_power_pofcon_vddh_set(NRF_POWER, p_config->thrvddh);
170 #elif NRF_REGULATORS_HAS_POFCON_VDDH
171 nrf_regulators_pofcon_vddh_set(NRF_REGULATORS, p_config->thrvddh);
172 #endif
173
174 if (m_pofwarn_handler != NULL)
175 {
176 nrf_power_int_enable(NRF_POWER, NRF_POWER_INT_POFWARN_MASK);
177 }
178 }
179
nrfx_power_pof_disable(void)180 void nrfx_power_pof_disable(void)
181 {
182 #if NRF_POWER_HAS_POFCON
183 nrf_power_pofcon_set(NRF_POWER, false, NRF_POWER_POFTHR_V27);
184 #elif NRF_REGULATORS_HAS_POFCON
185 nrf_regulators_pofcon_set(NRF_REGULATORS, false, NRF_REGULATORS_POFTHR_V27);
186 #endif
187 nrf_power_int_disable(NRF_POWER, NRF_POWER_INT_POFWARN_MASK);
188 }
189
nrfx_power_pof_uninit(void)190 void nrfx_power_pof_uninit(void)
191 {
192 m_pofwarn_handler = NULL;
193 }
194 #endif // NRFX_POWER_SUPPORTS_POFCON
195
196 #if NRF_POWER_HAS_SLEEPEVT
nrfx_power_sleepevt_init(nrfx_power_sleepevt_config_t const * p_config)197 void nrfx_power_sleepevt_init(nrfx_power_sleepevt_config_t const * p_config)
198 {
199 NRFX_ASSERT(p_config != NULL);
200
201 nrfx_power_sleepevt_uninit();
202 if (p_config->handler != NULL)
203 {
204 m_sleepevt_handler = p_config->handler;
205 }
206 }
207
nrfx_power_sleepevt_enable(nrfx_power_sleepevt_config_t const * p_config)208 void nrfx_power_sleepevt_enable(nrfx_power_sleepevt_config_t const * p_config)
209 {
210 uint32_t enmask = 0;
211 if (p_config->en_enter)
212 {
213 enmask |= NRF_POWER_INT_SLEEPENTER_MASK;
214 nrf_power_event_clear(NRF_POWER, NRF_POWER_EVENT_SLEEPENTER);
215 }
216 if (p_config->en_exit)
217 {
218 enmask |= NRF_POWER_INT_SLEEPEXIT_MASK;
219 nrf_power_event_clear(NRF_POWER, NRF_POWER_EVENT_SLEEPEXIT);
220 }
221 nrf_power_int_enable(NRF_POWER, enmask);
222 }
223
nrfx_power_sleepevt_disable(void)224 void nrfx_power_sleepevt_disable(void)
225 {
226 nrf_power_int_disable(NRF_POWER, NRF_POWER_INT_SLEEPENTER_MASK |
227 NRF_POWER_INT_SLEEPEXIT_MASK);
228 }
229
nrfx_power_sleepevt_uninit(void)230 void nrfx_power_sleepevt_uninit(void)
231 {
232 m_sleepevt_handler = NULL;
233 }
234 #endif /* NRF_POWER_HAS_SLEEPEVT */
235
236 #if NRF_POWER_HAS_USBREG
nrfx_power_usbevt_init(nrfx_power_usbevt_config_t const * p_config)237 void nrfx_power_usbevt_init(nrfx_power_usbevt_config_t const * p_config)
238 {
239 NRFX_ASSERT(p_config != NULL);
240
241 nrfx_power_usbevt_uninit();
242 if (p_config->handler != NULL)
243 {
244 m_usbevt_handler = p_config->handler;
245 }
246 }
247
nrfx_power_usbevt_enable(void)248 void nrfx_power_usbevt_enable(void)
249 {
250 nrf_power_int_enable(NRF_POWER, NRF_POWER_INT_USBDETECTED_MASK |
251 NRF_POWER_INT_USBREMOVED_MASK |
252 NRF_POWER_INT_USBPWRRDY_MASK);
253 }
254
nrfx_power_usbevt_disable(void)255 void nrfx_power_usbevt_disable(void)
256 {
257 nrf_power_int_disable(NRF_POWER, NRF_POWER_INT_USBDETECTED_MASK |
258 NRF_POWER_INT_USBREMOVED_MASK |
259 NRF_POWER_INT_USBPWRRDY_MASK);
260 }
261
nrfx_power_usbevt_uninit(void)262 void nrfx_power_usbevt_uninit(void)
263 {
264 nrfx_power_usbevt_disable();
265 m_usbevt_handler = NULL;
266 }
267
268
269 #endif /* NRF_POWER_HAS_USBREG */
270
271
nrfx_power_irq_handler(void)272 void nrfx_power_irq_handler(void)
273 {
274 uint32_t enabled = nrf_power_int_enable_get(NRF_POWER);
275
276 #if NRFX_POWER_SUPPORTS_POFCON
277 if ((0 != (enabled & NRF_POWER_INT_POFWARN_MASK)) &&
278 nrf_power_event_get_and_clear(NRF_POWER, NRF_POWER_EVENT_POFWARN))
279 {
280 /* Cannot be null if event is enabled */
281 NRFX_ASSERT(m_pofwarn_handler != NULL);
282 m_pofwarn_handler();
283 }
284 #endif
285 #if NRF_POWER_HAS_SLEEPEVT
286 if ((0 != (enabled & NRF_POWER_INT_SLEEPENTER_MASK)) &&
287 nrf_power_event_get_and_clear(NRF_POWER, NRF_POWER_EVENT_SLEEPENTER))
288 {
289 /* Cannot be null if event is enabled */
290 NRFX_ASSERT(m_sleepevt_handler != NULL);
291 m_sleepevt_handler(NRFX_POWER_SLEEP_EVT_ENTER);
292 }
293 if ((0 != (enabled & NRF_POWER_INT_SLEEPEXIT_MASK)) &&
294 nrf_power_event_get_and_clear(NRF_POWER, NRF_POWER_EVENT_SLEEPEXIT))
295 {
296 /* Cannot be null if event is enabled */
297 NRFX_ASSERT(m_sleepevt_handler != NULL);
298 m_sleepevt_handler(NRFX_POWER_SLEEP_EVT_EXIT);
299 }
300 #endif
301 #if NRF_POWER_HAS_USBREG
302 if ((0 != (enabled & NRF_POWER_INT_USBDETECTED_MASK)) &&
303 nrf_power_event_get_and_clear(NRF_POWER, NRF_POWER_EVENT_USBDETECTED))
304 {
305 /* Cannot be null if event is enabled */
306 NRFX_ASSERT(m_usbevt_handler != NULL);
307 m_usbevt_handler(NRFX_POWER_USB_EVT_DETECTED);
308 }
309 if ((0 != (enabled & NRF_POWER_INT_USBREMOVED_MASK)) &&
310 nrf_power_event_get_and_clear(NRF_POWER, NRF_POWER_EVENT_USBREMOVED))
311 {
312 /* Cannot be null if event is enabled */
313 NRFX_ASSERT(m_usbevt_handler != NULL);
314 m_usbevt_handler(NRFX_POWER_USB_EVT_REMOVED);
315 }
316 if ((0 != (enabled & NRF_POWER_INT_USBPWRRDY_MASK)) &&
317 nrf_power_event_get_and_clear(NRF_POWER, NRF_POWER_EVENT_USBPWRRDY))
318 {
319 /* Cannot be null if event is enabled */
320 NRFX_ASSERT(m_usbevt_handler != NULL);
321 m_usbevt_handler(NRFX_POWER_USB_EVT_READY);
322 }
323 #endif
324 }
325
326 #if NRFX_CHECK(NRFX_CLOCK_ENABLED)
327 /*
328 * If both POWER and CLOCK drivers are used, a common IRQ handler function must
329 * be used that calls the handlers in these two drivers. This is because these
330 * two peripherals share one interrupt.
331 * This function is located here, not in a separate nrfx_power_clock.c file,
332 * so that it does not end up as the only symbol in a separate object when
333 * a library with nrfx is created. In such case, forcing a linker to use this
334 * function instead of another one defined as weak will require additional
335 * actions, and might be even impossible.
336 */
nrfx_power_clock_irq_handler(void)337 void nrfx_power_clock_irq_handler(void)
338 {
339 nrfx_power_irq_handler();
340 nrfx_clock_irq_handler();
341 }
342 #endif
343
344 #endif // NRFX_CHECK(NRFX_POWER_ENABLED)
345