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