blob: 5d8b4d24e68e57743d445e48aebd3ab66fefb34e [file] [log] [blame]
/**
* Copyright (c) 2015 - 2018, 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 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 the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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 <nrfx.h>
#if NRFX_CHECK(NRFX_SWI_ENABLED)
#include <nrfx_swi.h>
#define NRFX_LOG_MODULE SWI
#include <nrfx_log.h>
// NRFX_SWI_RESERVED_MASK - SWIs reserved for use by external modules.
#if NRFX_CHECK(NRFX_PWM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
#define NRFX_SWI_RESERVED_MASK ((NRFX_SWI_USED) | \
(1u << NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE))
#else
#define NRFX_SWI_RESERVED_MASK (NRFX_SWI_USED)
#endif
// NRFX_SWI_DISABLED_MASK - SWIs excluded from use in <nrfx_config.h>.
#if NRFX_CHECK(NRFX_SWI0_DISABLED)
#define NRFX_SWI0_DISABLED_MASK (1u << 0)
#else
#define NRFX_SWI0_DISABLED_MASK 0u
#endif
#if NRFX_CHECK(NRFX_SWI1_DISABLED)
#define NRFX_SWI1_DISABLED_MASK (1u << 1)
#else
#define NRFX_SWI1_DISABLED_MASK 0u
#endif
#if NRFX_CHECK(NRFX_SWI2_DISABLED)
#define NRFX_SWI2_DISABLED_MASK (1u << 2)
#else
#define NRFX_SWI2_DISABLED_MASK 0u
#endif
#if NRFX_CHECK(NRFX_SWI3_DISABLED)
#define NRFX_SWI3_DISABLED_MASK (1u << 3)
#else
#define NRFX_SWI3_DISABLED_MASK 0u
#endif
#if NRFX_CHECK(NRFX_SWI4_DISABLED)
#define NRFX_SWI4_DISABLED_MASK (1u << 4)
#else
#define NRFX_SWI4_DISABLED_MASK 0u
#endif
#if NRFX_CHECK(NRFX_SWI5_DISABLED)
#define NRFX_SWI5_DISABLED_MASK (1u << 5)
#else
#define NRFX_SWI5_DISABLED_MASK 0u
#endif
#define NRFX_SWI_DISABLED_MASK (NRFX_SWI0_DISABLED_MASK | \
NRFX_SWI1_DISABLED_MASK | \
NRFX_SWI2_DISABLED_MASK | \
NRFX_SWI3_DISABLED_MASK | \
NRFX_SWI4_DISABLED_MASK | \
NRFX_SWI5_DISABLED_MASK)
#if (NRFX_SWI_RESERVED_MASK & NRFX_SWI_DISABLED_MASK)
#error "A reserved SWI configured to be disabled. Check <nrfx_config.h> and NRFX_SWI_USED."
#endif
// NRFX_SWI_AVAILABLE_MASK - SWIs available for this module, i.e. present
// in the hardware and neither reserved by external modules nor disabled
// in <nrfx_config.h>.
#define NRFX_SWI_PRESENT_MASK ((1u << (SWI_COUNT)) - 1u)
#define NRFX_SWI_AVAILABLE_MASK (NRFX_SWI_PRESENT_MASK & \
~(NRFX_SWI_RESERVED_MASK | \
NRFX_SWI_DISABLED_MASK))
#if (NRFX_SWI_AVAILABLE_MASK == 0)
#error "No available SWI instances. Check <nrfx_config.h> and NRFX_SWI_USED."
#endif
#define NRFX_SWI_IS_AVAILABLE(idx) ((NRFX_SWI_AVAILABLE_MASK >> (idx)) & 1u)
#define NRFX_SWI_FIRST (NRFX_SWI_IS_AVAILABLE(0) ? 0u : \
(NRFX_SWI_IS_AVAILABLE(1) ? 1u : \
(NRFX_SWI_IS_AVAILABLE(2) ? 2u : \
(NRFX_SWI_IS_AVAILABLE(3) ? 3u : \
(NRFX_SWI_IS_AVAILABLE(4) ? 4u : \
5u)))))
#define NRFX_SWI_LAST (NRFX_SWI_IS_AVAILABLE(5) ? 5u : \
(NRFX_SWI_IS_AVAILABLE(4) ? 4u : \
(NRFX_SWI_IS_AVAILABLE(3) ? 3u : \
(NRFX_SWI_IS_AVAILABLE(2) ? 2u : \
(NRFX_SWI_IS_AVAILABLE(1) ? 1u : \
0u)))))
// NRFX_SWI_EGU_COUNT - number of EGU instances to be used by this module
// (note - if EGU is not present, EGU_COUNT is not defined).
#if NRFX_CHECK(NRFX_EGU_ENABLED)
#define NRFX_SWI_EGU_COUNT EGU_COUNT
#else
#define NRFX_SWI_EGU_COUNT 0
#endif
// These flags are needed only for SWIs that have no corresponding EGU unit
// (in EGU such flags are available in hardware).
#if (NRFX_SWI_EGU_COUNT < SWI_COUNT)
static nrfx_swi_flags_t m_swi_flags[SWI_COUNT - NRFX_SWI_EGU_COUNT];
#endif
static nrfx_swi_handler_t m_swi_handlers[SWI_COUNT];
static uint8_t m_swi_allocated_mask;
static void swi_mark_allocated(nrfx_swi_t swi)
{
m_swi_allocated_mask |= (1u << swi);
}
static void swi_mark_unallocated(nrfx_swi_t swi)
{
m_swi_allocated_mask &= ~(1u << swi);
}
static bool swi_is_allocated(nrfx_swi_t swi)
{
return (m_swi_allocated_mask & (1u << swi));
}
static bool swi_is_available(nrfx_swi_t swi)
{
return NRFX_SWI_IS_AVAILABLE(swi);
}
static IRQn_Type swi_irq_number_get(nrfx_swi_t swi)
{
return (IRQn_Type)((uint32_t)SWI0_IRQn + (uint32_t)swi);
}
static void swi_handler_setup(nrfx_swi_t swi,
nrfx_swi_handler_t event_handler,
uint32_t irq_priority)
{
m_swi_handlers[swi] = event_handler;
#if NRFX_SWI_EGU_COUNT
if (swi < NRFX_SWI_EGU_COUNT)
{
NRF_EGU_Type * p_egu = nrfx_swi_egu_instance_get(swi);
NRFX_ASSERT(p_egu != NULL);
nrf_egu_int_enable(p_egu, NRF_EGU_INT_ALL);
if (event_handler == NULL)
{
return;
}
}
#endif
NRFX_ASSERT(event_handler != NULL);
NRFX_IRQ_PRIORITY_SET(swi_irq_number_get(swi), irq_priority);
NRFX_IRQ_ENABLE(swi_irq_number_get(swi));
}
nrfx_err_t nrfx_swi_alloc(nrfx_swi_t * p_swi,
nrfx_swi_handler_t event_handler,
uint32_t irq_priority)
{
NRFX_ASSERT(p_swi != NULL);
nrfx_err_t err_code;
for (nrfx_swi_t swi = NRFX_SWI_FIRST; swi <= NRFX_SWI_LAST; ++swi)
{
if (swi_is_available(swi))
{
bool allocated = false;
NRFX_CRITICAL_SECTION_ENTER();
if (!swi_is_allocated(swi))
{
swi_mark_allocated(swi);
allocated = true;
}
NRFX_CRITICAL_SECTION_EXIT();
if (allocated)
{
swi_handler_setup(swi, event_handler, irq_priority);
*p_swi = swi;
NRFX_LOG_INFO("SWI channel allocated: %d.", (*p_swi));
return NRFX_SUCCESS;
}
}
}
err_code = NRFX_ERROR_NO_MEM;
NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
return err_code;
}
bool nrfx_swi_is_allocated(nrfx_swi_t swi)
{
return swi_is_allocated(swi);
}
void nrfx_swi_free(nrfx_swi_t * p_swi)
{
NRFX_ASSERT(p_swi != NULL);
nrfx_swi_t swi = *p_swi;
NRFX_ASSERT(swi_is_allocated(swi));
NRFX_IRQ_DISABLE(swi_irq_number_get(swi));
m_swi_handlers[swi] = NULL;
swi_mark_unallocated(swi);
*p_swi = NRFX_SWI_UNALLOCATED;
}
void nrfx_swi_all_free(void)
{
for (nrfx_swi_t swi = NRFX_SWI_FIRST; swi <= NRFX_SWI_LAST; ++swi)
{
if (swi_is_allocated(swi))
{
NRFX_IRQ_DISABLE(swi_irq_number_get(swi));
m_swi_handlers[swi] = NULL;
#if NRFX_SWI_EGU_COUNT
if (swi < NRFX_SWI_EGU_COUNT)
{
nrf_egu_int_disable(nrfx_swi_egu_instance_get(swi),
NRF_EGU_INT_ALL);
}
#endif
}
}
m_swi_allocated_mask = 0;
}
void nrfx_swi_trigger(nrfx_swi_t swi, uint8_t flag_number)
{
NRFX_ASSERT(swi_is_allocated(swi));
#if NRFX_SWI_EGU_COUNT
NRF_EGU_Type * p_egu = nrfx_swi_egu_instance_get(swi);
#if (NRFX_SWI_EGU_COUNT < SWI_COUNT)
if (p_egu == NULL)
{
m_swi_flags[swi - NRFX_SWI_EGU_COUNT] |= (1 << flag_number);
NRFX_IRQ_PENDING_SET(swi_irq_number_get(swi));
}
else
#endif // (NRFX_SWI_EGU_COUNT < SWI_COUNT)
{
nrf_egu_task_trigger(p_egu,
nrf_egu_task_trigger_get(p_egu, flag_number));
}
#else // -> #if !NRFX_SWI_EGU_COUNT
m_swi_flags[swi - NRFX_SWI_EGU_COUNT] |= (1 << flag_number);
NRFX_IRQ_PENDING_SET(swi_irq_number_get(swi));
#endif
}
#if NRFX_SWI_EGU_COUNT
static void egu_irq_handler(nrfx_swi_t swi, uint8_t egu_channel_count)
{
#if (NRFX_SWI_FIRST > 0)
NRFX_ASSERT(swi >= NRFX_SWI_FIRST);
#endif
NRFX_ASSERT(swi <= NRFX_SWI_LAST);
nrfx_swi_handler_t handler = m_swi_handlers[swi];
NRFX_ASSERT(handler != NULL);
NRF_EGU_Type * p_egu = nrfx_swi_egu_instance_get(swi);
NRFX_ASSERT(p_egu != NULL);
nrfx_swi_flags_t flags = 0;
for (uint8_t i = 0; i < egu_channel_count; ++i)
{
nrf_egu_event_t egu_event = nrf_egu_event_triggered_get(p_egu, i);
if (nrf_egu_event_check(p_egu, egu_event))
{
flags |= (1u << i);
nrf_egu_event_clear(p_egu, egu_event);
}
}
handler(swi, flags);
}
#endif // NRFX_SWI_EGU_COUNT
#if (NRFX_SWI_EGU_COUNT < SWI_COUNT)
static void swi_irq_handler(nrfx_swi_t swi)
{
#if (NRFX_SWI_FIRST > 0)
NRFX_ASSERT(swi >= NRFX_SWI_FIRST);
#endif
NRFX_ASSERT(swi <= NRFX_SWI_LAST);
nrfx_swi_handler_t handler = m_swi_handlers[swi];
NRFX_ASSERT(handler != NULL);
nrfx_swi_flags_t flags = m_swi_flags[swi - NRFX_SWI_EGU_COUNT];
m_swi_flags[swi - NRFX_SWI_EGU_COUNT] &= ~flags;
handler(swi, flags);
}
#endif // (NRFX_SWI_EGU_COUNT < SWI_COUNT)
#if NRFX_SWI_IS_AVAILABLE(0)
void nrfx_swi_0_irq_handler(void)
{
#if (NRFX_SWI_EGU_COUNT > 0)
egu_irq_handler(0, EGU0_CH_NUM);
#else
swi_irq_handler(0);
#endif
}
#endif // NRFX_SWI_IS_AVAILABLE(0)
#if NRFX_SWI_IS_AVAILABLE(1)
void nrfx_swi_1_irq_handler(void)
{
#if (NRFX_SWI_EGU_COUNT > 1)
egu_irq_handler(1, EGU1_CH_NUM);
#else
swi_irq_handler(1);
#endif
}
#endif // NRFX_SWI_IS_AVAILABLE(1)
#if NRFX_SWI_IS_AVAILABLE(2)
void nrfx_swi_2_irq_handler(void)
{
#if (NRFX_SWI_EGU_COUNT > 2)
egu_irq_handler(2, EGU2_CH_NUM);
#else
swi_irq_handler(2);
#endif
}
#endif // NRFX_SWI_IS_AVAILABLE(2)
#if NRFX_SWI_IS_AVAILABLE(3)
void nrfx_swi_3_irq_handler(void)
{
#if (NRFX_SWI_EGU_COUNT > 3)
egu_irq_handler(3, EGU3_CH_NUM);
#else
swi_irq_handler(3);
#endif
}
#endif // NRFX_SWI_IS_AVAILABLE(3)
#if NRFX_SWI_IS_AVAILABLE(4)
void nrfx_swi_4_irq_handler(void)
{
#if (NRFX_SWI_EGU_COUNT > 4)
egu_irq_handler(4, EGU4_CH_NUM);
#else
swi_irq_handler(4);
#endif
}
#endif // NRFX_SWI_IS_AVAILABLE(4)
#if NRFX_SWI_IS_AVAILABLE(5)
void nrfx_swi_5_irq_handler(void)
{
#if (NRFX_SWI_EGU_COUNT > 5)
egu_irq_handler(5, EGU5_CH_NUM);
#else
swi_irq_handler(5);
#endif
}
#endif // NRFX_SWI_IS_AVAILABLE(5)
#endif // NRFX_CHECK(NRFX_SWI_ENABLED)