1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2020 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_qtmr.h"
10 /* Component ID definition, used by tools. */
11 #ifndef FSL_COMPONENT_ID
12 #define FSL_COMPONENT_ID "platform.drivers.qtmr_2"
13 #endif
14 
15 /*******************************************************************************
16  * Prototypes
17  ******************************************************************************/
18 /*!
19  * @brief Gets the instance from the base address to be used to gate or ungate the module clock
20  *
21  * @param base Quad Timer peripheral base address
22  *
23  * @return The Quad Timer instance
24  */
25 static uint32_t QTMR_GetInstance(TMR_Type *base);
26 
27 /*******************************************************************************
28  * Variables
29  ******************************************************************************/
30 /*! @brief Pointers to Quad Timer bases for each instance. */
31 static TMR_Type *const s_qtmrBases[] = TMR_BASE_PTRS;
32 
33 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
34 /*! @brief Pointers to Quad Timer clocks for each instance. */
35 static const clock_ip_name_t s_qtmrClocks[] = TMR_CLOCKS;
36 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
37 
38 /*******************************************************************************
39  * Code
40  ******************************************************************************/
QTMR_GetInstance(TMR_Type * base)41 static uint32_t QTMR_GetInstance(TMR_Type *base)
42 {
43     uint32_t instance;
44 
45     /* Find the instance index from base address mappings. */
46     for (instance = 0; instance < ARRAY_SIZE(s_qtmrBases); instance++)
47     {
48         if (s_qtmrBases[instance] == base)
49         {
50             break;
51         }
52     }
53 
54     assert(instance < ARRAY_SIZE(s_qtmrBases));
55 
56     return instance;
57 }
58 
59 /*!
60  * brief Ungates the Quad Timer clock and configures the peripheral for basic operation.
61  *
62  * note This API should be called at the beginning of the application using the Quad Timer driver.
63  *
64  * param base   Quad Timer peripheral base address
65  * param config Pointer to user's Quad Timer config structure
66  */
QTMR_Init(TMR_Type * base,const qtmr_config_t * config)67 void QTMR_Init(TMR_Type *base, const qtmr_config_t *config)
68 {
69     assert(NULL != config);
70 
71 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
72     /* Enable the module clock */
73     CLOCK_EnableClock(s_qtmrClocks[QTMR_GetInstance(base)]);
74 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
75 
76     /* Setup the counter sources */
77     base->CTRL = (TMR_CTRL_PCS(config->primarySource) | TMR_CTRL_SCS(config->secondarySource));
78 
79     /* Setup the master mode operation */
80     base->SCTRL = (TMR_SCTRL_EEOF(config->enableExternalForce) | TMR_SCTRL_MSTR(config->enableMasterMode));
81 
82     /* Setup debug mode */
83     base->CSCTRL = TMR_CSCTRL_DBG_EN(config->debugMode);
84 
85     /* Setup input filter */
86     base->FILT = (TMR_FILT_FILT_CNT(config->faultFilterCount) | TMR_FILT_FILT_PER(config->faultFilterPeriod));
87 }
88 
89 /*!
90  * brief Stops the counter and gates the Quad Timer clock
91  *
92  * param base Quad Timer peripheral base address
93  */
QTMR_Deinit(TMR_Type * base)94 void QTMR_Deinit(TMR_Type *base)
95 {
96     /* Stop the counter */
97     base->CTRL &= ~(uint16_t)TMR_CTRL_CM_MASK;
98 
99 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
100     /* Disable the module clock */
101     CLOCK_DisableClock(s_qtmrClocks[QTMR_GetInstance(base)]);
102 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
103 }
104 
105 /*!
106  * brief  Fill in the Quad Timer config struct with the default settings
107  *
108  * The default values are:
109  * code
110  *    config->debugMode = kQTMR_RunNormalInDebug;
111  *    config->enableExternalForce = false;
112  *    config->enableMasterMode = false;
113  *    config->faultFilterCount = 0;
114  *    config->faultFilterPeriod = 0;
115  *    config->primarySource = kQTMR_ClockDivide_2;
116  *    config->secondarySource = kQTMR_Counter0InputPin;
117  * endcode
118  * param config Pointer to user's Quad Timer config structure.
119  */
QTMR_GetDefaultConfig(qtmr_config_t * config)120 void QTMR_GetDefaultConfig(qtmr_config_t *config)
121 {
122     assert(NULL != config);
123 
124     /* Initializes the configure structure to zero. */
125     (void)memset(config, 0, sizeof(*config));
126 
127     /* Halt counter during debug mode */
128     config->debugMode = kQTMR_RunNormalInDebug;
129     /* Another counter cannot force state of OFLAG signal */
130     config->enableExternalForce = false;
131     /* Compare function's output from this counter is not broadcast to other counters */
132     config->enableMasterMode = false;
133     /* Fault filter count is set to 0 */
134     config->faultFilterCount = 0;
135     /* Fault filter period is set to 0 which disables the fault filter */
136     config->faultFilterPeriod = 0;
137     /* Primary count source is IP bus clock divide by 2 */
138     config->primarySource = kQTMR_ClockDivide_2;
139     /* Secondary count source is counter 0 input pin */
140     config->secondarySource = kQTMR_Counter0InputPin;
141 }
142 
143 /*!
144  * brief Sets up Quad timer module for PWM signal output.
145  *
146  * The function initializes the timer module according to the parameters passed in by the user. The
147  * function also sets up the value compare registers to match the PWM signal requirements.
148  *
149  * param base             Quad Timer peripheral base address
150  * param pwmFreqHz        PWM signal frequency in Hz
151  * param dutyCyclePercent PWM pulse width, value should be between 0 to 100
152  *                         0=inactive signal(0% duty cycle)...
153  *                         100=active signal (100% duty cycle)
154  * param outputPolarity   true: invert polarity of the output signal, false: no inversion
155  * param srcClock_Hz      Main counter clock in Hz.
156  *
157  * return Returns an error if there was error setting up the signal.
158  */
QTMR_SetupPwm(TMR_Type * base,uint32_t pwmFreqHz,uint8_t dutyCyclePercent,bool outputPolarity,uint32_t srcClock_Hz)159 status_t QTMR_SetupPwm(
160     TMR_Type *base, uint32_t pwmFreqHz, uint8_t dutyCyclePercent, bool outputPolarity, uint32_t srcClock_Hz)
161 {
162     uint32_t periodCount, highCount, lowCount;
163     uint16_t reg;
164     status_t status = kStatus_Success;
165 
166     if (dutyCyclePercent <= 100U)
167     {
168         /* Set OFLAG pin for output mode and force out a low on the pin */
169         base->SCTRL |= (TMR_SCTRL_FORCE_MASK | TMR_SCTRL_OEN_MASK);
170 
171         /* Counter values to generate a PWM signal */
172         periodCount = (srcClock_Hz / pwmFreqHz);
173         highCount   = (periodCount * dutyCyclePercent) / 100U;
174         lowCount    = periodCount - highCount;
175 
176         /* Setup the compare registers for PWM output */
177         base->COMP1 = (uint16_t)lowCount;
178         base->COMP2 = (uint16_t)highCount;
179 
180         /* Setup the pre-load registers for PWM output */
181         base->CMPLD1 = (uint16_t)lowCount;
182         base->CMPLD2 = (uint16_t)highCount;
183 
184         reg = base->CSCTRL;
185         /* Setup the compare load control for COMP1 and COMP2.
186          * Load COMP1 when CSCTRL[TCF2] is asserted, load COMP2 when CSCTRL[TCF1] is asserted
187          */
188         reg &= ~((uint16_t)TMR_CSCTRL_CL1_MASK | (uint16_t)TMR_CSCTRL_CL2_MASK);
189         reg |= (TMR_CSCTRL_CL1(kQTMR_LoadOnComp2) | TMR_CSCTRL_CL2(kQTMR_LoadOnComp1));
190         base->CSCTRL = reg;
191 
192         if (outputPolarity)
193         {
194             /* Invert the polarity */
195             base->SCTRL |= TMR_SCTRL_OPS_MASK;
196         }
197         else
198         {
199             /* True polarity, no inversion */
200             base->SCTRL &= ~(uint16_t)TMR_SCTRL_OPS_MASK;
201         }
202 
203         reg = base->CTRL;
204         reg &= ~(uint16_t)TMR_CTRL_OUTMODE_MASK;
205         /* Count until compare value is  reached and re-initialize the counter, toggle OFLAG output
206          * using alternating compare register
207          */
208         reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_ToggleOnAltCompareReg));
209         base->CTRL = reg;
210     }
211     else
212     {
213         /* Invalid dutycycle */
214         status = kStatus_Fail;
215     }
216 
217     return status;
218 }
219 
220 /*!
221  * brief Allows the user to count the source clock cycles until a capture event arrives.
222  *
223  * The count is stored in the capture register.
224  *
225  * param base            Quad Timer peripheral base address
226  * param capturePin      Pin through which we receive the input signal to trigger the capture
227  * param inputPolarity   true: invert polarity of the input signal, false: no inversion
228  * param reloadOnCapture true: reload the counter when an input capture occurs, false: no reload
229  * param captureMode     Specifies which edge of the input signal  triggers a capture
230  */
QTMR_SetupInputCapture(TMR_Type * base,qtmr_input_source_t capturePin,bool inputPolarity,bool reloadOnCapture,qtmr_input_capture_edge_t captureMode)231 void QTMR_SetupInputCapture(TMR_Type *base,
232                             qtmr_input_source_t capturePin,
233                             bool inputPolarity,
234                             bool reloadOnCapture,
235                             qtmr_input_capture_edge_t captureMode)
236 {
237     uint16_t reg;
238 
239     /* Clear the prior value for the input source for capture */
240     reg = base->CTRL & (~(uint16_t)TMR_CTRL_SCS_MASK);
241 
242     /* Set the new input source */
243     reg |= TMR_CTRL_SCS(capturePin);
244     base->CTRL = reg;
245 
246     /* Clear the prior values for input polarity, capture mode. Set the external pin as input */
247     reg = base->SCTRL &
248           (~((uint16_t)TMR_SCTRL_IPS_MASK | (uint16_t)TMR_SCTRL_CAPTURE_MODE_MASK | (uint16_t)TMR_SCTRL_OEN_MASK));
249     /* Set the new values */
250     reg |= (TMR_SCTRL_IPS(inputPolarity) | TMR_SCTRL_CAPTURE_MODE(captureMode));
251     base->SCTRL = reg;
252 
253     /* Setup if counter should reload when a capture occurs */
254     if (reloadOnCapture)
255     {
256         base->CSCTRL |= TMR_CSCTRL_ROC_MASK;
257     }
258     else
259     {
260         base->CSCTRL &= ~(uint16_t)TMR_CSCTRL_ROC_MASK;
261     }
262 }
263 
264 /*!
265  * brief Enables the selected Quad Timer interrupts
266  *
267  * param base Quad Timer peripheral base address
268  * param mask The interrupts to enable. This is a logical OR of members of the
269  *             enumeration ::qtmr_interrupt_enable_t
270  */
QTMR_EnableInterrupts(TMR_Type * base,uint32_t mask)271 void QTMR_EnableInterrupts(TMR_Type *base, uint32_t mask)
272 {
273     uint16_t reg;
274 
275     reg = base->SCTRL;
276     /* Compare interrupt */
277     if (0U != (mask & (uint32_t)kQTMR_CompareInterruptEnable))
278     {
279         reg |= TMR_SCTRL_TCFIE_MASK;
280     }
281     /* Overflow interrupt */
282     if (0U != (mask & (uint32_t)kQTMR_OverflowInterruptEnable))
283     {
284         reg |= TMR_SCTRL_TOFIE_MASK;
285     }
286     /* Input edge interrupt */
287     if (0U != (mask & (uint32_t)kQTMR_EdgeInterruptEnable))
288     {
289         reg |= TMR_SCTRL_IEFIE_MASK;
290     }
291     base->SCTRL = reg;
292 
293     reg = base->CSCTRL;
294     /* Compare 1 interrupt */
295     if (0U != (mask & (uint32_t)kQTMR_Compare1InterruptEnable))
296     {
297         reg |= TMR_CSCTRL_TCF1EN_MASK;
298     }
299     /* Compare 2 interrupt */
300     if (0U != (mask & (uint32_t)kQTMR_Compare2InterruptEnable))
301     {
302         reg |= TMR_CSCTRL_TCF2EN_MASK;
303     }
304     base->CSCTRL = reg;
305 }
306 
307 /*!
308  * brief Disables the selected Quad Timer interrupts
309  *
310  * param base Quad Timer peripheral base address
311  * param mask The interrupts to enable. This is a logical OR of members of the
312  *             enumeration ::qtmr_interrupt_enable_t
313  */
QTMR_DisableInterrupts(TMR_Type * base,uint32_t mask)314 void QTMR_DisableInterrupts(TMR_Type *base, uint32_t mask)
315 {
316     uint16_t reg;
317 
318     reg = base->SCTRL;
319     /* Compare interrupt */
320     if (0U != (mask & (uint32_t)kQTMR_CompareInterruptEnable))
321     {
322         reg &= ~(uint16_t)TMR_SCTRL_TCFIE_MASK;
323     }
324     /* Overflow interrupt */
325     if (0U != (mask & (uint32_t)kQTMR_OverflowInterruptEnable))
326     {
327         reg &= ~(uint16_t)TMR_SCTRL_TOFIE_MASK;
328     }
329     /* Input edge interrupt */
330     if (0U != (mask & (uint32_t)kQTMR_EdgeInterruptEnable))
331     {
332         reg &= ~(uint16_t)TMR_SCTRL_IEFIE_MASK;
333     }
334     base->SCTRL = reg;
335 
336     reg = base->CSCTRL;
337     /* Compare 1 interrupt */
338     if (0U != (mask & (uint32_t)kQTMR_Compare1InterruptEnable))
339     {
340         reg &= ~(uint16_t)TMR_CSCTRL_TCF1EN_MASK;
341     }
342     /* Compare 2 interrupt */
343     if (0U != (mask & (uint32_t)kQTMR_Compare2InterruptEnable))
344     {
345         reg &= ~(uint16_t)TMR_CSCTRL_TCF2EN_MASK;
346     }
347     base->CSCTRL = reg;
348 }
349 
350 /*!
351  * brief Gets the enabled Quad Timer interrupts
352  *
353  * param base Quad Timer peripheral base address
354  *
355  * return The enabled interrupts. This is the logical OR of members of the
356  *         enumeration ::qtmr_interrupt_enable_t
357  */
QTMR_GetEnabledInterrupts(TMR_Type * base)358 uint32_t QTMR_GetEnabledInterrupts(TMR_Type *base)
359 {
360     uint32_t enabledInterrupts = 0;
361     uint16_t reg;
362 
363     reg = base->SCTRL;
364     /* Compare interrupt */
365     if (0U != (reg & TMR_SCTRL_TCFIE_MASK))
366     {
367         enabledInterrupts |= (uint32_t)kQTMR_CompareFlag;
368     }
369     /* Overflow interrupt */
370     if (0U != (reg & TMR_SCTRL_TOFIE_MASK))
371     {
372         enabledInterrupts |= (uint32_t)kQTMR_OverflowInterruptEnable;
373     }
374     /* Input edge interrupt */
375     if (0U != (reg & TMR_SCTRL_IEFIE_MASK))
376     {
377         enabledInterrupts |= (uint32_t)kQTMR_EdgeInterruptEnable;
378     }
379 
380     reg = base->CSCTRL;
381     /* Compare 1 interrupt */
382     if (0U != (reg & TMR_CSCTRL_TCF1EN_MASK))
383     {
384         enabledInterrupts |= (uint32_t)kQTMR_Compare1InterruptEnable;
385     }
386     /* Compare 2 interrupt */
387     if (0U != (reg & TMR_CSCTRL_TCF2EN_MASK))
388     {
389         enabledInterrupts |= (uint32_t)kQTMR_Compare2InterruptEnable;
390     }
391 
392     return enabledInterrupts;
393 }
394 
395 /*!
396  * brief Gets the Quad Timer status flags
397  *
398  * param base Quad Timer peripheral base address
399  *
400  * return The status flags. This is the logical OR of members of the
401  *         enumeration ::qtmr_status_flags_t
402  */
QTMR_GetStatus(TMR_Type * base)403 uint32_t QTMR_GetStatus(TMR_Type *base)
404 {
405     uint32_t statusFlags = 0;
406     uint16_t reg;
407 
408     reg = base->SCTRL;
409     /* Timer compare flag */
410     if (0U != (reg & TMR_SCTRL_TCF_MASK))
411     {
412         statusFlags |= (uint32_t)kQTMR_CompareFlag;
413     }
414     /* Timer overflow flag */
415     if (0U != (reg & TMR_SCTRL_TOF_MASK))
416     {
417         statusFlags |= (uint32_t)kQTMR_OverflowFlag;
418     }
419     /* Input edge flag */
420     if (0U != (reg & TMR_SCTRL_IEF_MASK))
421     {
422         statusFlags |= (uint32_t)kQTMR_EdgeFlag;
423     }
424 
425     reg = base->CSCTRL;
426     /* Compare 1 flag */
427     if (0U != (reg & TMR_CSCTRL_TCF1_MASK))
428     {
429         statusFlags |= (uint32_t)kQTMR_Compare1Flag;
430     }
431     /* Compare 2 flag */
432     if (0U != (reg & TMR_CSCTRL_TCF2_MASK))
433     {
434         statusFlags |= (uint32_t)kQTMR_Compare2Flag;
435     }
436 
437     return statusFlags;
438 }
439 
440 /*!
441  * brief Clears the Quad Timer status flags.
442  *
443  * param base Quad Timer peripheral base address
444  * param mask The status flags to clear. This is a logical OR of members of the
445  *             enumeration ::qtmr_status_flags_t
446  */
QTMR_ClearStatusFlags(TMR_Type * base,uint32_t mask)447 void QTMR_ClearStatusFlags(TMR_Type *base, uint32_t mask)
448 {
449     uint16_t reg;
450 
451     reg = base->SCTRL;
452     /* Timer compare flag */
453     if (0U != (mask & (uint32_t)kQTMR_CompareFlag))
454     {
455         reg &= ~(uint16_t)TMR_SCTRL_TCF_MASK;
456     }
457     /* Timer overflow flag */
458     if (0U != (mask & (uint32_t)kQTMR_OverflowFlag))
459     {
460         reg &= ~(uint16_t)TMR_SCTRL_TOF_MASK;
461     }
462     /* Input edge flag */
463     if (0U != (mask & (uint32_t)kQTMR_EdgeFlag))
464     {
465         reg &= ~(uint16_t)TMR_SCTRL_IEF_MASK;
466     }
467     base->SCTRL = reg;
468 
469     reg = base->CSCTRL;
470     /* Compare 1 flag */
471     if (0U != (mask & (uint32_t)kQTMR_Compare1Flag))
472     {
473         reg &= ~(uint16_t)TMR_CSCTRL_TCF1_MASK;
474     }
475     /* Compare 2 flag */
476     if (0U != (mask & (uint32_t)kQTMR_Compare2Flag))
477     {
478         reg &= ~(uint16_t)TMR_CSCTRL_TCF2_MASK;
479     }
480     base->CSCTRL = reg;
481 }
482 
483 /*!
484  * brief Sets the timer period in ticks.
485  *
486  * Timers counts from initial value till it equals the count value set here. The counter
487  * will then reinitialize to the value specified in the Load register.
488  *
489  * note
490  * 1. This function will write the time period in ticks to COMP1 or COMP2 register
491  *    depending on the count direction
492  * 2. User can call the utility macros provided in fsl_common.h to convert to ticks
493  * 3. This function supports cases, providing only primary source clock without secondary source clock.
494  *
495  * param base  Quad Timer peripheral base address
496  * param ticks Timer period in units of ticks
497  */
QTMR_SetTimerPeriod(TMR_Type * base,uint16_t ticks)498 void QTMR_SetTimerPeriod(TMR_Type *base, uint16_t ticks)
499 {
500     /* Set the length bit to reinitialize the counters on a match */
501     base->CTRL |= TMR_CTRL_LENGTH_MASK;
502 
503     if (0U != (base->CTRL & TMR_CTRL_DIR_MASK))
504     {
505         /* Counting down */
506         base->COMP2 = ticks;
507     }
508     else
509     {
510         /* Counting up */
511         base->COMP1 = ticks;
512     }
513 }
514