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 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 95 nrfx_power_usb_event_handler_t nrfx_power_usb_handler_get(void) 96 { 97 return m_usbevt_handler; 98 } 99 #endif 100 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 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 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 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 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 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 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 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 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 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 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 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 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 251 void nrfx_power_usbevt_uninit(void) 252 { 253 m_usbevt_handler = NULL; 254 } 255 #endif /* NRF_POWER_HAS_USBREG */ 256 257 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 */ 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