/** * Copyright (c) 2017 - 2019, Nordic Semiconductor ASA * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into a Nordic * Semiconductor ASA integrated circuit in a product or a software update for * such product, must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. Neither the name of Nordic Semiconductor ASA nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * 4. This software, with or without modification, must only be used with a * Nordic Semiconductor ASA integrated circuit. * * 5. Any software provided in binary form under this license must not be reverse * engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #if NRFX_CHECK(NRFX_POWER_ENABLED) #include #if defined(REGULATORS_PRESENT) #include #endif #if NRFX_CHECK(NRFX_CLOCK_ENABLED) extern bool nrfx_clock_irq_enabled; extern void nrfx_clock_irq_handler(void); #endif /** * @internal * @defgroup nrfx_power_internals POWER driver internals * @ingroup nrfx_power * * Internal variables, auxiliary macros and functions of POWER driver. * @{ */ /** * This variable is used to check whether common POWER_CLOCK common interrupt * should be disabled or not if @ref nrfx_clock tries to disable the interrupt. */ bool nrfx_power_irq_enabled; /** * @brief The initialization flag */ #define m_initialized nrfx_power_irq_enabled /** * @brief The handler of power fail comparator warning event */ static nrfx_power_pofwarn_event_handler_t m_pofwarn_handler; #if NRF_POWER_HAS_SLEEPEVT /** * @brief The handler of sleep event handler */ static nrfx_power_sleep_event_handler_t m_sleepevt_handler; #endif #if NRF_POWER_HAS_USBREG /** * @brief The handler of USB power events */ static nrfx_power_usb_event_handler_t m_usbevt_handler; #endif /** @} */ nrfx_power_pofwarn_event_handler_t nrfx_power_pof_handler_get(void) { return m_pofwarn_handler; } #if NRF_POWER_HAS_USBREG nrfx_power_usb_event_handler_t nrfx_power_usb_handler_get(void) { return m_usbevt_handler; } #endif nrfx_err_t nrfx_power_init(nrfx_power_config_t const * p_config) { NRFX_ASSERT(p_config); if (m_initialized) { return NRFX_ERROR_ALREADY_INITIALIZED; } #if NRF_POWER_HAS_VDDH nrf_power_dcdcen_vddh_set(p_config->dcdcenhv); #endif #if NRF_POWER_HAS_DCDCEN nrf_power_dcdcen_set(p_config->dcdcen); #else nrf_regulators_dcdcen_set(NRF_REGULATORS, p_config->dcdcen); #endif nrfx_power_clock_irq_init(); m_initialized = true; return NRFX_SUCCESS; } void nrfx_power_uninit(void) { NRFX_ASSERT(m_initialized); #if NRFX_CHECK(NRFX_CLOCK_ENABLED) if (!nrfx_clock_irq_enabled) #endif { NRFX_IRQ_DISABLE(nrfx_get_irq_number(NRF_POWER)); } #if NRF_POWER_HAS_POFCON nrfx_power_pof_uninit(); #endif #if NRF_POWER_HAS_SLEEPEVT nrfx_power_sleepevt_uninit(); #endif #if NRF_POWER_HAS_USBREG nrfx_power_usbevt_uninit(); #endif m_initialized = false; } #if NRF_POWER_HAS_POFCON void nrfx_power_pof_init(nrfx_power_pofwarn_config_t const * p_config) { NRFX_ASSERT(p_config != NULL); nrfx_power_pof_uninit(); if (p_config->handler != NULL) { m_pofwarn_handler = p_config->handler; } } void nrfx_power_pof_enable(nrfx_power_pofwarn_config_t const * p_config) { nrf_power_pofcon_set(true, p_config->thr); #if NRF_POWER_HAS_VDDH nrf_power_pofcon_vddh_set(p_config->thrvddh); #endif if (m_pofwarn_handler != NULL) { nrf_power_int_enable(NRF_POWER_INT_POFWARN_MASK); } } void nrfx_power_pof_disable(void) { nrf_power_pofcon_set(false, NRF_POWER_POFTHR_V27); nrf_power_int_disable(NRF_POWER_INT_POFWARN_MASK); } void nrfx_power_pof_uninit(void) { m_pofwarn_handler = NULL; } #endif // NRF_POWER_HAS_POFCON #if NRF_POWER_HAS_SLEEPEVT void nrfx_power_sleepevt_init(nrfx_power_sleepevt_config_t const * p_config) { NRFX_ASSERT(p_config != NULL); nrfx_power_sleepevt_uninit(); if (p_config->handler != NULL) { m_sleepevt_handler = p_config->handler; } } void nrfx_power_sleepevt_enable(nrfx_power_sleepevt_config_t const * p_config) { uint32_t enmask = 0; if (p_config->en_enter) { enmask |= NRF_POWER_INT_SLEEPENTER_MASK; nrf_power_event_clear(NRF_POWER_EVENT_SLEEPENTER); } if (p_config->en_exit) { enmask |= NRF_POWER_INT_SLEEPEXIT_MASK; nrf_power_event_clear(NRF_POWER_EVENT_SLEEPEXIT); } nrf_power_int_enable(enmask); } void nrfx_power_sleepevt_disable(void) { nrf_power_int_disable( NRF_POWER_INT_SLEEPENTER_MASK | NRF_POWER_INT_SLEEPEXIT_MASK); } void nrfx_power_sleepevt_uninit(void) { m_sleepevt_handler = NULL; } #endif /* NRF_POWER_HAS_SLEEPEVT */ #if NRF_POWER_HAS_USBREG void nrfx_power_usbevt_init(nrfx_power_usbevt_config_t const * p_config) { nrfx_power_usbevt_uninit(); if (p_config->handler != NULL) { m_usbevt_handler = p_config->handler; } } void nrfx_power_usbevt_enable(void) { nrf_power_int_enable( NRF_POWER_INT_USBDETECTED_MASK | NRF_POWER_INT_USBREMOVED_MASK | NRF_POWER_INT_USBPWRRDY_MASK); } void nrfx_power_usbevt_disable(void) { nrf_power_int_disable( NRF_POWER_INT_USBDETECTED_MASK | NRF_POWER_INT_USBREMOVED_MASK | NRF_POWER_INT_USBPWRRDY_MASK); } void nrfx_power_usbevt_uninit(void) { m_usbevt_handler = NULL; } #endif /* NRF_POWER_HAS_USBREG */ void nrfx_power_irq_handler(void) { uint32_t enabled = nrf_power_int_enable_get(); #if NRF_POWER_HAS_POFCON if ((0 != (enabled & NRF_POWER_INT_POFWARN_MASK)) && nrf_power_event_get_and_clear(NRF_POWER_EVENT_POFWARN)) { /* Cannot be null if event is enabled */ NRFX_ASSERT(m_pofwarn_handler != NULL); m_pofwarn_handler(); } #endif #if NRF_POWER_HAS_SLEEPEVT if ((0 != (enabled & NRF_POWER_INT_SLEEPENTER_MASK)) && nrf_power_event_get_and_clear(NRF_POWER_EVENT_SLEEPENTER)) { /* Cannot be null if event is enabled */ NRFX_ASSERT(m_sleepevt_handler != NULL); m_sleepevt_handler(NRFX_POWER_SLEEP_EVT_ENTER); } if ((0 != (enabled & NRF_POWER_INT_SLEEPEXIT_MASK)) && nrf_power_event_get_and_clear(NRF_POWER_EVENT_SLEEPEXIT)) { /* Cannot be null if event is enabled */ NRFX_ASSERT(m_sleepevt_handler != NULL); m_sleepevt_handler(NRFX_POWER_SLEEP_EVT_EXIT); } #endif #if NRF_POWER_HAS_USBREG if ((0 != (enabled & NRF_POWER_INT_USBDETECTED_MASK)) && nrf_power_event_get_and_clear(NRF_POWER_EVENT_USBDETECTED)) { /* Cannot be null if event is enabled */ NRFX_ASSERT(m_usbevt_handler != NULL); m_usbevt_handler(NRFX_POWER_USB_EVT_DETECTED); } if ((0 != (enabled & NRF_POWER_INT_USBREMOVED_MASK)) && nrf_power_event_get_and_clear(NRF_POWER_EVENT_USBREMOVED)) { /* Cannot be null if event is enabled */ NRFX_ASSERT(m_usbevt_handler != NULL); m_usbevt_handler(NRFX_POWER_USB_EVT_REMOVED); } if ((0 != (enabled & NRF_POWER_INT_USBPWRRDY_MASK)) && nrf_power_event_get_and_clear(NRF_POWER_EVENT_USBPWRRDY)) { /* Cannot be null if event is enabled */ NRFX_ASSERT(m_usbevt_handler != NULL); m_usbevt_handler(NRFX_POWER_USB_EVT_READY); } #endif } #if NRFX_CHECK(NRFX_CLOCK_ENABLED) /* * If both POWER and CLOCK drivers are used, a common IRQ handler function must * be used that calls the handlers in these two drivers. This is because these * two peripherals share one interrupt. * This function is located here, not in a separate nrfx_power_clock.c file, * so that it does not end up as the only symbol in a separate object when * a library with nrfx is created. In such case, forcing a linker to use this * function instead of another one defined as weak will require additional * actions, and might be even impossible. */ void nrfx_power_clock_irq_handler(void) { nrfx_power_irq_handler(); nrfx_clock_irq_handler(); } #endif #endif // NRFX_CHECK(NRFX_POWER_ENABLED)