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