1 /******************************************************************************
2  *
3  * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
4  * Analog Devices, Inc.),
5  * Copyright (C) 2023-2024 Analog Devices, Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************************/
20 
21 /* **** Includes **** */
22 #include <stddef.h>
23 #include <stdbool.h>
24 #include "mxc_assert.h"
25 #include "tmr.h"
26 #include "tmr_revb.h"
27 #include "gpio.h"
28 #include "mxc_pins.h"
29 #include "mxc_lock.h"
30 
31 /* **** Definitions **** */
32 #define TIMER_16A_OFFSET 0
33 #define TIMER_16B_OFFSET 16
34 
35 typedef struct {
36     bool configured;
37     uint32_t freq;
38 } mxc_tmr_revb_clksrc_freq_t;
39 
40 static mxc_tmr_revb_clksrc_freq_t tmr_clksrc[MXC_CFG_TMR_INSTANCES];
41 
42 /* **** Functions **** */
MXC_TMR_RevB_Init(mxc_tmr_revb_regs_t * tmr,mxc_tmr_cfg_t * cfg,uint8_t clk_src)43 int MXC_TMR_RevB_Init(mxc_tmr_revb_regs_t *tmr, mxc_tmr_cfg_t *cfg, uint8_t clk_src)
44 {
45     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
46     (void)tmr_id;
47     MXC_ASSERT(tmr_id >= 0);
48 
49     if (cfg == NULL) {
50         return E_NULL_PTR;
51     }
52 
53     // Default 32 bit timer
54     if (cfg->bitMode & (MXC_TMR_BIT_MODE_16A | MXC_TMR_BIT_MODE_16B)) {
55         tmr->ctrl1 &= ~MXC_F_TMR_REVB_CTRL1_CASCADE;
56     } else {
57         tmr->ctrl1 |= MXC_F_TMR_REVB_CTRL1_CASCADE;
58     }
59 
60     // Clear interrupt flag
61     tmr->intfl |= (MXC_F_TMR_REVB_INTFL_IRQ_A | MXC_F_TMR_REVB_INTFL_IRQ_B);
62 
63     // Select clock Source and prescaler
64     // Note:  For 32-bit cascade mode, TMR A and TMR B clock sources must be
65     //        the same to ensure proper operation.  (See MAX32670 UG Rev 4 Section 13.4)
66     if (cfg->bitMode == TMR_BIT_MODE_16A || cfg->bitMode == TMR_BIT_MODE_32) {
67         MXC_SETFIELD(tmr->ctrl1, MXC_F_TMR_CTRL1_CLKSEL_A,
68                      (clk_src << MXC_F_TMR_CTRL1_CLKSEL_A_POS));
69         MXC_SETFIELD(tmr->ctrl0, MXC_F_TMR_CTRL0_CLKDIV_A, cfg->pres);
70     }
71     if (cfg->bitMode == TMR_BIT_MODE_16B || cfg->bitMode == TMR_BIT_MODE_32) {
72         MXC_SETFIELD(tmr->ctrl1, MXC_F_TMR_CTRL1_CLKSEL_B,
73                      (clk_src << MXC_F_TMR_CTRL1_CLKSEL_B_POS));
74         // mxc_tmr_pres_t is for for CLKDIV_A register settings [4:7]
75         // Field positions for CLKDIV_B are Located at [16:19]. Shift 12 more bits.
76         MXC_SETFIELD(tmr->ctrl0, MXC_F_TMR_CTRL0_CLKDIV_B, (cfg->pres) << 12);
77     }
78 
79     //TIMER_16B only supports compare, oneshot and continuous modes.
80     switch (cfg->mode) {
81     case MXC_TMR_MODE_ONESHOT:
82         MXC_TMR_RevB_ConfigGeneric((mxc_tmr_revb_regs_t *)tmr, cfg);
83         break;
84 
85     case MXC_TMR_MODE_CONTINUOUS:
86         MXC_TMR_RevB_ConfigGeneric((mxc_tmr_revb_regs_t *)tmr, cfg);
87         break;
88 
89     case MXC_TMR_MODE_COUNTER:
90         if (cfg->bitMode == MXC_TMR_BIT_MODE_16B) {
91             return E_NOT_SUPPORTED;
92         }
93 
94         MXC_TMR_RevB_ConfigGeneric(tmr, cfg);
95         break;
96 
97     case MXC_TMR_MODE_CAPTURE:
98         if (cfg->bitMode == MXC_TMR_BIT_MODE_16B) {
99             return E_NOT_SUPPORTED;
100         }
101 
102         MXC_TMR_RevB_ConfigGeneric(tmr, cfg);
103         break;
104 
105     case MXC_TMR_MODE_COMPARE:
106         MXC_TMR_RevB_ConfigGeneric((mxc_tmr_revb_regs_t *)tmr, cfg);
107         break;
108 
109     case MXC_TMR_MODE_GATED:
110         if (cfg->bitMode == MXC_TMR_BIT_MODE_16B) {
111             return E_NOT_SUPPORTED;
112         }
113 
114         MXC_TMR_RevB_ConfigGeneric(tmr, cfg);
115         break;
116 
117     case MXC_TMR_MODE_CAPTURE_COMPARE:
118         if (cfg->bitMode == MXC_TMR_BIT_MODE_16B) {
119             return E_NOT_SUPPORTED;
120         }
121 
122         MXC_TMR_RevB_ConfigGeneric(tmr, cfg);
123         break;
124 
125     case MXC_TMR_MODE_DUAL_EDGE:
126         if (cfg->bitMode == MXC_TMR_BIT_MODE_16B) {
127             return E_NOT_SUPPORTED;
128         }
129 
130         MXC_TMR_RevB_ConfigGeneric(tmr, cfg);
131         break;
132 
133     case MXC_TMR_MODE_PWM:
134         if (cfg->bitMode == MXC_TMR_BIT_MODE_16B) {
135             return E_NOT_SUPPORTED;
136         }
137 
138         MXC_TMR_RevB_ConfigGeneric((mxc_tmr_revb_regs_t *)tmr, cfg);
139         break;
140     }
141 
142     return E_NO_ERROR;
143 }
144 
MXC_TMR_RevB_SetClockSourceFreq(mxc_tmr_revb_regs_t * tmr,int clksrc_freq)145 void MXC_TMR_RevB_SetClockSourceFreq(mxc_tmr_revb_regs_t *tmr, int clksrc_freq)
146 {
147     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
148     (void)tmr_id;
149     MXC_ASSERT(tmr_id >= 0);
150 
151     tmr_clksrc[tmr_id].configured = true;
152     tmr_clksrc[tmr_id].freq = clksrc_freq;
153 }
154 
MXC_TMR_RevB_GetClockSourceFreq(mxc_tmr_revb_regs_t * tmr)155 int MXC_TMR_RevB_GetClockSourceFreq(mxc_tmr_revb_regs_t *tmr)
156 {
157     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
158     (void)tmr_id;
159     MXC_ASSERT(tmr_id >= 0);
160 
161     if (tmr_clksrc[tmr_id].configured == false) {
162         return E_BAD_STATE;
163     }
164 
165     return tmr_clksrc[tmr_id].freq;
166 }
167 
MXC_TMR_RevB_ConfigGeneric(mxc_tmr_revb_regs_t * tmr,mxc_tmr_cfg_t * cfg)168 void MXC_TMR_RevB_ConfigGeneric(mxc_tmr_revb_regs_t *tmr, mxc_tmr_cfg_t *cfg)
169 {
170     uint32_t timerOffset;
171     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
172     (void)tmr_id;
173     MXC_ASSERT(tmr_id >= 0);
174 
175     if (cfg == NULL) {
176         return;
177     }
178 
179     if (cfg->bitMode == MXC_TMR_BIT_MODE_16B) {
180         timerOffset = TIMER_16B_OFFSET;
181     } else {
182         timerOffset = TIMER_16A_OFFSET;
183     }
184 
185     tmr->ctrl0 |= (MXC_F_TMR_REVB_CTRL0_CLKEN_A << timerOffset);
186     while (!(tmr->ctrl1 & (MXC_F_TMR_REVB_CTRL1_CLKRDY_A << timerOffset))) {}
187 
188     tmr->ctrl0 |= (cfg->mode << timerOffset);
189     tmr->ctrl0 |= ((cfg->pol << MXC_F_TMR_REVB_CTRL0_POL_A_POS) << timerOffset);
190     //enable timer interrupt if needed
191     tmr->cnt = (0x1 << timerOffset);
192     while (!(tmr->intfl & (MXC_F_TMR_REVB_INTFL_WRDONE_A << timerOffset))) {}
193 
194     tmr->cmp = (cfg->cmp_cnt << timerOffset);
195 #if TARGET_NUM == 32655 || TARGET_NUM == 78000 || TARGET_NUM == 32690 || TARGET_NUM == 78002
196     tmr->ctrl1 &= ~(MXC_F_TMR_REVB_CTRL1_OUTEN_A << timerOffset);
197 #else
198     tmr->ctrl1 |= (MXC_F_TMR_REVB_CTRL1_OUTEN_A << timerOffset);
199 #endif
200 
201     // If configured as TIMER_16B then enable the interrupt and start the timer
202     if (cfg->bitMode == MXC_TMR_BIT_MODE_16B) {
203         tmr->ctrl1 |= MXC_F_TMR_REVB_CTRL1_IE_B;
204 
205         tmr->ctrl0 |= MXC_F_TMR_REVB_CTRL0_EN_B;
206         while (!(tmr->ctrl1 & MXC_F_TMR_REVB_CTRL1_CLKEN_B)) {}
207     }
208 }
209 
MXC_TMR_RevB_Shutdown(mxc_tmr_revb_regs_t * tmr)210 void MXC_TMR_RevB_Shutdown(mxc_tmr_revb_regs_t *tmr)
211 {
212     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
213     (void)tmr_id;
214     MXC_ASSERT(tmr_id >= 0);
215 
216     // Stop timer before disable it.
217     MXC_TMR_RevB_Stop(tmr);
218     // Disable timer and clear settings
219     tmr->ctrl0 = 0;
220     while (tmr->ctrl1 & MXC_F_TMR_REVB_CTRL1_CLKRDY_A) {}
221     tmr_clksrc[tmr_id].configured = false;
222 }
223 
MXC_TMR_RevB_Start(mxc_tmr_revb_regs_t * tmr)224 void MXC_TMR_RevB_Start(mxc_tmr_revb_regs_t *tmr)
225 {
226     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
227     (void)tmr_id;
228     MXC_ASSERT(tmr_id >= 0);
229 
230     tmr->ctrl0 |= MXC_F_TMR_REVB_CTRL0_EN_A;
231     while (!(tmr->ctrl1 & MXC_F_TMR_REVB_CTRL1_CLKEN_A)) {}
232 }
233 
MXC_TMR_RevB_Stop(mxc_tmr_revb_regs_t * tmr)234 void MXC_TMR_RevB_Stop(mxc_tmr_revb_regs_t *tmr)
235 {
236     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
237     (void)tmr_id;
238     MXC_ASSERT(tmr_id >= 0);
239 
240     tmr->ctrl0 &= ~MXC_F_TMR_REVB_CTRL0_EN_A;
241 }
242 
MXC_TMR_RevB_SetPWM(mxc_tmr_revb_regs_t * tmr,uint32_t pwm)243 int MXC_TMR_RevB_SetPWM(mxc_tmr_revb_regs_t *tmr, uint32_t pwm)
244 {
245     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
246     (void)tmr_id;
247     MXC_ASSERT(tmr_id >= 0);
248 
249     if (pwm > (tmr->cmp)) {
250         return E_BAD_PARAM;
251     }
252 
253     bool timera_is_running = tmr->ctrl0 & MXC_F_TMR_CTRL0_EN_A;
254     bool timerb_is_running = tmr->ctrl0 & MXC_F_TMR_CTRL0_EN_B;
255 
256     if (timera_is_running || timerb_is_running) {
257         MXC_TMR_RevB_ClearFlags(tmr); // Clear flags so we can catch the next one
258         while (!MXC_TMR_RevB_GetFlags(tmr)) {} // Wait for next PWM transition
259         MXC_TMR_RevB_Stop(tmr); // Pause timer
260         MXC_TMR_RevB_SetCount(tmr, 0); // Reset the count
261         MXC_TMR_RevB_ClearFlags(
262             tmr); // Clear flags since app code wants the new PWM transitions set by this function
263     }
264 
265     tmr->pwm = pwm;
266     while (!(tmr->intfl & MXC_F_TMR_REVB_INTFL_WRDONE_A)) {}
267 
268     if (timera_is_running) {
269         tmr->ctrl0 |= MXC_F_TMR_REVB_CTRL0_EN_A; // Unpause A
270     }
271 
272     if (timerb_is_running) {
273         tmr->ctrl0 |= MXC_F_TMR_REVB_CTRL0_EN_B; // Unpause B
274     }
275 
276     return E_NO_ERROR;
277 }
278 
MXC_TMR_RevB_GetCompare(mxc_tmr_revb_regs_t * tmr)279 uint32_t MXC_TMR_RevB_GetCompare(mxc_tmr_revb_regs_t *tmr)
280 {
281     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
282     (void)tmr_id;
283     MXC_ASSERT(tmr_id >= 0);
284 
285     return tmr->cmp;
286 }
287 
MXC_TMR_RevB_GetCapture(mxc_tmr_revb_regs_t * tmr)288 uint32_t MXC_TMR_RevB_GetCapture(mxc_tmr_revb_regs_t *tmr)
289 {
290     uint32_t pwm;
291     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
292     (void)tmr_id;
293     MXC_ASSERT(tmr_id >= 0);
294 
295     // read pwm register twice
296     pwm = tmr->pwm;
297     pwm = tmr->pwm;
298     return pwm;
299 }
300 
MXC_TMR_RevB_GetCount(mxc_tmr_revb_regs_t * tmr)301 uint32_t MXC_TMR_RevB_GetCount(mxc_tmr_revb_regs_t *tmr)
302 {
303     uint32_t cnt;
304     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
305     (void)tmr_id;
306     MXC_ASSERT(tmr_id >= 0);
307 
308     // read cnt register twice
309     cnt = tmr->cnt;
310     cnt = tmr->cnt;
311     return cnt;
312 }
313 
MXC_TMR_RevB_GetPeriod(mxc_tmr_revb_regs_t * tmr,uint32_t clk_frequency,uint32_t prescalar,uint32_t frequency)314 uint32_t MXC_TMR_RevB_GetPeriod(mxc_tmr_revb_regs_t *tmr, uint32_t clk_frequency,
315                                 uint32_t prescalar, uint32_t frequency)
316 {
317     uint32_t periodTicks;
318     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
319     (void)tmr_id;
320     MXC_ASSERT(tmr_id >= 0);
321 
322     periodTicks = clk_frequency / (frequency * prescalar);
323 
324     return periodTicks;
325 }
326 
MXC_TMR_RevB_ClearFlags(mxc_tmr_revb_regs_t * tmr)327 void MXC_TMR_RevB_ClearFlags(mxc_tmr_revb_regs_t *tmr)
328 {
329     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
330     (void)tmr_id;
331     MXC_ASSERT(tmr_id >= 0);
332 
333     tmr->intfl |= (MXC_F_TMR_REVB_INTFL_IRQ_A | MXC_F_TMR_REVB_INTFL_IRQ_B);
334 }
335 
MXC_TMR_RevB_GetFlags(mxc_tmr_revb_regs_t * tmr)336 uint32_t MXC_TMR_RevB_GetFlags(mxc_tmr_revb_regs_t *tmr)
337 {
338     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
339     (void)tmr_id;
340     MXC_ASSERT(tmr_id >= 0);
341 
342     return (tmr->intfl & (MXC_F_TMR_REVB_INTFL_IRQ_A | MXC_F_TMR_REVB_INTFL_IRQ_B));
343 }
344 
MXC_TMR_RevB_EnableInt(mxc_tmr_revb_regs_t * tmr)345 void MXC_TMR_RevB_EnableInt(mxc_tmr_revb_regs_t *tmr)
346 {
347     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
348     (void)tmr_id;
349     MXC_ASSERT(tmr_id >= 0);
350 
351     tmr->ctrl1 |= MXC_F_TMR_REVB_CTRL1_IE_A | MXC_F_TMR_REVB_CTRL1_IE_B;
352 }
353 
MXC_TMR_RevB_DisableInt(mxc_tmr_revb_regs_t * tmr)354 void MXC_TMR_RevB_DisableInt(mxc_tmr_revb_regs_t *tmr)
355 {
356     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
357     (void)tmr_id;
358     MXC_ASSERT(tmr_id >= 0);
359 
360     tmr->ctrl1 &= ~(MXC_F_TMR_REVB_CTRL1_IE_A | MXC_F_TMR_REVB_CTRL1_IE_B);
361 }
362 
MXC_TMR_RevB_EnableWakeup(mxc_tmr_revb_regs_t * tmr,mxc_tmr_cfg_t * cfg)363 void MXC_TMR_RevB_EnableWakeup(mxc_tmr_revb_regs_t *tmr, mxc_tmr_cfg_t *cfg)
364 {
365     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
366     (void)tmr_id;
367     MXC_ASSERT(tmr_id >= 0);
368 
369     // Enable Timer wake-up source
370     if (cfg->bitMode == MXC_TMR_BIT_MODE_16B) {
371         tmr->ctrl1 |= MXC_F_TMR_REVB_CTRL1_WE_B;
372     } else {
373         tmr->ctrl1 |= MXC_F_TMR_REVB_CTRL1_WE_A;
374     }
375 }
376 
MXC_TMR_RevB_DisableWakeup(mxc_tmr_revb_regs_t * tmr,mxc_tmr_cfg_t * cfg)377 void MXC_TMR_RevB_DisableWakeup(mxc_tmr_revb_regs_t *tmr, mxc_tmr_cfg_t *cfg)
378 {
379     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
380     (void)tmr_id;
381     MXC_ASSERT(tmr_id >= 0);
382 
383     // Disable Timer wake-up source
384     if (cfg->bitMode == MXC_TMR_BIT_MODE_16B) {
385         tmr->ctrl1 &= ~MXC_F_TMR_REVB_CTRL1_WE_B;
386     } else {
387         tmr->ctrl1 &= ~MXC_F_TMR_REVB_CTRL1_WE_A;
388     }
389 }
390 
MXC_TMR_RevB_SetCompare(mxc_tmr_revb_regs_t * tmr,uint32_t cmp_cnt)391 void MXC_TMR_RevB_SetCompare(mxc_tmr_revb_regs_t *tmr, uint32_t cmp_cnt)
392 {
393     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
394     (void)tmr_id;
395     MXC_ASSERT(tmr_id >= 0);
396 
397     tmr->cmp = cmp_cnt;
398 }
399 
MXC_TMR_RevB_SetCount(mxc_tmr_revb_regs_t * tmr,uint32_t cnt)400 void MXC_TMR_RevB_SetCount(mxc_tmr_revb_regs_t *tmr, uint32_t cnt)
401 {
402     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
403     (void)tmr_id;
404     MXC_ASSERT(tmr_id >= 0);
405 
406     tmr->cnt = cnt;
407     while (!(tmr->intfl & MXC_F_TMR_REVB_INTFL_WRDONE_A)) {}
408 }
409 
MXC_TMR_RevB_TO_Start(mxc_tmr_revb_regs_t * tmr,uint32_t us)410 void MXC_TMR_RevB_TO_Start(mxc_tmr_revb_regs_t *tmr, uint32_t us)
411 {
412     uint64_t ticks;
413     int clk_shift = 0;
414 
415     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
416     (void)tmr_id;
417     MXC_ASSERT(tmr_id >= 0);
418 
419     if (us == 0) {
420         return;
421     }
422 
423     ticks = (uint64_t)us * (uint64_t)PeripheralClock / (uint64_t)1000000;
424 
425     while (ticks > 0xFFFFFFFFUL) {
426         ticks >>= 1;
427         ++clk_shift;
428     }
429 
430     mxc_tmr_pres_t prescale = (mxc_tmr_pres_t)(clk_shift << MXC_F_TMR_REVB_CTRL0_CLKDIV_A_POS);
431     mxc_tmr_cfg_t cfg;
432 
433     // Initialize the timer in one-shot mode
434     cfg.pres = prescale;
435     cfg.mode = MXC_TMR_MODE_ONESHOT;
436     cfg.bitMode = MXC_TMR_BIT_MODE_32;
437     cfg.clock = MXC_TMR_APB_CLK;
438     cfg.cmp_cnt = ticks;
439     cfg.pol = 0;
440 
441     MXC_TMR_Stop((mxc_tmr_regs_t *)tmr);
442 #if TARGET_NUM == 32662
443     MXC_TMR_Init((mxc_tmr_regs_t *)tmr, &cfg, false, MAP_A);
444 #else
445     MXC_TMR_Init((mxc_tmr_regs_t *)tmr, &cfg, false);
446 #endif
447     tmr->ctrl1 |= MXC_F_TMR_REVB_CTRL1_CASCADE;
448     MXC_TMR_ClearFlags((mxc_tmr_regs_t *)tmr);
449     MXC_TMR_Start((mxc_tmr_regs_t *)tmr);
450 }
451 
MXC_TMR_RevB_GetTime(mxc_tmr_revb_regs_t * tmr,uint32_t ticks,uint32_t * time,mxc_tmr_unit_t * units)452 int MXC_TMR_RevB_GetTime(mxc_tmr_revb_regs_t *tmr, uint32_t ticks, uint32_t *time,
453                          mxc_tmr_unit_t *units)
454 {
455     int tmr_id = MXC_TMR_GET_IDX((mxc_tmr_regs_t *)tmr);
456     (void)tmr_id;
457     MXC_ASSERT(tmr_id >= 0);
458 
459     uint64_t temp_time = 0;
460     uint32_t prescale = (tmr->ctrl0 & MXC_F_TMR_REVB_CTRL0_CLKDIV_A) >>
461                         MXC_F_TMR_REVB_CTRL0_CLKDIV_A_POS;
462 
463     int timerClock = MXC_TMR_RevB_GetClockSourceFreq(tmr);
464 
465     // Confirm clock is configured by checking for error return.
466     if (timerClock < 0) {
467         return timerClock;
468     }
469 
470     temp_time = (uint64_t)ticks * 1000 * (1 << (prescale & 0xF)) / (timerClock / 1000000);
471 
472     if (!(temp_time & 0xffffffff00000000)) {
473         *time = temp_time;
474         *units = MXC_TMR_UNIT_NANOSEC;
475         return E_NO_ERROR;
476     }
477 
478     temp_time = (uint64_t)ticks * 1000 * (1 << (prescale & 0xF)) / (timerClock / 1000);
479 
480     if (!(temp_time & 0xffffffff00000000)) {
481         *time = temp_time;
482         *units = MXC_TMR_UNIT_MICROSEC;
483         return E_NO_ERROR;
484     }
485 
486     temp_time = (uint64_t)ticks * 1000 * (1 << (prescale & 0xF)) / timerClock;
487 
488     if (!(temp_time & 0xffffffff00000000)) {
489         *time = temp_time;
490         *units = MXC_TMR_UNIT_MILLISEC;
491         return E_NO_ERROR;
492     }
493 
494     temp_time = (uint64_t)ticks * (1 << (prescale & 0xF)) / timerClock;
495 
496     if (!(temp_time & 0xffffffff00000000)) {
497         *time = temp_time;
498         *units = MXC_TMR_UNIT_SEC;
499         return E_NO_ERROR;
500     }
501 
502     return E_INVALID;
503 }
504 
MXC_TMR_RevB_GetTicks(mxc_tmr_revb_regs_t * tmr,uint32_t time,mxc_tmr_unit_t units,uint32_t * ticks)505 int MXC_TMR_RevB_GetTicks(mxc_tmr_revb_regs_t *tmr, uint32_t time, mxc_tmr_unit_t units,
506                           uint32_t *ticks)
507 {
508     uint32_t unit_div0, unit_div1;
509     uint32_t timerClock;
510     uint32_t prescale;
511     uint64_t temp_ticks;
512 
513     timerClock = PeripheralClock;
514 
515     prescale = ((tmr->ctrl0 & MXC_F_TMR_CTRL0_CLKDIV_A) >> MXC_F_TMR_CTRL0_CLKDIV_A_POS);
516 
517     switch (units) {
518     case MXC_TMR_UNIT_NANOSEC:
519         unit_div0 = 1000000;
520         unit_div1 = 1000;
521         break;
522     case MXC_TMR_UNIT_MICROSEC:
523         unit_div0 = 1000;
524         unit_div1 = 1000;
525         break;
526     case MXC_TMR_UNIT_MILLISEC:
527         unit_div0 = 1;
528         unit_div1 = 1000;
529         break;
530     case MXC_TMR_UNIT_SEC:
531         unit_div0 = 1;
532         unit_div1 = 1;
533         break;
534     default:
535         return E_BAD_PARAM;
536     }
537 
538     temp_ticks = (uint64_t)time * (timerClock / unit_div0) / (unit_div1 * (1 << (prescale & 0xF)));
539 
540     //make sure ticks is within a 32 bit value
541     if (!(temp_ticks & 0xffffffff00000000) && (temp_ticks & 0xffffffff)) {
542         *ticks = temp_ticks;
543         return E_NO_ERROR;
544     }
545 
546     return E_INVALID;
547 }
548