1 /*
2  * Copyright (c) 2021, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
18  *    contributors may be used to endorse or promote products derived from this
19  *    software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 
35 /**
36  * @brief Module that defines the Low Power Timer Abstraction Layer for the nrf_802154_sl_timer service
37  *
38  * @details
39  * Design claims:
40  * 1. lptimer works in @c lpticks (Low Power Timer Ticks), it is not aware of other timer units with
41  *    exception to convenience functions for calculating lpticks to other units.
42  * 2. One @c lptick is at least 1 microsecond, but can be greater.
43  * 3. lptimer can rarely fire spurious "timer fired" callout as well as rarely perform spurious (D)PPI
44  *    triggering (if connections have been made). This phenomena should be avoided, but modules relying
45  *    on lptimer must be immune to such behavior.
46  * 4. lptimer counts @c lpticks as @c uint64_t type, handling (and hiding from higher layers) any
47  *    underlying RTC overflow events.
48  */
49 
50 #ifndef NRF_802154_PLATFORM_SL_LPTIMER_H_
51 #define NRF_802154_PLATFORM_SL_LPTIMER_H_
52 
53 #include <stdint.h>
54 #include <stdbool.h>
55 
56 #ifdef __cplusplus
57 extern "C" {
58 #endif
59 
60 /**@brief Special value to use when no (D)PPI configuration is requested. */
61 #define NRF_802154_SL_HW_TASK_PPI_INVALID UINT32_MAX
62 
63 /**@brief Type of result returned by LPTIMER platform functions. */
64 typedef uint32_t nrf_802154_sl_lptimer_platform_result_t;
65 
66 /**@brief Operation performed successfully. */
67 #define NRF_802154_SL_LPTIMER_PLATFORM_SUCCESS      0
68 
69 /**@brief The timer was scheduled too early in the future. */
70 #define NRF_802154_SL_LPTIMER_PLATFORM_TOO_LATE     1
71 
72 /**@brief The timer was scheduled too far in the future. */
73 #define NRF_802154_SL_LPTIMER_PLATFORM_TOO_DISTANT  2
74 
75 /**@brief No free hardware resources available to perform the operation. */
76 #define NRF_802154_SL_LPTIMER_PLATFORM_NO_RESOURCES 3
77 
78 /**@brief Operation could not be completed due to a wrong state. */
79 #define NRF_802154_SL_LPTIMER_PLATFORM_WRONG_STATE  4
80 
81 /** @brief Initializes the Timer.
82  */
83 void nrf_802154_platform_sl_lp_timer_init(void);
84 
85 /** @brief Deinitializes the Timer.
86  */
87 void nrf_802154_platform_sl_lp_timer_deinit(void);
88 
89 /**@brief Returns current state of the lptimer in @c lpticks .
90  */
91 uint64_t nrf_802154_platform_sl_lptimer_current_lpticks_get(void);
92 
93 /**@brief Converts time in microseconds to @c lpticks
94  *
95  * @param[in] us         Number of microseconds to convert.
96  * @param[in] round_up   @c true, to force rounding up. @c false to round down.
97  *
98  * @return Time corresponding to @p us in @c lpticks.
99  */
100 uint64_t nrf_802154_platform_sl_lptimer_us_to_lpticks_convert(uint64_t us, bool round_up);
101 
102 /**@brief Converts time in @c lpticks to microseconds.
103  *
104  * @param[in] lpticks   Number of lpticks to convert.
105  *
106  * @return Time corresponding to @p lpticks in microseconds.
107  */
108 uint64_t nrf_802154_platform_sl_lptimer_lpticks_to_us_convert(uint64_t lpticks);
109 
110 /**@brief Schedules a lptimer event to happen at given time.
111  *
112  * @param[in]   fire_lpticks    Timer state (in @c lpticks) at which timer event should fire.
113  *                              If @p fire_lpticks are in the past, the lptimer event will be triggered
114  *                              asap, but still from the context of an lptimer's ISR. If
115  *                              @ref nrf_802154_platform_sl_lptimer_critical_section_enter is
116  *                              in effect, processing will be delayed until pending interrupt
117  *                              can be processed.
118  */
119 void nrf_802154_platform_sl_lptimer_schedule_at(uint64_t fire_lpticks);
120 
121 /**@brief Disables generation of any event scheduled by @ref nrf_802154_platform_sl_lptimer_schedule_at
122  *
123  * @note If called from ISR priority higher than the priority from which
124  * @ref nrf_802154_sl_timer_handler is called, the @ref nrf_802154_sl_timer_handler function
125  * may be still called after @ref nrf_802154_platform_sl_lptimer_disable. It is due to the fact
126  * that ISR can be preempted in such way, that decision to call @ref nrf_802154_sl_timer_handler
127  * has already been taken and the call is inevitable (or is already in process of execution)
128  */
129 void nrf_802154_platform_sl_lptimer_disable(void);
130 
131 /**@brief Enters into critical section of the lptimer module.
132  * @note Critical section can be nested
133  *
134  * Inside critical section calls to @ref nrf_802154_sl_timer_handler do not happen. This
135  * includes indirect effect of calling @ref nrf_802154_platform_sl_lptimer_schedule_at. If necessary
136  * the interrupt calling the @ref nrf_802154_sl_timer_handler function it will remain pending
137  * at least until a corresponding call to @ref nrf_802154_platform_sl_lptimer_critical_section_exit.
138  */
139 void nrf_802154_platform_sl_lptimer_critical_section_enter(void);
140 
141 /**@brief Exits out of critical section of the lptimer module.
142  */
143 void nrf_802154_platform_sl_lptimer_critical_section_exit(void);
144 
145 /**@brief Prepares hardware bindings for triggering hardware task.
146  *
147  * This function configures timer compare channel to fire at a specified time and publish
148  * the signal to a specific PPI channel. The PPI channel may initially be set to
149  * @ref NRF_802154_SL_HW_TASK_PPI_INVALID and later updated with
150  * @ref nrf_802154_platform_sl_lptimer_hw_task_update_ppi.
151  *
152  * @param[in]  fire_lpticks  Timer state (in @c lpticks) at which timer event should fire.
153  * @param[in]  ppi_channel   (D)PPI channel that compare event will be published to.
154  *
155  * @retval NRF_802154_SL_LPTIMER_PLATFORM_SUCCESS
156  *      The timer was started successfuly and (D)PPI channel was connected, if requested.
157  * @retval NRF_802154_SL_LPTIMER_PLATFORM_TOO_LATE
158  *      The timer was scheduled too early in the future. The (D)PPI channel was not connected.
159  * @retval NRF_802154_SL_LPTIMER_PLATFORM_TOO_DISTANT
160  *      The timer was scheduled too far in the future. The (D)PPI channel was not connected.
161  * @retval NRF_802154_SL_LPTIMER_PLATFORM_NO_RESOURCES
162  *      No available compare channels to schedule a timer. The (D)PPI channel was not connected.
163  */
164 nrf_802154_sl_lptimer_platform_result_t nrf_802154_platform_sl_lptimer_hw_task_prepare(
165     uint64_t fire_lpticks,
166     uint32_t ppi_channel);
167 
168 /**@brief Removes hardware bindings created for hardware task and stops the timer.
169  *
170  * @retval NRF_802154_SL_LPTIMER_PLATFORM_SUCCESS
171  *      The cleaning was successful.
172  * @retval NRF_802154_SL_LPTIMER_PLATFORM_WRONG_STATE
173  *      Cleaning was not performed because the module is in an unsuitable state.
174  */
175 nrf_802154_sl_lptimer_platform_result_t nrf_802154_platform_sl_lptimer_hw_task_cleanup(void);
176 
177 /**@brief Updates the hardware bindings for triggering hardware task.
178  *
179  * If the timer was started with @ref nrf_802154_platform_sl_lptimer_hw_task_prepare
180  * without specifying a valid (D)PPI channel (@ref NRF_802154_SL_HW_TASK_PPI_INVALID)
181  * it is possible to use this function to update the (D)PPI channel to a valid one.
182  *
183  * @param[in]  ppi_channel  (D)PPI channel that compare event will be published to.
184  *
185  * @retval NRF_802154_SL_LPTIMER_PLATFORM_SUCCESS
186  *      The (D)PPI channel was connected and it was done on time, i.e. before specified
187  *      fire time.
188  * @retval NRF_802154_SL_LPTIMER_PLATFORM_TOO_LATE
189  *      The (D)PPI channel was connected, but it is not sure if it was done in time:
190  *      it has been detected that the timer has already fired.
191  * @retval NRF_802154_SL_LPTIMER_PLATFORM_WRONG_STATE
192  *      The (D)PPI channel was not connected, because the timer is not properly configured.
193  */
194 nrf_802154_sl_lptimer_platform_result_t nrf_802154_platform_sl_lptimer_hw_task_update_ppi(
195     uint32_t ppi_channel);
196 
197 /**
198  * @brief Starts a one-shot synchronization timer that expires at the nearest possible timepoint.
199  *
200  * On timer expiration, the @ref nrf_802154_sl_timestamper_synchronized function is called and the
201  * event returned by @ref nrf_802154_platform_sl_lptimer_sync_event_get is triggered.
202  *
203  * @note @ref nrf_802154_sl_timestamper_synchronized may be called multiple times.
204  */
205 void nrf_802154_platform_sl_lptimer_sync_schedule_now(void);
206 
207 /**
208  * @brief Starts a one-shot synchronization timer that expires at the specified time.
209  *
210  * This function starts a one-shot synchronization timer that expires at @p fire_lpticks.
211  *
212  * On timer expiration, @ref nrf_802154_sl_timestamper_synchronized function is called and
213  * the event returned by @ref nrf_802154_platform_sl_lptimer_sync_event_get is triggered.
214  *
215  * @param[in]  fire_lpticks  Timer state (in @c lpticks) at which timer event should fire.
216  */
217 void nrf_802154_platform_sl_lptimer_sync_schedule_at(uint64_t fire_lpticks);
218 
219 /**
220  * @brief Stops the currently running synchronization timer.
221  */
222 void nrf_802154_platform_sl_lptimer_sync_abort(void);
223 
224 /**
225  * @brief Gets the event used to synchronize this timer with the HP Timer.
226  *
227  * @returns  Address of the peripheral register corresponding to the event
228  *           to be used for the timer synchronization.
229  *
230  */
231 uint32_t nrf_802154_platform_sl_lptimer_sync_event_get(void);
232 
233 /**
234  * @brief Gets the timestamp of the synchronization event.
235  *
236  * @returns  Timestamp of the synchronization event.
237  */
238 uint64_t nrf_802154_platform_sl_lptimer_sync_lpticks_get(void);
239 
240 /**
241  * @brief Gets the granularity of the timer.
242  *
243  * This function can be used to round up or round down the time calculations.
244  *
245  * @returns Timer granularity in microseconds.
246  */
247 uint32_t nrf_802154_platform_sl_lptimer_granularity_get(void);
248 
249 /**@brief Handler called from an ISR of lptimer.
250  *
251  * @param now_lpticks   Specifies moment in time at which the handler is triggered.
252  */
253 extern void nrf_802154_sl_timer_handler(uint64_t now_lpticks);
254 
255 /**
256  * @brief Callback function executed when the synchronization timer expires.
257  */
258 extern void nrf_802154_sl_timestamper_synchronized(void);
259 
260 #ifdef __cplusplus
261 }
262 #endif
263 
264 #endif // NRF_802154_PLATFORM_SL_LPTIMER_H_
265