xref: /nrf52832-nimble/nordic/nrfx/drivers/src/nrfx_power.c (revision 150812a83cab50279bd772ef6db1bfaf255f2c5b)
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