xref: /nrf52832-nimble/packages/NimBLE-latest/porting/nimble/src/hal_timer.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1*042d53a7SEvalZero /*
2*042d53a7SEvalZero  * Licensed to the Apache Software Foundation (ASF) under one
3*042d53a7SEvalZero  * or more contributor license agreements.  See the NOTICE file
4*042d53a7SEvalZero  * distributed with this work for additional information
5*042d53a7SEvalZero  * regarding copyright ownership.  The ASF licenses this file
6*042d53a7SEvalZero  * to you under the Apache License, Version 2.0 (the
7*042d53a7SEvalZero  * "License"); you may not use this file except in compliance
8*042d53a7SEvalZero  * with the License.  You may obtain a copy of the License at
9*042d53a7SEvalZero  *
10*042d53a7SEvalZero  *  http://www.apache.org/licenses/LICENSE-2.0
11*042d53a7SEvalZero  *
12*042d53a7SEvalZero  * Unless required by applicable law or agreed to in writing,
13*042d53a7SEvalZero  * software distributed under the License is distributed on an
14*042d53a7SEvalZero  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15*042d53a7SEvalZero  * KIND, either express or implied.  See the License for the
16*042d53a7SEvalZero  * specific language governing permissions and limitations
17*042d53a7SEvalZero  * under the License.
18*042d53a7SEvalZero  */
19*042d53a7SEvalZero 
20*042d53a7SEvalZero #include <string.h>
21*042d53a7SEvalZero #include <stdint.h>
22*042d53a7SEvalZero #include <assert.h>
23*042d53a7SEvalZero #include <errno.h>
24*042d53a7SEvalZero #include "os/os.h"
25*042d53a7SEvalZero #include "nrfx.h"
26*042d53a7SEvalZero #include "hal/hal_timer.h"
27*042d53a7SEvalZero 
28*042d53a7SEvalZero #define __HAL_DISABLE_INTERRUPTS(x)                     \
29*042d53a7SEvalZero     do {                                                \
30*042d53a7SEvalZero         x = __get_PRIMASK();                            \
31*042d53a7SEvalZero         __disable_irq();                                \
32*042d53a7SEvalZero     } while(0);
33*042d53a7SEvalZero 
34*042d53a7SEvalZero #define __HAL_ENABLE_INTERRUPTS(x)                      \
35*042d53a7SEvalZero     do {                                                \
36*042d53a7SEvalZero         if (!x) {                                       \
37*042d53a7SEvalZero             __enable_irq();                             \
38*042d53a7SEvalZero         }                                               \
39*042d53a7SEvalZero     } while(0);
40*042d53a7SEvalZero 
41*042d53a7SEvalZero /* IRQ prototype */
42*042d53a7SEvalZero typedef void (*hal_timer_irq_handler_t)(void);
43*042d53a7SEvalZero 
44*042d53a7SEvalZero /* User CC 2 for reading counter, CC 3 for timer isr */
45*042d53a7SEvalZero #define NRF_TIMER_CC_READ       (2)
46*042d53a7SEvalZero #define NRF_TIMER_CC_INT        (3)
47*042d53a7SEvalZero 
48*042d53a7SEvalZero /* Output compare 2 used for RTC timers */
49*042d53a7SEvalZero #define NRF_RTC_TIMER_CC_INT    (2)
50*042d53a7SEvalZero 
51*042d53a7SEvalZero /* Maximum number of hal timers used */
52*042d53a7SEvalZero #define NRF52_HAL_TIMER_MAX     (6)
53*042d53a7SEvalZero 
54*042d53a7SEvalZero /* Maximum timer frequency */
55*042d53a7SEvalZero #define NRF52_MAX_TIMER_FREQ    (16000000)
56*042d53a7SEvalZero 
57*042d53a7SEvalZero struct nrf52_hal_timer {
58*042d53a7SEvalZero     uint8_t tmr_enabled;
59*042d53a7SEvalZero     uint8_t tmr_irq_num;
60*042d53a7SEvalZero     uint8_t tmr_rtc;
61*042d53a7SEvalZero     uint8_t tmr_pad;
62*042d53a7SEvalZero     uint32_t tmr_cntr;
63*042d53a7SEvalZero     uint32_t timer_isrs;
64*042d53a7SEvalZero     uint32_t tmr_freq;
65*042d53a7SEvalZero     void *tmr_reg;
66*042d53a7SEvalZero     TAILQ_HEAD(hal_timer_qhead, hal_timer) hal_timer_q;
67*042d53a7SEvalZero };
68*042d53a7SEvalZero 
69*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_0)
70*042d53a7SEvalZero struct nrf52_hal_timer nrf52_hal_timer0;
71*042d53a7SEvalZero #endif
72*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_1)
73*042d53a7SEvalZero struct nrf52_hal_timer nrf52_hal_timer1;
74*042d53a7SEvalZero #endif
75*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_2)
76*042d53a7SEvalZero struct nrf52_hal_timer nrf52_hal_timer2;
77*042d53a7SEvalZero #endif
78*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_3)
79*042d53a7SEvalZero struct nrf52_hal_timer nrf52_hal_timer3;
80*042d53a7SEvalZero #endif
81*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_4)
82*042d53a7SEvalZero struct nrf52_hal_timer nrf52_hal_timer4;
83*042d53a7SEvalZero #endif
84*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_5)
85*042d53a7SEvalZero struct nrf52_hal_timer nrf52_hal_timer5;
86*042d53a7SEvalZero #endif
87*042d53a7SEvalZero 
88*042d53a7SEvalZero static const struct nrf52_hal_timer *nrf52_hal_timers[NRF52_HAL_TIMER_MAX] = {
89*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_0)
90*042d53a7SEvalZero     &nrf52_hal_timer0,
91*042d53a7SEvalZero #else
92*042d53a7SEvalZero     NULL,
93*042d53a7SEvalZero #endif
94*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_1)
95*042d53a7SEvalZero     &nrf52_hal_timer1,
96*042d53a7SEvalZero #else
97*042d53a7SEvalZero     NULL,
98*042d53a7SEvalZero #endif
99*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_2)
100*042d53a7SEvalZero     &nrf52_hal_timer2,
101*042d53a7SEvalZero #else
102*042d53a7SEvalZero     NULL,
103*042d53a7SEvalZero #endif
104*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_3)
105*042d53a7SEvalZero     &nrf52_hal_timer3,
106*042d53a7SEvalZero #else
107*042d53a7SEvalZero     NULL,
108*042d53a7SEvalZero #endif
109*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_4)
110*042d53a7SEvalZero     &nrf52_hal_timer4,
111*042d53a7SEvalZero #else
112*042d53a7SEvalZero     NULL,
113*042d53a7SEvalZero #endif
114*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_5)
115*042d53a7SEvalZero     &nrf52_hal_timer5
116*042d53a7SEvalZero #else
117*042d53a7SEvalZero     NULL
118*042d53a7SEvalZero #endif
119*042d53a7SEvalZero };
120*042d53a7SEvalZero 
121*042d53a7SEvalZero /* Resolve timer number into timer structure */
122*042d53a7SEvalZero #define NRF52_HAL_TIMER_RESOLVE(__n, __v)       \
123*042d53a7SEvalZero     if ((__n) >= NRF52_HAL_TIMER_MAX) {         \
124*042d53a7SEvalZero         rc = EINVAL;                            \
125*042d53a7SEvalZero         goto err;                               \
126*042d53a7SEvalZero     }                                           \
127*042d53a7SEvalZero     (__v) = (struct nrf52_hal_timer *) nrf52_hal_timers[(__n)];            \
128*042d53a7SEvalZero     if ((__v) == NULL) {                        \
129*042d53a7SEvalZero         rc = EINVAL;                            \
130*042d53a7SEvalZero         goto err;                               \
131*042d53a7SEvalZero     }
132*042d53a7SEvalZero 
133*042d53a7SEvalZero /* Interrupt mask for interrupt enable/clear */
134*042d53a7SEvalZero #define NRF_TIMER_INT_MASK(x)    ((1 << (uint32_t)(x)) << 16)
135*042d53a7SEvalZero 
136*042d53a7SEvalZero static uint32_t
nrf_read_timer_cntr(NRF_TIMER_Type * hwtimer)137*042d53a7SEvalZero nrf_read_timer_cntr(NRF_TIMER_Type *hwtimer)
138*042d53a7SEvalZero {
139*042d53a7SEvalZero     uint32_t tcntr;
140*042d53a7SEvalZero 
141*042d53a7SEvalZero     /* Force a capture of the timer into 'cntr' capture channel; read it */
142*042d53a7SEvalZero     hwtimer->TASKS_CAPTURE[NRF_TIMER_CC_READ] = 1;
143*042d53a7SEvalZero     tcntr = hwtimer->CC[NRF_TIMER_CC_READ];
144*042d53a7SEvalZero 
145*042d53a7SEvalZero     return tcntr;
146*042d53a7SEvalZero }
147*042d53a7SEvalZero 
148*042d53a7SEvalZero /**
149*042d53a7SEvalZero  * nrf timer set ocmp
150*042d53a7SEvalZero  *
151*042d53a7SEvalZero  * Set the OCMP used by the timer to the desired expiration tick
152*042d53a7SEvalZero  *
153*042d53a7SEvalZero  * NOTE: Must be called with interrupts disabled.
154*042d53a7SEvalZero  *
155*042d53a7SEvalZero  * @param timer Pointer to timer.
156*042d53a7SEvalZero  */
157*042d53a7SEvalZero static void
nrf_timer_set_ocmp(struct nrf52_hal_timer * bsptimer,uint32_t expiry)158*042d53a7SEvalZero nrf_timer_set_ocmp(struct nrf52_hal_timer *bsptimer, uint32_t expiry)
159*042d53a7SEvalZero {
160*042d53a7SEvalZero     int32_t delta_t;
161*042d53a7SEvalZero     uint32_t temp;
162*042d53a7SEvalZero     uint32_t cntr;
163*042d53a7SEvalZero     NRF_TIMER_Type *hwtimer;
164*042d53a7SEvalZero     NRF_RTC_Type *rtctimer;
165*042d53a7SEvalZero 
166*042d53a7SEvalZero     if (bsptimer->tmr_rtc) {
167*042d53a7SEvalZero         rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg;
168*042d53a7SEvalZero         rtctimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT);
169*042d53a7SEvalZero         temp = bsptimer->tmr_cntr;
170*042d53a7SEvalZero         cntr = rtctimer->COUNTER;
171*042d53a7SEvalZero         if (rtctimer->EVENTS_OVRFLW) {
172*042d53a7SEvalZero             temp += (1UL << 24);
173*042d53a7SEvalZero             cntr = rtctimer->COUNTER;
174*042d53a7SEvalZero         }
175*042d53a7SEvalZero         temp |= cntr;
176*042d53a7SEvalZero         delta_t = (int32_t)(expiry - temp);
177*042d53a7SEvalZero 
178*042d53a7SEvalZero         /*
179*042d53a7SEvalZero          * The nrf documentation states that you must set the output
180*042d53a7SEvalZero          * compare to 2 greater than the counter to guarantee an interrupt.
181*042d53a7SEvalZero          * Since the counter can tick once while we check, we make sure
182*042d53a7SEvalZero          * it is greater than 2.
183*042d53a7SEvalZero          */
184*042d53a7SEvalZero         if (delta_t < 3) {
185*042d53a7SEvalZero             NVIC_SetPendingIRQ(bsptimer->tmr_irq_num);
186*042d53a7SEvalZero         } else  {
187*042d53a7SEvalZero             if (delta_t < (1UL << 24)) {
188*042d53a7SEvalZero                 rtctimer->CC[NRF_RTC_TIMER_CC_INT] = expiry & 0x00ffffff;
189*042d53a7SEvalZero             } else {
190*042d53a7SEvalZero                 /* CC too far ahead. Just make sure we set compare far ahead */
191*042d53a7SEvalZero                 rtctimer->CC[NRF_RTC_TIMER_CC_INT] = cntr + (1UL << 23);
192*042d53a7SEvalZero             }
193*042d53a7SEvalZero             rtctimer->INTENSET = NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT);
194*042d53a7SEvalZero         }
195*042d53a7SEvalZero     } else {
196*042d53a7SEvalZero         hwtimer = bsptimer->tmr_reg;
197*042d53a7SEvalZero 
198*042d53a7SEvalZero         /* Disable ocmp interrupt and set new value */
199*042d53a7SEvalZero         hwtimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT);
200*042d53a7SEvalZero 
201*042d53a7SEvalZero         /* Set output compare register to timer expiration */
202*042d53a7SEvalZero         hwtimer->CC[NRF_TIMER_CC_INT] = expiry;
203*042d53a7SEvalZero 
204*042d53a7SEvalZero         /* Clear interrupt flag */
205*042d53a7SEvalZero         hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT] = 0;
206*042d53a7SEvalZero 
207*042d53a7SEvalZero         /* Enable the output compare interrupt */
208*042d53a7SEvalZero         hwtimer->INTENSET = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT);
209*042d53a7SEvalZero 
210*042d53a7SEvalZero         /* Force interrupt to occur as we may have missed it */
211*042d53a7SEvalZero         if ((int32_t)(nrf_read_timer_cntr(hwtimer) - expiry) >= 0) {
212*042d53a7SEvalZero             NVIC_SetPendingIRQ(bsptimer->tmr_irq_num);
213*042d53a7SEvalZero         }
214*042d53a7SEvalZero     }
215*042d53a7SEvalZero }
216*042d53a7SEvalZero 
217*042d53a7SEvalZero /* Disable output compare used for timer */
218*042d53a7SEvalZero static void
nrf_timer_disable_ocmp(NRF_TIMER_Type * hwtimer)219*042d53a7SEvalZero nrf_timer_disable_ocmp(NRF_TIMER_Type *hwtimer)
220*042d53a7SEvalZero {
221*042d53a7SEvalZero     hwtimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT);
222*042d53a7SEvalZero }
223*042d53a7SEvalZero 
224*042d53a7SEvalZero static void
nrf_rtc_disable_ocmp(NRF_RTC_Type * rtctimer)225*042d53a7SEvalZero nrf_rtc_disable_ocmp(NRF_RTC_Type *rtctimer)
226*042d53a7SEvalZero {
227*042d53a7SEvalZero     rtctimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT);
228*042d53a7SEvalZero }
229*042d53a7SEvalZero 
230*042d53a7SEvalZero static uint32_t
hal_timer_read_bsptimer(struct nrf52_hal_timer * bsptimer)231*042d53a7SEvalZero hal_timer_read_bsptimer(struct nrf52_hal_timer *bsptimer)
232*042d53a7SEvalZero {
233*042d53a7SEvalZero     uint32_t low32;
234*042d53a7SEvalZero     uint32_t ctx;
235*042d53a7SEvalZero     uint32_t tcntr;
236*042d53a7SEvalZero     NRF_RTC_Type *rtctimer;
237*042d53a7SEvalZero 
238*042d53a7SEvalZero     rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg;
239*042d53a7SEvalZero     __HAL_DISABLE_INTERRUPTS(ctx);
240*042d53a7SEvalZero     tcntr = bsptimer->tmr_cntr;
241*042d53a7SEvalZero     low32 = rtctimer->COUNTER;
242*042d53a7SEvalZero     if (rtctimer->EVENTS_OVRFLW) {
243*042d53a7SEvalZero         tcntr += (1UL << 24);
244*042d53a7SEvalZero         bsptimer->tmr_cntr = tcntr;
245*042d53a7SEvalZero         low32 = rtctimer->COUNTER;
246*042d53a7SEvalZero         rtctimer->EVENTS_OVRFLW = 0;
247*042d53a7SEvalZero         NVIC_SetPendingIRQ(bsptimer->tmr_irq_num);
248*042d53a7SEvalZero     }
249*042d53a7SEvalZero     tcntr |= low32;
250*042d53a7SEvalZero     __HAL_ENABLE_INTERRUPTS(ctx);
251*042d53a7SEvalZero 
252*042d53a7SEvalZero     return tcntr;
253*042d53a7SEvalZero }
254*042d53a7SEvalZero 
255*042d53a7SEvalZero #if (MYNEWT_VAL(TIMER_0) || MYNEWT_VAL(TIMER_1) || MYNEWT_VAL(TIMER_2) || \
256*042d53a7SEvalZero      MYNEWT_VAL(TIMER_3) || MYNEWT_VAL(TIMER_4) || MYNEWT_VAL(TIMER_5))
257*042d53a7SEvalZero /**
258*042d53a7SEvalZero  * hal timer chk queue
259*042d53a7SEvalZero  *
260*042d53a7SEvalZero  *
261*042d53a7SEvalZero  * @param bsptimer
262*042d53a7SEvalZero  */
263*042d53a7SEvalZero static void
hal_timer_chk_queue(struct nrf52_hal_timer * bsptimer)264*042d53a7SEvalZero hal_timer_chk_queue(struct nrf52_hal_timer *bsptimer)
265*042d53a7SEvalZero {
266*042d53a7SEvalZero     int32_t delta;
267*042d53a7SEvalZero     uint32_t tcntr;
268*042d53a7SEvalZero     uint32_t ctx;
269*042d53a7SEvalZero     struct hal_timer *timer;
270*042d53a7SEvalZero 
271*042d53a7SEvalZero     /* disable interrupts */
272*042d53a7SEvalZero     __HAL_DISABLE_INTERRUPTS(ctx);
273*042d53a7SEvalZero     while ((timer = TAILQ_FIRST(&bsptimer->hal_timer_q)) != NULL) {
274*042d53a7SEvalZero         if (bsptimer->tmr_rtc) {
275*042d53a7SEvalZero             tcntr = hal_timer_read_bsptimer(bsptimer);
276*042d53a7SEvalZero             /*
277*042d53a7SEvalZero              * If we are within 3 ticks of RTC, we wont be able to set compare.
278*042d53a7SEvalZero              * Thus, we have to service this timer early.
279*042d53a7SEvalZero              */
280*042d53a7SEvalZero             delta = -3;
281*042d53a7SEvalZero         } else {
282*042d53a7SEvalZero             tcntr = nrf_read_timer_cntr(bsptimer->tmr_reg);
283*042d53a7SEvalZero             delta = 0;
284*042d53a7SEvalZero         }
285*042d53a7SEvalZero         if ((int32_t)(tcntr - timer->expiry) >= delta) {
286*042d53a7SEvalZero             TAILQ_REMOVE(&bsptimer->hal_timer_q, timer, link);
287*042d53a7SEvalZero             timer->link.tqe_prev = NULL;
288*042d53a7SEvalZero             timer->cb_func(timer->cb_arg);
289*042d53a7SEvalZero         } else {
290*042d53a7SEvalZero             break;
291*042d53a7SEvalZero         }
292*042d53a7SEvalZero     }
293*042d53a7SEvalZero 
294*042d53a7SEvalZero     /* Any timers left on queue? If so, we need to set OCMP */
295*042d53a7SEvalZero     timer = TAILQ_FIRST(&bsptimer->hal_timer_q);
296*042d53a7SEvalZero     if (timer) {
297*042d53a7SEvalZero         nrf_timer_set_ocmp(bsptimer, timer->expiry);
298*042d53a7SEvalZero     } else {
299*042d53a7SEvalZero         if (bsptimer->tmr_rtc) {
300*042d53a7SEvalZero             nrf_rtc_disable_ocmp((NRF_RTC_Type *)bsptimer->tmr_reg);
301*042d53a7SEvalZero         } else {
302*042d53a7SEvalZero             nrf_timer_disable_ocmp(bsptimer->tmr_reg);
303*042d53a7SEvalZero         }
304*042d53a7SEvalZero     }
305*042d53a7SEvalZero     __HAL_ENABLE_INTERRUPTS(ctx);
306*042d53a7SEvalZero }
307*042d53a7SEvalZero #endif
308*042d53a7SEvalZero 
309*042d53a7SEvalZero /**
310*042d53a7SEvalZero  * hal timer irq handler
311*042d53a7SEvalZero  *
312*042d53a7SEvalZero  * Generic HAL timer irq handler.
313*042d53a7SEvalZero  *
314*042d53a7SEvalZero  * @param tmr
315*042d53a7SEvalZero  */
316*042d53a7SEvalZero /**
317*042d53a7SEvalZero  * hal timer irq handler
318*042d53a7SEvalZero  *
319*042d53a7SEvalZero  * This is the global timer interrupt routine.
320*042d53a7SEvalZero  *
321*042d53a7SEvalZero  */
322*042d53a7SEvalZero #if (MYNEWT_VAL(TIMER_0) || MYNEWT_VAL(TIMER_1) || MYNEWT_VAL(TIMER_2) || \
323*042d53a7SEvalZero      MYNEWT_VAL(TIMER_3) || MYNEWT_VAL(TIMER_4))
324*042d53a7SEvalZero 
325*042d53a7SEvalZero static void
hal_timer_irq_handler(struct nrf52_hal_timer * bsptimer)326*042d53a7SEvalZero hal_timer_irq_handler(struct nrf52_hal_timer *bsptimer)
327*042d53a7SEvalZero {
328*042d53a7SEvalZero     uint32_t compare;
329*042d53a7SEvalZero     NRF_TIMER_Type *hwtimer;
330*042d53a7SEvalZero 
331*042d53a7SEvalZero     os_trace_enter_isr();
332*042d53a7SEvalZero 
333*042d53a7SEvalZero     /* Check interrupt source. If set, clear them */
334*042d53a7SEvalZero     hwtimer = bsptimer->tmr_reg;
335*042d53a7SEvalZero     compare = hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT];
336*042d53a7SEvalZero     if (compare) {
337*042d53a7SEvalZero         hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT] = 0;
338*042d53a7SEvalZero     }
339*042d53a7SEvalZero 
340*042d53a7SEvalZero     /* XXX: make these stats? */
341*042d53a7SEvalZero     /* Count # of timer isrs */
342*042d53a7SEvalZero     ++bsptimer->timer_isrs;
343*042d53a7SEvalZero 
344*042d53a7SEvalZero     /*
345*042d53a7SEvalZero      * NOTE: we dont check the 'compare' variable here due to how the timer
346*042d53a7SEvalZero      * is implemented on this chip. There is no way to force an output
347*042d53a7SEvalZero      * compare, so if we are late setting the output compare (i.e. the timer
348*042d53a7SEvalZero      * counter is already passed the output compare value), we use the NVIC
349*042d53a7SEvalZero      * to set a pending interrupt. This means that there will be no compare
350*042d53a7SEvalZero      * flag set, so all we do is check to see if the compare interrupt is
351*042d53a7SEvalZero      * enabled.
352*042d53a7SEvalZero      */
353*042d53a7SEvalZero     if (hwtimer->INTENCLR & NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT)) {
354*042d53a7SEvalZero         hal_timer_chk_queue(bsptimer);
355*042d53a7SEvalZero         /* XXX: Recommended by nordic to make sure interrupts are cleared */
356*042d53a7SEvalZero         compare = hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT];
357*042d53a7SEvalZero     }
358*042d53a7SEvalZero 
359*042d53a7SEvalZero     os_trace_exit_isr();
360*042d53a7SEvalZero }
361*042d53a7SEvalZero #endif
362*042d53a7SEvalZero 
363*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_5)
364*042d53a7SEvalZero static void
hal_rtc_timer_irq_handler(struct nrf52_hal_timer * bsptimer)365*042d53a7SEvalZero hal_rtc_timer_irq_handler(struct nrf52_hal_timer *bsptimer)
366*042d53a7SEvalZero {
367*042d53a7SEvalZero     uint32_t overflow;
368*042d53a7SEvalZero     uint32_t compare;
369*042d53a7SEvalZero     NRF_RTC_Type *rtctimer;
370*042d53a7SEvalZero 
371*042d53a7SEvalZero     /* Check interrupt source. If set, clear them */
372*042d53a7SEvalZero     rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg;
373*042d53a7SEvalZero     compare = rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT];
374*042d53a7SEvalZero     if (compare) {
375*042d53a7SEvalZero        rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT] = 0;
376*042d53a7SEvalZero     }
377*042d53a7SEvalZero 
378*042d53a7SEvalZero     overflow = rtctimer->EVENTS_OVRFLW;
379*042d53a7SEvalZero     if (overflow) {
380*042d53a7SEvalZero         rtctimer->EVENTS_OVRFLW = 0;
381*042d53a7SEvalZero         bsptimer->tmr_cntr += (1UL << 24);
382*042d53a7SEvalZero     }
383*042d53a7SEvalZero 
384*042d53a7SEvalZero     /* Count # of timer isrs */
385*042d53a7SEvalZero     ++bsptimer->timer_isrs;
386*042d53a7SEvalZero 
387*042d53a7SEvalZero     /*
388*042d53a7SEvalZero      * NOTE: we dont check the 'compare' variable here due to how the timer
389*042d53a7SEvalZero      * is implemented on this chip. There is no way to force an output
390*042d53a7SEvalZero      * compare, so if we are late setting the output compare (i.e. the timer
391*042d53a7SEvalZero      * counter is already passed the output compare value), we use the NVIC
392*042d53a7SEvalZero      * to set a pending interrupt. This means that there will be no compare
393*042d53a7SEvalZero      * flag set, so all we do is check to see if the compare interrupt is
394*042d53a7SEvalZero      * enabled.
395*042d53a7SEvalZero      */
396*042d53a7SEvalZero     hal_timer_chk_queue(bsptimer);
397*042d53a7SEvalZero 
398*042d53a7SEvalZero     /* Recommended by nordic to make sure interrupts are cleared */
399*042d53a7SEvalZero     compare = rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT];
400*042d53a7SEvalZero }
401*042d53a7SEvalZero #endif
402*042d53a7SEvalZero 
403*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_0)
404*042d53a7SEvalZero void
nrf52_timer0_irq_handler(void)405*042d53a7SEvalZero nrf52_timer0_irq_handler(void)
406*042d53a7SEvalZero {
407*042d53a7SEvalZero     hal_timer_irq_handler(&nrf52_hal_timer0);
408*042d53a7SEvalZero }
409*042d53a7SEvalZero #endif
410*042d53a7SEvalZero 
411*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_1)
412*042d53a7SEvalZero void
nrf52_timer1_irq_handler(void)413*042d53a7SEvalZero nrf52_timer1_irq_handler(void)
414*042d53a7SEvalZero {
415*042d53a7SEvalZero     hal_timer_irq_handler(&nrf52_hal_timer1);
416*042d53a7SEvalZero }
417*042d53a7SEvalZero #endif
418*042d53a7SEvalZero 
419*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_2)
420*042d53a7SEvalZero void
nrf52_timer2_irq_handler(void)421*042d53a7SEvalZero nrf52_timer2_irq_handler(void)
422*042d53a7SEvalZero {
423*042d53a7SEvalZero     hal_timer_irq_handler(&nrf52_hal_timer2);
424*042d53a7SEvalZero }
425*042d53a7SEvalZero #endif
426*042d53a7SEvalZero 
427*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_3)
428*042d53a7SEvalZero void
nrf52_timer3_irq_handler(void)429*042d53a7SEvalZero nrf52_timer3_irq_handler(void)
430*042d53a7SEvalZero {
431*042d53a7SEvalZero     hal_timer_irq_handler(&nrf52_hal_timer3);
432*042d53a7SEvalZero }
433*042d53a7SEvalZero #endif
434*042d53a7SEvalZero 
435*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_4)
436*042d53a7SEvalZero void
nrf52_timer4_irq_handler(void)437*042d53a7SEvalZero nrf52_timer4_irq_handler(void)
438*042d53a7SEvalZero {
439*042d53a7SEvalZero     hal_timer_irq_handler(&nrf52_hal_timer4);
440*042d53a7SEvalZero }
441*042d53a7SEvalZero #endif
442*042d53a7SEvalZero 
443*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_5)
444*042d53a7SEvalZero void
nrf52_timer5_irq_handler(void)445*042d53a7SEvalZero nrf52_timer5_irq_handler(void)
446*042d53a7SEvalZero {
447*042d53a7SEvalZero     hal_rtc_timer_irq_handler(&nrf52_hal_timer5);
448*042d53a7SEvalZero }
449*042d53a7SEvalZero #endif
450*042d53a7SEvalZero 
451*042d53a7SEvalZero /**
452*042d53a7SEvalZero  * hal timer init
453*042d53a7SEvalZero  *
454*042d53a7SEvalZero  * Initialize platform specific timer items
455*042d53a7SEvalZero  *
456*042d53a7SEvalZero  * @param timer_num     Timer number to initialize
457*042d53a7SEvalZero  * @param cfg           Pointer to platform specific configuration
458*042d53a7SEvalZero  *
459*042d53a7SEvalZero  * @return int          0: success; error code otherwise
460*042d53a7SEvalZero  */
461*042d53a7SEvalZero int
hal_timer_init(int timer_num,void * cfg)462*042d53a7SEvalZero hal_timer_init(int timer_num, void *cfg)
463*042d53a7SEvalZero {
464*042d53a7SEvalZero     int rc;
465*042d53a7SEvalZero     uint8_t irq_num;
466*042d53a7SEvalZero     struct nrf52_hal_timer *bsptimer;
467*042d53a7SEvalZero     void *hwtimer;
468*042d53a7SEvalZero     hal_timer_irq_handler_t irq_isr;
469*042d53a7SEvalZero 
470*042d53a7SEvalZero     NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
471*042d53a7SEvalZero 
472*042d53a7SEvalZero     /* If timer is enabled do not allow init */
473*042d53a7SEvalZero     if (bsptimer->tmr_enabled) {
474*042d53a7SEvalZero         rc = EINVAL;
475*042d53a7SEvalZero         goto err;
476*042d53a7SEvalZero     }
477*042d53a7SEvalZero 
478*042d53a7SEvalZero     switch (timer_num) {
479*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_5)
480*042d53a7SEvalZero     case 5:
481*042d53a7SEvalZero         irq_num = RTC0_IRQn;
482*042d53a7SEvalZero         hwtimer = NRF_RTC0;
483*042d53a7SEvalZero         irq_isr = nrf52_timer5_irq_handler;
484*042d53a7SEvalZero         bsptimer->tmr_rtc = 1;
485*042d53a7SEvalZero         break;
486*042d53a7SEvalZero #endif
487*042d53a7SEvalZero     default:
488*042d53a7SEvalZero         hwtimer = NULL;
489*042d53a7SEvalZero         break;
490*042d53a7SEvalZero     }
491*042d53a7SEvalZero 
492*042d53a7SEvalZero     if (hwtimer == NULL) {
493*042d53a7SEvalZero         rc = EINVAL;
494*042d53a7SEvalZero         goto err;
495*042d53a7SEvalZero     }
496*042d53a7SEvalZero 
497*042d53a7SEvalZero     bsptimer->tmr_reg = hwtimer;
498*042d53a7SEvalZero     bsptimer->tmr_irq_num = irq_num;
499*042d53a7SEvalZero 
500*042d53a7SEvalZero     /* Disable IRQ, set priority and set vector in table */
501*042d53a7SEvalZero     NVIC_DisableIRQ(irq_num);
502*042d53a7SEvalZero #ifndef RIOT_VERSION
503*042d53a7SEvalZero     NVIC_SetPriority(irq_num, (1 << __NVIC_PRIO_BITS) - 1);
504*042d53a7SEvalZero #endif
505*042d53a7SEvalZero #if MYNEWT
506*042d53a7SEvalZero     NVIC_SetVector(irq_num, (uint32_t)irq_isr);
507*042d53a7SEvalZero #else
508*042d53a7SEvalZero     ble_npl_hw_set_isr(irq_num, irq_isr);
509*042d53a7SEvalZero #endif
510*042d53a7SEvalZero 
511*042d53a7SEvalZero     return 0;
512*042d53a7SEvalZero 
513*042d53a7SEvalZero err:
514*042d53a7SEvalZero     return rc;
515*042d53a7SEvalZero }
516*042d53a7SEvalZero 
517*042d53a7SEvalZero /**
518*042d53a7SEvalZero  * hal timer config
519*042d53a7SEvalZero  *
520*042d53a7SEvalZero  * Configure a timer to run at the desired frequency. This starts the timer.
521*042d53a7SEvalZero  *
522*042d53a7SEvalZero  * @param timer_num
523*042d53a7SEvalZero  * @param freq_hz
524*042d53a7SEvalZero  *
525*042d53a7SEvalZero  * @return int
526*042d53a7SEvalZero  */
527*042d53a7SEvalZero int
hal_timer_config(int timer_num,uint32_t freq_hz)528*042d53a7SEvalZero hal_timer_config(int timer_num, uint32_t freq_hz)
529*042d53a7SEvalZero {
530*042d53a7SEvalZero     int rc;
531*042d53a7SEvalZero     uint32_t ctx;
532*042d53a7SEvalZero     struct nrf52_hal_timer *bsptimer;
533*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_5)
534*042d53a7SEvalZero     NRF_RTC_Type *rtctimer;
535*042d53a7SEvalZero #endif
536*042d53a7SEvalZero 
537*042d53a7SEvalZero     NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
538*042d53a7SEvalZero 
539*042d53a7SEvalZero #if MYNEWT_VAL(TIMER_5)
540*042d53a7SEvalZero     if (timer_num == 5) {
541*042d53a7SEvalZero         /* NOTE: we only allow the RTC frequency to be set at 32768 */
542*042d53a7SEvalZero         if (bsptimer->tmr_enabled || (freq_hz != 32768) ||
543*042d53a7SEvalZero             (bsptimer->tmr_reg == NULL)) {
544*042d53a7SEvalZero             rc = EINVAL;
545*042d53a7SEvalZero             goto err;
546*042d53a7SEvalZero         }
547*042d53a7SEvalZero 
548*042d53a7SEvalZero         bsptimer->tmr_freq = freq_hz;
549*042d53a7SEvalZero         bsptimer->tmr_enabled = 1;
550*042d53a7SEvalZero 
551*042d53a7SEvalZero         __HAL_DISABLE_INTERRUPTS(ctx);
552*042d53a7SEvalZero 
553*042d53a7SEvalZero         rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg;
554*042d53a7SEvalZero 
555*042d53a7SEvalZero         /* Stop the timer first */
556*042d53a7SEvalZero         rtctimer->TASKS_STOP = 1;
557*042d53a7SEvalZero 
558*042d53a7SEvalZero         /* Always no prescaler */
559*042d53a7SEvalZero         rtctimer->PRESCALER = 0;
560*042d53a7SEvalZero 
561*042d53a7SEvalZero         /* Clear overflow events and set overflow interrupt */
562*042d53a7SEvalZero         rtctimer->EVENTS_OVRFLW = 0;
563*042d53a7SEvalZero         rtctimer->INTENSET = RTC_INTENSET_OVRFLW_Msk;
564*042d53a7SEvalZero 
565*042d53a7SEvalZero         /* Start the timer */
566*042d53a7SEvalZero         rtctimer->TASKS_START = 1;
567*042d53a7SEvalZero 
568*042d53a7SEvalZero         /* Set isr in vector table and enable interrupt */
569*042d53a7SEvalZero         NVIC_EnableIRQ(bsptimer->tmr_irq_num);
570*042d53a7SEvalZero 
571*042d53a7SEvalZero         __HAL_ENABLE_INTERRUPTS(ctx);
572*042d53a7SEvalZero         return 0;
573*042d53a7SEvalZero     }
574*042d53a7SEvalZero #endif
575*042d53a7SEvalZero 
576*042d53a7SEvalZero     assert(0);
577*042d53a7SEvalZero 
578*042d53a7SEvalZero     return 0;
579*042d53a7SEvalZero 
580*042d53a7SEvalZero err:
581*042d53a7SEvalZero     return rc;
582*042d53a7SEvalZero }
583*042d53a7SEvalZero 
584*042d53a7SEvalZero /**
585*042d53a7SEvalZero  * hal timer deinit
586*042d53a7SEvalZero  *
587*042d53a7SEvalZero  * De-initialize a HW timer.
588*042d53a7SEvalZero  *
589*042d53a7SEvalZero  * @param timer_num
590*042d53a7SEvalZero  *
591*042d53a7SEvalZero  * @return int
592*042d53a7SEvalZero  */
593*042d53a7SEvalZero int
hal_timer_deinit(int timer_num)594*042d53a7SEvalZero hal_timer_deinit(int timer_num)
595*042d53a7SEvalZero {
596*042d53a7SEvalZero     int rc;
597*042d53a7SEvalZero     uint32_t ctx;
598*042d53a7SEvalZero     struct nrf52_hal_timer *bsptimer;
599*042d53a7SEvalZero     NRF_TIMER_Type *hwtimer;
600*042d53a7SEvalZero     NRF_RTC_Type *rtctimer;
601*042d53a7SEvalZero 
602*042d53a7SEvalZero     rc = 0;
603*042d53a7SEvalZero     NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
604*042d53a7SEvalZero 
605*042d53a7SEvalZero     __HAL_DISABLE_INTERRUPTS(ctx);
606*042d53a7SEvalZero     if (bsptimer->tmr_rtc) {
607*042d53a7SEvalZero         rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg;
608*042d53a7SEvalZero         rtctimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT);
609*042d53a7SEvalZero         rtctimer->TASKS_STOP = 1;
610*042d53a7SEvalZero     } else {
611*042d53a7SEvalZero         hwtimer = (NRF_TIMER_Type *)bsptimer->tmr_reg;
612*042d53a7SEvalZero         hwtimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT);
613*042d53a7SEvalZero         hwtimer->TASKS_STOP = 1;
614*042d53a7SEvalZero     }
615*042d53a7SEvalZero     bsptimer->tmr_enabled = 0;
616*042d53a7SEvalZero     bsptimer->tmr_reg = NULL;
617*042d53a7SEvalZero     __HAL_ENABLE_INTERRUPTS(ctx);
618*042d53a7SEvalZero 
619*042d53a7SEvalZero err:
620*042d53a7SEvalZero     return rc;
621*042d53a7SEvalZero }
622*042d53a7SEvalZero 
623*042d53a7SEvalZero /**
624*042d53a7SEvalZero  * hal timer get resolution
625*042d53a7SEvalZero  *
626*042d53a7SEvalZero  * Get the resolution of the timer. This is the timer period, in nanoseconds
627*042d53a7SEvalZero  *
628*042d53a7SEvalZero  * @param timer_num
629*042d53a7SEvalZero  *
630*042d53a7SEvalZero  * @return uint32_t The
631*042d53a7SEvalZero  */
632*042d53a7SEvalZero uint32_t
hal_timer_get_resolution(int timer_num)633*042d53a7SEvalZero hal_timer_get_resolution(int timer_num)
634*042d53a7SEvalZero {
635*042d53a7SEvalZero     int rc;
636*042d53a7SEvalZero     uint32_t resolution;
637*042d53a7SEvalZero     struct nrf52_hal_timer *bsptimer;
638*042d53a7SEvalZero 
639*042d53a7SEvalZero     NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
640*042d53a7SEvalZero 
641*042d53a7SEvalZero     resolution = 1000000000 / bsptimer->tmr_freq;
642*042d53a7SEvalZero     return resolution;
643*042d53a7SEvalZero 
644*042d53a7SEvalZero err:
645*042d53a7SEvalZero     rc = 0;
646*042d53a7SEvalZero     return rc;
647*042d53a7SEvalZero }
648*042d53a7SEvalZero 
649*042d53a7SEvalZero /**
650*042d53a7SEvalZero  * hal timer read
651*042d53a7SEvalZero  *
652*042d53a7SEvalZero  * Returns the timer counter. NOTE: if the timer is a 16-bit timer, only
653*042d53a7SEvalZero  * the lower 16 bits are valid. If the timer is a 64-bit timer, only the
654*042d53a7SEvalZero  * low 32-bits are returned.
655*042d53a7SEvalZero  *
656*042d53a7SEvalZero  * @return uint32_t The timer counter register.
657*042d53a7SEvalZero  */
658*042d53a7SEvalZero uint32_t
hal_timer_read(int timer_num)659*042d53a7SEvalZero hal_timer_read(int timer_num)
660*042d53a7SEvalZero {
661*042d53a7SEvalZero     int rc;
662*042d53a7SEvalZero     uint32_t tcntr;
663*042d53a7SEvalZero     struct nrf52_hal_timer *bsptimer;
664*042d53a7SEvalZero 
665*042d53a7SEvalZero     NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
666*042d53a7SEvalZero     if (bsptimer->tmr_rtc) {
667*042d53a7SEvalZero         tcntr = hal_timer_read_bsptimer(bsptimer);
668*042d53a7SEvalZero     } else {
669*042d53a7SEvalZero         tcntr = nrf_read_timer_cntr(bsptimer->tmr_reg);
670*042d53a7SEvalZero     }
671*042d53a7SEvalZero 
672*042d53a7SEvalZero     return tcntr;
673*042d53a7SEvalZero 
674*042d53a7SEvalZero     /* Assert here since there is no invalid return code */
675*042d53a7SEvalZero err:
676*042d53a7SEvalZero     assert(0);
677*042d53a7SEvalZero     rc = 0;
678*042d53a7SEvalZero     return rc;
679*042d53a7SEvalZero }
680*042d53a7SEvalZero 
681*042d53a7SEvalZero /**
682*042d53a7SEvalZero  * hal timer delay
683*042d53a7SEvalZero  *
684*042d53a7SEvalZero  * Blocking delay for n ticks
685*042d53a7SEvalZero  *
686*042d53a7SEvalZero  * @param timer_num
687*042d53a7SEvalZero  * @param ticks
688*042d53a7SEvalZero  *
689*042d53a7SEvalZero  * @return int 0 on success; error code otherwise.
690*042d53a7SEvalZero  */
691*042d53a7SEvalZero int
hal_timer_delay(int timer_num,uint32_t ticks)692*042d53a7SEvalZero hal_timer_delay(int timer_num, uint32_t ticks)
693*042d53a7SEvalZero {
694*042d53a7SEvalZero     uint32_t until;
695*042d53a7SEvalZero 
696*042d53a7SEvalZero     until = hal_timer_read(timer_num) + ticks;
697*042d53a7SEvalZero     while ((int32_t)(hal_timer_read(timer_num) - until) <= 0) {
698*042d53a7SEvalZero         /* Loop here till finished */
699*042d53a7SEvalZero     }
700*042d53a7SEvalZero 
701*042d53a7SEvalZero     return 0;
702*042d53a7SEvalZero }
703*042d53a7SEvalZero 
704*042d53a7SEvalZero /**
705*042d53a7SEvalZero  *
706*042d53a7SEvalZero  * Initialize the HAL timer structure with the callback and the callback
707*042d53a7SEvalZero  * argument. Also initializes the HW specific timer pointer.
708*042d53a7SEvalZero  *
709*042d53a7SEvalZero  * @param cb_func
710*042d53a7SEvalZero  *
711*042d53a7SEvalZero  * @return int
712*042d53a7SEvalZero  */
713*042d53a7SEvalZero int
hal_timer_set_cb(int timer_num,struct hal_timer * timer,hal_timer_cb cb_func,void * arg)714*042d53a7SEvalZero hal_timer_set_cb(int timer_num, struct hal_timer *timer, hal_timer_cb cb_func,
715*042d53a7SEvalZero                  void *arg)
716*042d53a7SEvalZero {
717*042d53a7SEvalZero     int rc;
718*042d53a7SEvalZero     struct nrf52_hal_timer *bsptimer;
719*042d53a7SEvalZero 
720*042d53a7SEvalZero     NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer);
721*042d53a7SEvalZero 
722*042d53a7SEvalZero     timer->cb_func = cb_func;
723*042d53a7SEvalZero     timer->cb_arg = arg;
724*042d53a7SEvalZero     timer->link.tqe_prev = NULL;
725*042d53a7SEvalZero     timer->bsp_timer = bsptimer;
726*042d53a7SEvalZero 
727*042d53a7SEvalZero     rc = 0;
728*042d53a7SEvalZero 
729*042d53a7SEvalZero err:
730*042d53a7SEvalZero     return rc;
731*042d53a7SEvalZero }
732*042d53a7SEvalZero 
733*042d53a7SEvalZero int
hal_timer_start(struct hal_timer * timer,uint32_t ticks)734*042d53a7SEvalZero hal_timer_start(struct hal_timer *timer, uint32_t ticks)
735*042d53a7SEvalZero {
736*042d53a7SEvalZero     int rc;
737*042d53a7SEvalZero     uint32_t tick;
738*042d53a7SEvalZero     struct nrf52_hal_timer *bsptimer;
739*042d53a7SEvalZero 
740*042d53a7SEvalZero     /* Set the tick value at which the timer should expire */
741*042d53a7SEvalZero     bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer;
742*042d53a7SEvalZero     if (bsptimer->tmr_rtc) {
743*042d53a7SEvalZero         tick = hal_timer_read_bsptimer(bsptimer) + ticks;
744*042d53a7SEvalZero     } else {
745*042d53a7SEvalZero         tick = nrf_read_timer_cntr(bsptimer->tmr_reg) + ticks;
746*042d53a7SEvalZero     }
747*042d53a7SEvalZero     rc = hal_timer_start_at(timer, tick);
748*042d53a7SEvalZero     return rc;
749*042d53a7SEvalZero }
750*042d53a7SEvalZero 
751*042d53a7SEvalZero int
hal_timer_start_at(struct hal_timer * timer,uint32_t tick)752*042d53a7SEvalZero hal_timer_start_at(struct hal_timer *timer, uint32_t tick)
753*042d53a7SEvalZero {
754*042d53a7SEvalZero     uint32_t ctx;
755*042d53a7SEvalZero     struct hal_timer *entry;
756*042d53a7SEvalZero     struct nrf52_hal_timer *bsptimer;
757*042d53a7SEvalZero 
758*042d53a7SEvalZero     if ((timer == NULL) || (timer->link.tqe_prev != NULL) ||
759*042d53a7SEvalZero         (timer->cb_func == NULL)) {
760*042d53a7SEvalZero         return EINVAL;
761*042d53a7SEvalZero     }
762*042d53a7SEvalZero     bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer;
763*042d53a7SEvalZero     timer->expiry = tick;
764*042d53a7SEvalZero 
765*042d53a7SEvalZero     __HAL_DISABLE_INTERRUPTS(ctx);
766*042d53a7SEvalZero 
767*042d53a7SEvalZero     if (TAILQ_EMPTY(&bsptimer->hal_timer_q)) {
768*042d53a7SEvalZero         TAILQ_INSERT_HEAD(&bsptimer->hal_timer_q, timer, link);
769*042d53a7SEvalZero     } else {
770*042d53a7SEvalZero         TAILQ_FOREACH(entry, &bsptimer->hal_timer_q, link) {
771*042d53a7SEvalZero             if ((int32_t)(timer->expiry - entry->expiry) < 0) {
772*042d53a7SEvalZero                 TAILQ_INSERT_BEFORE(entry, timer, link);
773*042d53a7SEvalZero                 break;
774*042d53a7SEvalZero             }
775*042d53a7SEvalZero         }
776*042d53a7SEvalZero         if (!entry) {
777*042d53a7SEvalZero             TAILQ_INSERT_TAIL(&bsptimer->hal_timer_q, timer, link);
778*042d53a7SEvalZero         }
779*042d53a7SEvalZero     }
780*042d53a7SEvalZero 
781*042d53a7SEvalZero     /* If this is the head, we need to set new OCMP */
782*042d53a7SEvalZero     if (timer == TAILQ_FIRST(&bsptimer->hal_timer_q)) {
783*042d53a7SEvalZero         nrf_timer_set_ocmp(bsptimer, timer->expiry);
784*042d53a7SEvalZero     }
785*042d53a7SEvalZero 
786*042d53a7SEvalZero     __HAL_ENABLE_INTERRUPTS(ctx);
787*042d53a7SEvalZero 
788*042d53a7SEvalZero     return 0;
789*042d53a7SEvalZero }
790*042d53a7SEvalZero 
791*042d53a7SEvalZero /**
792*042d53a7SEvalZero  * hal timer stop
793*042d53a7SEvalZero  *
794*042d53a7SEvalZero  * Stop a timer.
795*042d53a7SEvalZero  *
796*042d53a7SEvalZero  * @param timer
797*042d53a7SEvalZero  *
798*042d53a7SEvalZero  * @return int
799*042d53a7SEvalZero  */
800*042d53a7SEvalZero int
hal_timer_stop(struct hal_timer * timer)801*042d53a7SEvalZero hal_timer_stop(struct hal_timer *timer)
802*042d53a7SEvalZero {
803*042d53a7SEvalZero     uint32_t ctx;
804*042d53a7SEvalZero     int reset_ocmp;
805*042d53a7SEvalZero     struct hal_timer *entry;
806*042d53a7SEvalZero     struct nrf52_hal_timer *bsptimer;
807*042d53a7SEvalZero 
808*042d53a7SEvalZero     if (timer == NULL) {
809*042d53a7SEvalZero         return EINVAL;
810*042d53a7SEvalZero     }
811*042d53a7SEvalZero 
812*042d53a7SEvalZero    bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer;
813*042d53a7SEvalZero 
814*042d53a7SEvalZero     __HAL_DISABLE_INTERRUPTS(ctx);
815*042d53a7SEvalZero 
816*042d53a7SEvalZero     if (timer->link.tqe_prev != NULL) {
817*042d53a7SEvalZero         reset_ocmp = 0;
818*042d53a7SEvalZero         if (timer == TAILQ_FIRST(&bsptimer->hal_timer_q)) {
819*042d53a7SEvalZero             /* If first on queue, we will need to reset OCMP */
820*042d53a7SEvalZero             entry = TAILQ_NEXT(timer, link);
821*042d53a7SEvalZero             reset_ocmp = 1;
822*042d53a7SEvalZero         }
823*042d53a7SEvalZero         TAILQ_REMOVE(&bsptimer->hal_timer_q, timer, link);
824*042d53a7SEvalZero         timer->link.tqe_prev = NULL;
825*042d53a7SEvalZero         if (reset_ocmp) {
826*042d53a7SEvalZero             if (entry) {
827*042d53a7SEvalZero                 nrf_timer_set_ocmp((struct nrf52_hal_timer *)entry->bsp_timer,
828*042d53a7SEvalZero                                    entry->expiry);
829*042d53a7SEvalZero             } else {
830*042d53a7SEvalZero                 if (bsptimer->tmr_rtc) {
831*042d53a7SEvalZero                     nrf_rtc_disable_ocmp((NRF_RTC_Type *)bsptimer->tmr_reg);
832*042d53a7SEvalZero                 } else {
833*042d53a7SEvalZero                     nrf_timer_disable_ocmp(bsptimer->tmr_reg);
834*042d53a7SEvalZero                 }
835*042d53a7SEvalZero             }
836*042d53a7SEvalZero         }
837*042d53a7SEvalZero     }
838*042d53a7SEvalZero 
839*042d53a7SEvalZero     __HAL_ENABLE_INTERRUPTS(ctx);
840*042d53a7SEvalZero 
841*042d53a7SEvalZero     return 0;
842*042d53a7SEvalZero }
843