blob: 6ecc2042fb1be787a6ebd6b5d9e4c6a15daadf0a [file] [log] [blame]
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "platform/nrf_802154_lp_timer.h"
#include <assert.h>
#include <kernel.h>
#include <stdbool.h>
#include "drivers/timer/nrf_rtc_timer.h"
#include "platform/nrf_802154_clock.h"
#include "nrf_802154_sl_utils.h"
static volatile bool m_clock_ready;
static bool m_is_running;
static int32_t m_rtc_channel;
static bool m_in_critical_section;
void rtc_irq_handler(int32_t id, uint32_t cc_value, void *user_data)
{
(void)cc_value;
(void)user_data;
nrf_802154_sl_mcu_critical_state_t state;
assert(id == m_rtc_channel);
nrf_802154_sl_mcu_critical_enter(state);
m_is_running = false;
(void)z_nrf_rtc_timer_compare_int_lock(m_rtc_channel);
nrf_802154_sl_mcu_critical_exit(state);
nrf_802154_lp_timer_fired();
}
/**
* @brief Start one-shot timer that expires at specified time on desired channel.
*
* Start one-shot timer that will expire @p dt microseconds after @p t0 time on channel @p channel.
*
* @param[in] channel Compare channel on which timer will be started.
* @param[in] t0 Number of microseconds representing timer start time.
* @param[in] dt Time of timer expiration as time elapsed from @p t0 [us].
*/
static void timer_start_at(uint32_t channel,
uint32_t t0,
uint32_t dt)
{
uint32_t cc_value = NRF_802154_SL_US_TO_RTC_TICKS(t0 + dt);
nrf_802154_sl_mcu_critical_state_t state;
z_nrf_rtc_timer_compare_set(m_rtc_channel, cc_value, rtc_irq_handler, NULL);
nrf_802154_sl_mcu_critical_enter(state);
m_is_running = true;
z_nrf_rtc_timer_compare_int_unlock(m_rtc_channel, (m_in_critical_section == false));
nrf_802154_sl_mcu_critical_exit(state);
}
void nrf_802154_clock_lfclk_ready(void)
{
m_clock_ready = true;
}
void nrf_802154_lp_timer_init(void)
{
m_in_critical_section = false;
m_is_running = false;
/* Setup low frequency clock. */
nrf_802154_clock_lfclk_start();
while (!m_clock_ready) {
/* Intentionally empty */
}
m_rtc_channel = z_nrf_rtc_timer_chan_alloc();
if (m_rtc_channel < 0) {
assert(false);
return;
}
(void)z_nrf_rtc_timer_compare_int_lock(m_rtc_channel);
}
void nrf_802154_lp_timer_deinit(void)
{
(void)z_nrf_rtc_timer_compare_int_lock(m_rtc_channel);
z_nrf_rtc_timer_chan_free(m_rtc_channel);
nrf_802154_clock_lfclk_stop();
}
void nrf_802154_lp_timer_critical_section_enter(void)
{
nrf_802154_sl_mcu_critical_state_t state;
nrf_802154_sl_mcu_critical_enter(state);
if (!m_in_critical_section) {
(void)z_nrf_rtc_timer_compare_int_lock(m_rtc_channel);
m_in_critical_section = true;
}
nrf_802154_sl_mcu_critical_exit(state);
}
void nrf_802154_lp_timer_critical_section_exit(void)
{
nrf_802154_sl_mcu_critical_state_t state;
nrf_802154_sl_mcu_critical_enter(state);
m_in_critical_section = false;
z_nrf_rtc_timer_compare_int_unlock(m_rtc_channel, m_is_running);
nrf_802154_sl_mcu_critical_exit(state);
}
uint32_t nrf_802154_lp_timer_time_get(void)
{
/* Please note that this function does not handle RTC overflow */
return NRF_802154_SL_RTC_TICKS_TO_US(z_nrf_rtc_timer_read());
}
uint32_t nrf_802154_lp_timer_granularity_get(void)
{
return NRF_802154_SL_US_PER_TICK;
}
void nrf_802154_lp_timer_start(uint32_t t0, uint32_t dt)
{
timer_start_at(m_rtc_channel, t0, dt);
}
bool nrf_802154_lp_timer_is_running(void)
{
return m_is_running;
}
void nrf_802154_lp_timer_stop(void)
{
nrf_802154_sl_mcu_critical_state_t state;
nrf_802154_sl_mcu_critical_enter(state);
m_is_running = false;
(void)z_nrf_rtc_timer_compare_int_lock(m_rtc_channel);
nrf_802154_sl_mcu_critical_exit(state);
}
void nrf_802154_lp_timer_sync_start_now(void)
{
/* Currently not supported */
}
void nrf_802154_lp_timer_sync_start_at(uint32_t t0, uint32_t dt)
{
(void)t0;
(void)dt;
/* Currently not supported */
}
void nrf_802154_lp_timer_sync_stop(void)
{
/* Currently not supported */
}
uint32_t nrf_802154_lp_timer_sync_event_get(void)
{
/* Currently not supported */
return 0;
}
uint32_t nrf_802154_lp_timer_sync_time_get(void)
{
/* Currently not supported */
return 0;
}
#ifndef UNITY_ON_TARGET
__WEAK void nrf_802154_lp_timer_synchronized(void)
{
/* Intentionally empty */
}
#endif