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