1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2017 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_tpm.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 #define TPM_COMBINE_SHIFT (8U)
15 
16 /*******************************************************************************
17  * Prototypes
18  ******************************************************************************/
19 /*!
20  * @brief Gets the instance from the base address
21  *
22  * @param base TPM peripheral base address
23  *
24  * @return The TPM instance
25  */
26 static uint32_t TPM_GetInstance(TPM_Type *base);
27 
28 /*******************************************************************************
29  * Variables
30  ******************************************************************************/
31 /*! @brief Pointers to TPM bases for each instance. */
32 static TPM_Type *const s_tpmBases[] = TPM_BASE_PTRS;
33 
34 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
35 /*! @brief Pointers to TPM clocks for each instance. */
36 static const clock_ip_name_t s_tpmClocks[] = TPM_CLOCKS;
37 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
38 
39 /*******************************************************************************
40  * Code
41  ******************************************************************************/
TPM_GetInstance(TPM_Type * base)42 static uint32_t TPM_GetInstance(TPM_Type *base)
43 {
44     uint32_t instance;
45     uint32_t tpmArrayCount = (sizeof(s_tpmBases) / sizeof(s_tpmBases[0]));
46 
47     /* Find the instance index from base address mappings. */
48     for (instance = 0; instance < tpmArrayCount; instance++)
49     {
50         if (s_tpmBases[instance] == base)
51         {
52             break;
53         }
54     }
55 
56     assert(instance < tpmArrayCount);
57 
58     return instance;
59 }
60 
TPM_Init(TPM_Type * base,const tpm_config_t * config)61 void TPM_Init(TPM_Type *base, const tpm_config_t *config)
62 {
63     assert(config);
64 
65 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
66     /* Enable the module clock */
67     CLOCK_EnableClock(s_tpmClocks[TPM_GetInstance(base)]);
68 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
69 
70 #if defined(FSL_FEATURE_TPM_HAS_GLOBAL) && FSL_FEATURE_TPM_HAS_GLOBAL
71     /* TPM reset is available on certain SoC's */
72     TPM_Reset(base);
73 #endif
74 
75     /* Set the clock prescale factor */
76     base->SC = TPM_SC_PS(config->prescale);
77 
78     /* Setup the counter operation */
79     base->CONF = TPM_CONF_DOZEEN(config->enableDoze) | TPM_CONF_GTBEEN(config->useGlobalTimeBase) |
80                  TPM_CONF_CROT(config->enableReloadOnTrigger) | TPM_CONF_CSOT(config->enableStartOnTrigger) |
81                  TPM_CONF_CSOO(config->enableStopOnOverflow) |
82 #if defined(FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER) && FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER
83                  TPM_CONF_CPOT(config->enablePauseOnTrigger) |
84 #endif
85 #if defined(FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION) && FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION
86                  TPM_CONF_TRGSRC(config->triggerSource) |
87 #endif
88                  TPM_CONF_TRGSEL(config->triggerSelect);
89     if (config->enableDebugMode)
90     {
91         base->CONF |= TPM_CONF_DBGMODE_MASK;
92     }
93     else
94     {
95         base->CONF &= ~TPM_CONF_DBGMODE_MASK;
96     }
97 }
98 
TPM_Deinit(TPM_Type * base)99 void TPM_Deinit(TPM_Type *base)
100 {
101     /* Stop the counter */
102     base->SC &= ~TPM_SC_CMOD_MASK;
103 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
104     /* Gate the TPM clock */
105     CLOCK_DisableClock(s_tpmClocks[TPM_GetInstance(base)]);
106 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
107 }
108 
TPM_GetDefaultConfig(tpm_config_t * config)109 void TPM_GetDefaultConfig(tpm_config_t *config)
110 {
111     assert(config);
112 
113     /* TPM clock divide by 1 */
114     config->prescale = kTPM_Prescale_Divide_1;
115     /* Use internal TPM counter as timebase */
116     config->useGlobalTimeBase = false;
117     /* TPM counter continues in doze mode */
118     config->enableDoze = false;
119     /* TPM counter pauses when in debug mode */
120     config->enableDebugMode = false;
121     /* TPM counter will not be reloaded on input trigger */
122     config->enableReloadOnTrigger = false;
123     /* TPM counter continues running after overflow */
124     config->enableStopOnOverflow = false;
125     /* TPM counter starts immediately once it is enabled */
126     config->enableStartOnTrigger = false;
127 #if defined(FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER) && FSL_FEATURE_TPM_HAS_PAUSE_COUNTER_ON_TRIGGER
128     config->enablePauseOnTrigger = false;
129 #endif
130     /* Choose trigger select 0 as input trigger for controlling counter operation */
131     config->triggerSelect = kTPM_Trigger_Select_0;
132 #if defined(FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION) && FSL_FEATURE_TPM_HAS_EXTERNAL_TRIGGER_SELECTION
133     /* Choose external trigger source to control counter operation */
134     config->triggerSource = kTPM_TriggerSource_External;
135 #endif
136 }
137 
TPM_SetupPwm(TPM_Type * base,const tpm_chnl_pwm_signal_param_t * chnlParams,uint8_t numOfChnls,tpm_pwm_mode_t mode,uint32_t pwmFreq_Hz,uint32_t srcClock_Hz)138 status_t TPM_SetupPwm(TPM_Type *base,
139                       const tpm_chnl_pwm_signal_param_t *chnlParams,
140                       uint8_t numOfChnls,
141                       tpm_pwm_mode_t mode,
142                       uint32_t pwmFreq_Hz,
143                       uint32_t srcClock_Hz)
144 {
145     assert(chnlParams);
146     assert(pwmFreq_Hz);
147     assert(numOfChnls);
148     assert(srcClock_Hz);
149 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
150     if(mode == kTPM_CombinedPwm)
151     {
152         assert(FSL_FEATURE_TPM_COMBINE_HAS_EFFECTn(base));
153     }
154 #endif
155 
156     uint32_t mod;
157     uint32_t tpmClock = (srcClock_Hz / (1U << (base->SC & TPM_SC_PS_MASK)));
158     uint16_t cnv;
159     uint8_t i;
160 
161 #if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL
162     /* The TPM's QDCTRL register required to be effective */
163     if( FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base) )
164     {
165         /* Clear quadrature Decoder mode because in quadrature Decoder mode PWM doesn't operate*/
166         base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK;
167     }
168 #endif
169 
170     switch (mode)
171     {
172         case kTPM_EdgeAlignedPwm:
173 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
174         case kTPM_CombinedPwm:
175 #endif
176             base->SC &= ~TPM_SC_CPWMS_MASK;
177             mod = (tpmClock / pwmFreq_Hz) - 1;
178             break;
179         case kTPM_CenterAlignedPwm:
180             base->SC |= TPM_SC_CPWMS_MASK;
181             mod = tpmClock / (pwmFreq_Hz * 2);
182             break;
183         default:
184             return kStatus_Fail;
185     }
186 
187     /* Return an error in case we overflow the registers, probably would require changing
188      * clock source to get the desired frequency */
189     if (mod > 65535U)
190     {
191         return kStatus_Fail;
192     }
193     /* Set the PWM period */
194     base->MOD = mod;
195 
196     /* Setup each TPM channel */
197     for (i = 0; i < numOfChnls; i++)
198     {
199         /* Return error if requested dutycycle is greater than the max allowed */
200         if (chnlParams->dutyCyclePercent > 100)
201         {
202             return kStatus_Fail;
203         }
204 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
205         if (mode == kTPM_CombinedPwm)
206         {
207             uint16_t cnvFirstEdge;
208 
209             /* This check is added for combined mode as the channel number should be the pair number */
210             if (chnlParams->chnlNumber >= (FSL_FEATURE_TPM_CHANNEL_COUNTn(base) / 2))
211             {
212                 return kStatus_Fail;
213             }
214 
215             /* Return error if requested value is greater than the max allowed */
216             if (chnlParams->firstEdgeDelayPercent > 100)
217             {
218                 return kStatus_Fail;
219             }
220             /* Configure delay of the first edge */
221             if (chnlParams->firstEdgeDelayPercent == 0)
222             {
223                 /* No delay for the first edge */
224                 cnvFirstEdge = 0;
225             }
226             else
227             {
228                 cnvFirstEdge = (mod * chnlParams->firstEdgeDelayPercent) / 100;
229             }
230             /* Configure dutycycle */
231             if (chnlParams->dutyCyclePercent == 0)
232             {
233                 /* Signal stays low */
234                 cnv = 0;
235                 cnvFirstEdge = 0;
236             }
237             else
238             {
239                 cnv = (mod * chnlParams->dutyCyclePercent) / 100;
240                 /* For 100% duty cycle */
241                 if (cnv >= mod)
242                 {
243                     cnv = mod + 1;
244                 }
245             }
246 
247             /* Set the combine bit for the channel pair */
248             base->COMBINE |= (1U << (TPM_COMBINE_COMBINE0_SHIFT + (TPM_COMBINE_SHIFT * chnlParams->chnlNumber)));
249 
250             /* When switching mode, disable channel n first */
251             base->CONTROLS[chnlParams->chnlNumber * 2].CnSC &=
252                 ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
253 
254             /* Wait till mode change to disable channel is acknowledged */
255             while ((base->CONTROLS[chnlParams->chnlNumber * 2].CnSC &
256                     (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
257             {
258             }
259 
260             /* Set the requested PWM mode for channel n, PWM output requires mode select to be set to 2 */
261             base->CONTROLS[chnlParams->chnlNumber * 2].CnSC |=
262                 ((chnlParams->level << TPM_CnSC_ELSA_SHIFT) | (2U << TPM_CnSC_MSA_SHIFT));
263 
264             /* Wait till mode change is acknowledged */
265             while (!(base->CONTROLS[chnlParams->chnlNumber * 2].CnSC &
266                      (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
267             {
268             }
269             /* Set the channel pair values */
270             base->CONTROLS[chnlParams->chnlNumber * 2].CnV = cnvFirstEdge;
271 
272             /* When switching mode, disable channel n + 1 first */
273             base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC &=
274                 ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
275 
276             /* Wait till mode change to disable channel is acknowledged */
277             while ((base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC &
278                     (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
279             {
280             }
281 
282             /* Set the requested PWM mode for channel n + 1, PWM output requires mode select to be set to 2 */
283             base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC |=
284                 ((chnlParams->level << TPM_CnSC_ELSA_SHIFT) | (2U << TPM_CnSC_MSA_SHIFT));
285 
286             /* Wait till mode change is acknowledged */
287             while (!(base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnSC &
288                      (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
289             {
290             }
291             /* Set the channel pair values */
292             base->CONTROLS[(chnlParams->chnlNumber * 2) + 1].CnV = cnvFirstEdge + cnv;
293         }
294         else
295         {
296 #endif
297             if (chnlParams->dutyCyclePercent == 0)
298             {
299                 /* Signal stays low */
300                 cnv = 0;
301             }
302             else
303             {
304                 cnv = (mod * chnlParams->dutyCyclePercent) / 100;
305                 /* For 100% duty cycle */
306                 if (cnv >= mod)
307                 {
308                     cnv = mod + 1;
309                 }
310             }
311 
312             /* When switching mode, disable channel first */
313             base->CONTROLS[chnlParams->chnlNumber].CnSC &=
314                 ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
315 
316             /* Wait till mode change to disable channel is acknowledged */
317             while ((base->CONTROLS[chnlParams->chnlNumber].CnSC &
318                     (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
319             {
320             }
321 
322             /* Set the requested PWM mode, PWM output requires mode select to be set to 2 */
323             base->CONTROLS[chnlParams->chnlNumber].CnSC |=
324                 ((chnlParams->level << TPM_CnSC_ELSA_SHIFT) | (2U << TPM_CnSC_MSA_SHIFT));
325 
326             /* Wait till mode change is acknowledged */
327             while (!(base->CONTROLS[chnlParams->chnlNumber].CnSC &
328                      (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
329             {
330             }
331             base->CONTROLS[chnlParams->chnlNumber].CnV = cnv;
332 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
333         }
334 #endif
335 
336         chnlParams++;
337     }
338 
339     return kStatus_Success;
340 }
341 
TPM_UpdatePwmDutycycle(TPM_Type * base,tpm_chnl_t chnlNumber,tpm_pwm_mode_t currentPwmMode,uint8_t dutyCyclePercent)342 void TPM_UpdatePwmDutycycle(TPM_Type *base,
343                             tpm_chnl_t chnlNumber,
344                             tpm_pwm_mode_t currentPwmMode,
345                             uint8_t dutyCyclePercent)
346 {
347     assert(chnlNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base));
348 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
349     if(currentPwmMode == kTPM_CombinedPwm)
350     {
351         assert(FSL_FEATURE_TPM_COMBINE_HAS_EFFECTn(base));
352     }
353 #endif
354 
355     uint16_t cnv, mod;
356 
357     mod = base->MOD;
358 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
359     if (currentPwmMode == kTPM_CombinedPwm)
360     {
361         uint16_t cnvFirstEdge;
362 
363         /* This check is added for combined mode as the channel number should be the pair number */
364         if (chnlNumber >= (FSL_FEATURE_TPM_CHANNEL_COUNTn(base) / 2))
365         {
366             return;
367         }
368         cnv = (mod * dutyCyclePercent) / 100;
369         cnvFirstEdge = base->CONTROLS[chnlNumber * 2].CnV;
370         /* For 100% duty cycle */
371         if (cnv >= mod)
372         {
373             cnv = mod + 1;
374         }
375         base->CONTROLS[(chnlNumber * 2) + 1].CnV = cnvFirstEdge + cnv;
376     }
377     else
378     {
379 #endif
380         cnv = (mod * dutyCyclePercent) / 100;
381         /* For 100% duty cycle */
382         if (cnv >= mod)
383         {
384             cnv = mod + 1;
385         }
386         base->CONTROLS[chnlNumber].CnV = cnv;
387 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
388     }
389 #endif
390 }
391 
TPM_UpdateChnlEdgeLevelSelect(TPM_Type * base,tpm_chnl_t chnlNumber,uint8_t level)392 void TPM_UpdateChnlEdgeLevelSelect(TPM_Type *base, tpm_chnl_t chnlNumber, uint8_t level)
393 {
394     assert(chnlNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base));
395 
396     uint32_t reg = base->CONTROLS[chnlNumber].CnSC & ~(TPM_CnSC_CHF_MASK);
397 
398     /* When switching mode, disable channel first  */
399     base->CONTROLS[chnlNumber].CnSC &=
400         ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
401 
402     /* Wait till mode change to disable channel is acknowledged */
403     while ((base->CONTROLS[chnlNumber].CnSC &
404             (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
405     {
406     }
407 
408     /* Clear the field and write the new level value */
409     reg &= ~(TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
410     reg |= ((uint32_t)level << TPM_CnSC_ELSA_SHIFT) & (TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
411 
412     base->CONTROLS[chnlNumber].CnSC = reg;
413 
414     /* Wait till mode change is acknowledged */
415     reg &= (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
416     while (reg != (base->CONTROLS[chnlNumber].CnSC &
417                    (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
418     {
419     }
420 }
421 
TPM_SetupInputCapture(TPM_Type * base,tpm_chnl_t chnlNumber,tpm_input_capture_edge_t captureMode)422 void TPM_SetupInputCapture(TPM_Type *base, tpm_chnl_t chnlNumber, tpm_input_capture_edge_t captureMode)
423 {
424     assert(chnlNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base));
425 
426 #if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL
427     /* The TPM's QDCTRL register required to be effective */
428     if( FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base) )
429     {
430         /* Clear quadrature Decoder mode for channel 0 or 1*/
431         if ((chnlNumber == 0) || (chnlNumber == 1))
432         {
433             base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK;
434         }
435     }
436 #endif
437 
438 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
439         /* The TPM's COMBINE register required to be effective */
440     if( FSL_FEATURE_TPM_COMBINE_HAS_EFFECTn(base) )
441     {
442         /* Clear the combine bit for chnlNumber */
443         base->COMBINE &= ~(1U << TPM_COMBINE_SHIFT * (chnlNumber / 2));
444     }
445 #endif
446 
447     /* When switching mode, disable channel first  */
448     base->CONTROLS[chnlNumber].CnSC &=
449         ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
450 
451     /* Wait till mode change to disable channel is acknowledged */
452     while ((base->CONTROLS[chnlNumber].CnSC &
453             (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
454     {
455     }
456 
457     /* Set the requested input capture mode */
458     base->CONTROLS[chnlNumber].CnSC |= captureMode;
459 
460     /* Wait till mode change is acknowledged */
461     while (!(base->CONTROLS[chnlNumber].CnSC &
462              (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
463     {
464     }
465 }
466 
TPM_SetupOutputCompare(TPM_Type * base,tpm_chnl_t chnlNumber,tpm_output_compare_mode_t compareMode,uint32_t compareValue)467 void TPM_SetupOutputCompare(TPM_Type *base,
468                             tpm_chnl_t chnlNumber,
469                             tpm_output_compare_mode_t compareMode,
470                             uint32_t compareValue)
471 {
472     assert(chnlNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base));
473 
474 #if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL
475     /* The TPM's QDCTRL register required to be effective */
476     if( FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base) )
477     {
478         /* Clear quadrature Decoder mode for channel 0 or 1 */
479         if ((chnlNumber == 0) || (chnlNumber == 1))
480         {
481             base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK;
482         }
483     }
484 #endif
485 
486     /* When switching mode, disable channel first  */
487     base->CONTROLS[chnlNumber].CnSC &=
488         ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
489 
490     /* Wait till mode change to disable channel is acknowledged */
491     while ((base->CONTROLS[chnlNumber].CnSC &
492             (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
493     {
494     }
495 
496     /* Setup the channel output behaviour when a match occurs with the compare value */
497     base->CONTROLS[chnlNumber].CnSC |= compareMode;
498 
499     /* Setup the compare value */
500     base->CONTROLS[chnlNumber].CnV = compareValue;
501 
502     /* Wait till mode change is acknowledged */
503     while (!(base->CONTROLS[chnlNumber].CnSC &
504              (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
505     {
506     }
507 }
508 
509 #if defined(FSL_FEATURE_TPM_HAS_COMBINE) && FSL_FEATURE_TPM_HAS_COMBINE
TPM_SetupDualEdgeCapture(TPM_Type * base,tpm_chnl_t chnlPairNumber,const tpm_dual_edge_capture_param_t * edgeParam,uint32_t filterValue)510 void TPM_SetupDualEdgeCapture(TPM_Type *base,
511                               tpm_chnl_t chnlPairNumber,
512                               const tpm_dual_edge_capture_param_t *edgeParam,
513                               uint32_t filterValue)
514 {
515     assert(edgeParam);
516     assert(chnlPairNumber < FSL_FEATURE_TPM_CHANNEL_COUNTn(base) / 2);
517     assert(FSL_FEATURE_TPM_COMBINE_HAS_EFFECTn(base));
518 
519     uint32_t reg;
520 
521 #if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL
522     /* The TPM's QDCTRL register required to be effective */
523     if( FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base) )
524     {
525         /* Clear quadrature Decoder mode for channel 0 or 1*/
526         if (chnlPairNumber == 0)
527         {
528             base->QDCTRL &= ~TPM_QDCTRL_QUADEN_MASK;
529         }
530     }
531 #endif
532 
533     /* Unlock: When switching mode, disable channel first */
534     base->CONTROLS[chnlPairNumber * 2].CnSC &=
535         ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
536 
537     /* Wait till mode change to disable channel is acknowledged */
538     while ((base->CONTROLS[chnlPairNumber * 2].CnSC &
539             (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
540     {
541     }
542 
543     base->CONTROLS[chnlPairNumber * 2 + 1].CnSC &=
544         ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
545 
546     /* Wait till mode change to disable channel is acknowledged */
547     while ((base->CONTROLS[chnlPairNumber * 2 + 1].CnSC &
548             (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
549     {
550     }
551 
552     /* Now, the registers for input mode can be operated. */
553     if (edgeParam->enableSwap)
554     {
555         /* Set the combine and swap bits for the channel pair */
556         base->COMBINE |= (TPM_COMBINE_COMBINE0_MASK | TPM_COMBINE_COMSWAP0_MASK)
557                          << (TPM_COMBINE_SHIFT * chnlPairNumber);
558 
559         /* Input filter setup for channel n+1 input */
560         reg = base->FILTER;
561         reg &= ~(TPM_FILTER_CH0FVAL_MASK << (TPM_FILTER_CH1FVAL_SHIFT * (chnlPairNumber + 1)));
562         reg |= (filterValue << (TPM_FILTER_CH1FVAL_SHIFT * (chnlPairNumber + 1)));
563         base->FILTER = reg;
564     }
565     else
566     {
567         reg = base->COMBINE;
568         /* Clear the swap bit for the channel pair */
569         reg &= ~(TPM_COMBINE_COMSWAP0_MASK << (TPM_COMBINE_COMSWAP0_SHIFT * chnlPairNumber));
570 
571         /* Set the combine bit for the channel pair */
572         reg |= TPM_COMBINE_COMBINE0_MASK << (TPM_COMBINE_SHIFT * chnlPairNumber);
573         base->COMBINE = reg;
574 
575         /* Input filter setup for channel n input */
576         reg = base->FILTER;
577         reg &= ~(TPM_FILTER_CH0FVAL_MASK << (TPM_FILTER_CH1FVAL_SHIFT * chnlPairNumber));
578         reg |= (filterValue << (TPM_FILTER_CH1FVAL_SHIFT * chnlPairNumber));
579         base->FILTER = reg;
580     }
581 
582     /* Setup the edge detection from channel n */
583     base->CONTROLS[chnlPairNumber * 2].CnSC |= edgeParam->currChanEdgeMode;
584 
585     /* Wait till mode change is acknowledged */
586     while (!(base->CONTROLS[chnlPairNumber * 2].CnSC &
587              (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
588     {
589     }
590 
591     /* Setup the edge detection from channel n+1 */
592     base->CONTROLS[(chnlPairNumber * 2) + 1].CnSC |= edgeParam->nextChanEdgeMode;
593 
594     /* Wait till mode change is acknowledged */
595     while (!(base->CONTROLS[(chnlPairNumber * 2) + 1].CnSC &
596              (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
597     {
598     }
599 }
600 #endif
601 
602 #if defined(FSL_FEATURE_TPM_HAS_QDCTRL) && FSL_FEATURE_TPM_HAS_QDCTRL
TPM_SetupQuadDecode(TPM_Type * base,const tpm_phase_params_t * phaseAParams,const tpm_phase_params_t * phaseBParams,tpm_quad_decode_mode_t quadMode)603 void TPM_SetupQuadDecode(TPM_Type *base,
604                          const tpm_phase_params_t *phaseAParams,
605                          const tpm_phase_params_t *phaseBParams,
606                          tpm_quad_decode_mode_t quadMode)
607 {
608     assert(phaseAParams);
609     assert(phaseBParams);
610     assert(FSL_FEATURE_TPM_QDCTRL_HAS_EFFECTn(base));
611 
612     base->CONTROLS[0].CnSC &= ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
613 
614     /* Wait till mode change to disable channel is acknowledged */
615     while ((base->CONTROLS[0].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
616     {
617     }
618     uint32_t reg;
619 
620     /* Set Phase A filter value */
621     reg = base->FILTER;
622     reg &= ~(TPM_FILTER_CH0FVAL_MASK);
623     reg |= TPM_FILTER_CH0FVAL(phaseAParams->phaseFilterVal);
624     base->FILTER = reg;
625 
626 #if defined(FSL_FEATURE_TPM_HAS_POL) && FSL_FEATURE_TPM_HAS_POL
627     /* Set Phase A polarity */
628     if (phaseAParams->phasePolarity)
629     {
630         base->POL |= TPM_POL_POL0_MASK;
631     }
632     else
633     {
634         base->POL &= ~TPM_POL_POL0_MASK;
635     }
636 #endif
637 
638     base->CONTROLS[1].CnSC &= ~(TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK);
639 
640     /* Wait till mode change to disable channel is acknowledged */
641     while ((base->CONTROLS[1].CnSC & (TPM_CnSC_MSA_MASK | TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK | TPM_CnSC_ELSB_MASK)))
642     {
643     }
644     /* Set Phase B filter value */
645     reg = base->FILTER;
646     reg &= ~(TPM_FILTER_CH1FVAL_MASK);
647     reg |= TPM_FILTER_CH1FVAL(phaseBParams->phaseFilterVal);
648     base->FILTER = reg;
649 #if defined(FSL_FEATURE_TPM_HAS_POL) && FSL_FEATURE_TPM_HAS_POL
650     /* Set Phase B polarity */
651     if (phaseBParams->phasePolarity)
652     {
653         base->POL |= TPM_POL_POL1_MASK;
654     }
655     else
656     {
657         base->POL &= ~TPM_POL_POL1_MASK;
658     }
659 #endif
660 
661     /* Set Quadrature mode */
662     reg = base->QDCTRL;
663     reg &= ~(TPM_QDCTRL_QUADMODE_MASK);
664     reg |= TPM_QDCTRL_QUADMODE(quadMode);
665     base->QDCTRL = reg;
666 
667     /* Enable Quad decode */
668     base->QDCTRL |= TPM_QDCTRL_QUADEN_MASK;
669 }
670 
671 #endif
672 
TPM_EnableInterrupts(TPM_Type * base,uint32_t mask)673 void TPM_EnableInterrupts(TPM_Type *base, uint32_t mask)
674 {
675     uint32_t chnlInterrupts = (mask & 0xFF);
676     uint8_t chnlNumber = 0;
677 
678     /* Enable the timer overflow interrupt */
679     if (mask & kTPM_TimeOverflowInterruptEnable)
680     {
681         base->SC |= TPM_SC_TOIE_MASK;
682     }
683 
684     /* Enable the channel interrupts */
685     while (chnlInterrupts)
686     {
687         if (chnlInterrupts & 0x1)
688         {
689             base->CONTROLS[chnlNumber].CnSC |= TPM_CnSC_CHIE_MASK;
690         }
691         chnlNumber++;
692         chnlInterrupts = chnlInterrupts >> 1U;
693     }
694 }
695 
TPM_DisableInterrupts(TPM_Type * base,uint32_t mask)696 void TPM_DisableInterrupts(TPM_Type *base, uint32_t mask)
697 {
698     uint32_t chnlInterrupts = (mask & 0xFF);
699     uint8_t chnlNumber = 0;
700 
701     /* Disable the timer overflow interrupt */
702     if (mask & kTPM_TimeOverflowInterruptEnable)
703     {
704         base->SC &= ~TPM_SC_TOIE_MASK;
705     }
706 
707     /* Disable the channel interrupts */
708     while (chnlInterrupts)
709     {
710         if (chnlInterrupts & 0x1)
711         {
712             base->CONTROLS[chnlNumber].CnSC &= ~TPM_CnSC_CHIE_MASK;
713         }
714         chnlNumber++;
715         chnlInterrupts = chnlInterrupts >> 1U;
716     }
717 }
718 
TPM_GetEnabledInterrupts(TPM_Type * base)719 uint32_t TPM_GetEnabledInterrupts(TPM_Type *base)
720 {
721     uint32_t enabledInterrupts = 0;
722     int8_t chnlCount = FSL_FEATURE_TPM_CHANNEL_COUNTn(base);
723 
724     /* The CHANNEL_COUNT macro returns -1 if it cannot match the TPM instance */
725     assert(chnlCount != -1);
726 
727     /* Check if timer overflow interrupt is enabled */
728     if (base->SC & TPM_SC_TOIE_MASK)
729     {
730         enabledInterrupts |= kTPM_TimeOverflowInterruptEnable;
731     }
732 
733     /* Check if the channel interrupts are enabled */
734     while (chnlCount > 0)
735     {
736         chnlCount--;
737         if (base->CONTROLS[chnlCount].CnSC & TPM_CnSC_CHIE_MASK)
738         {
739             enabledInterrupts |= (1U << chnlCount);
740         }
741     }
742 
743     return enabledInterrupts;
744 }
745