1 /*
2  * Copyright (c) 2016, 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_cmt.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.cmt"
18 #endif
19 
20 /* The standard intermediate frequency (IF). */
21 #define CMT_INTERMEDIATEFREQUENCY_8MHZ (8000000U)
22 /* CMT data modulate mask. */
23 #define CMT_MODULATE_COUNT_WIDTH (8U)
24 /* CMT diver 1. */
25 #define CMT_CMTDIV_ONE (1)
26 /* CMT diver 2. */
27 #define CMT_CMTDIV_TWO (2)
28 /* CMT diver 4. */
29 #define CMT_CMTDIV_FOUR (4)
30 /* CMT diver 8. */
31 #define CMT_CMTDIV_EIGHT (8)
32 
33 /*******************************************************************************
34  * Prototypes
35  ******************************************************************************/
36 
37 /*!
38  * @brief Get instance number for CMT module.
39  *
40  * @param base CMT peripheral base address.
41  */
42 static uint32_t CMT_GetInstance(CMT_Type *base);
43 
44 /*******************************************************************************
45  * Variables
46  ******************************************************************************/
47 
48 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
49 /*! @brief Pointers to cmt clocks for each instance. */
50 static const clock_ip_name_t s_cmtClock[FSL_FEATURE_SOC_CMT_COUNT] = CMT_CLOCKS;
51 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
52 
53 /*! @brief Pointers to cmt bases for each instance. */
54 static CMT_Type *const s_cmtBases[] = CMT_BASE_PTRS;
55 
56 /*! @brief Pointers to cmt IRQ number for each instance. */
57 static const IRQn_Type s_cmtIrqs[] = CMT_IRQS;
58 
59 /*******************************************************************************
60  * Codes
61  ******************************************************************************/
62 
CMT_GetInstance(CMT_Type * base)63 static uint32_t CMT_GetInstance(CMT_Type *base)
64 {
65     uint32_t instance;
66 
67     /* Find the instance index from base address mappings. */
68     for (instance = 0; instance < ARRAY_SIZE(s_cmtBases); instance++)
69     {
70         if (s_cmtBases[instance] == base)
71         {
72             break;
73         }
74     }
75 
76     assert(instance < ARRAY_SIZE(s_cmtBases));
77 
78     return instance;
79 }
80 
81 /*!
82  * brief Gets the CMT default configuration structure. This API
83  * gets the default configuration structure for the CMT_Init().
84  * Use the initialized structure unchanged in CMT_Init() or modify
85  * fields of the structure before calling the CMT_Init().
86  *
87  * param config The CMT configuration structure pointer.
88  */
CMT_GetDefaultConfig(cmt_config_t * config)89 void CMT_GetDefaultConfig(cmt_config_t *config)
90 {
91     assert(NULL != config);
92 
93     /* Initializes the configure structure to zero. */
94     (void)memset(config, 0, sizeof(*config));
95 
96     /* Default infrared output is enabled and set with high active, the divider is set to 1. */
97     config->isInterruptEnabled = false;
98     config->isIroEnabled       = true;
99     config->iroPolarity        = kCMT_IROActiveHigh;
100     config->divider            = kCMT_SecondClkDiv1;
101 }
102 
103 /*!
104  * brief Initializes the CMT module.
105  *
106  * This function ungates the module clock and sets the CMT internal clock,
107  * interrupt, and infrared output signal for the CMT module.
108  *
109  * param base            CMT peripheral base address.
110  * param config          The CMT basic configuration structure.
111  * param busClock_Hz     The CMT module input clock - bus clock frequency.
112  */
CMT_Init(CMT_Type * base,const cmt_config_t * config,uint32_t busClock_Hz)113 void CMT_Init(CMT_Type *base, const cmt_config_t *config, uint32_t busClock_Hz)
114 {
115     assert(NULL != config);
116     assert(busClock_Hz >= CMT_INTERMEDIATEFREQUENCY_8MHZ);
117 
118     uint8_t divider;
119 
120 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
121     /* Ungate clock. */
122     CLOCK_EnableClock(s_cmtClock[CMT_GetInstance(base)]);
123 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
124 
125     /* Sets clock divider. The divider set in pps should be set
126        to make sycClock_Hz/divder = 8MHz */
127     base->PPS = CMT_PPS_PPSDIV(busClock_Hz / CMT_INTERMEDIATEFREQUENCY_8MHZ - 1U);
128     divider   = base->MSC;
129     divider &= ~(uint8_t)CMT_MSC_CMTDIV_MASK;
130     divider |= CMT_MSC_CMTDIV(config->divider);
131     base->MSC = divider;
132 
133     /* Set the IRO signal. */
134     base->OC = CMT_OC_CMTPOL(config->iroPolarity) | CMT_OC_IROPEN(config->isIroEnabled);
135 
136     /* Set interrupt. */
137     if (true == config->isInterruptEnabled)
138     {
139         CMT_EnableInterrupts(base, (uint32_t)kCMT_EndOfCycleInterruptEnable);
140         (void)EnableIRQ(s_cmtIrqs[CMT_GetInstance(base)]);
141     }
142 }
143 
144 /*!
145  * brief Disables the CMT module and gate control.
146  *
147  * This function disables CMT modulator, interrupts, and gates the
148  * CMT clock control. CMT_Init must be called  to use the CMT again.
149  *
150  * param base   CMT peripheral base address.
151  */
CMT_Deinit(CMT_Type * base)152 void CMT_Deinit(CMT_Type *base)
153 {
154     /*Disable the CMT modulator. */
155     base->MSC = 0;
156 
157     /* Disable the interrupt. */
158     CMT_DisableInterrupts(base, (uint32_t)kCMT_EndOfCycleInterruptEnable);
159     (void)DisableIRQ(s_cmtIrqs[CMT_GetInstance(base)]);
160 
161 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
162     /* Gate the clock. */
163     CLOCK_DisableClock(s_cmtClock[CMT_GetInstance(base)]);
164 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
165 }
166 
167 /*!
168  * brief Selects the mode for CMT.
169  *
170  * param base   CMT peripheral base address.
171  * param mode   The CMT feature mode enumeration. See "cmt_mode_t".
172  * param modulateConfig  The carrier generation and modulator configuration.
173  */
CMT_SetMode(CMT_Type * base,cmt_mode_t mode,cmt_modulate_config_t * modulateConfig)174 void CMT_SetMode(CMT_Type *base, cmt_mode_t mode, cmt_modulate_config_t *modulateConfig)
175 {
176     uint8_t mscReg = base->MSC;
177 
178     /* Judge the mode. */
179     if (mode != kCMT_DirectIROCtl)
180     {
181         assert(NULL != modulateConfig);
182 
183         /* Set carrier generator. */
184         CMT_SetCarrirGenerateCountOne(base, modulateConfig->highCount1, modulateConfig->lowCount1);
185         if (mode == kCMT_FSKMode)
186         {
187             CMT_SetCarrirGenerateCountTwo(base, modulateConfig->highCount2, modulateConfig->lowCount2);
188         }
189 
190         /* Set carrier modulator. */
191         CMT_SetModulateMarkSpace(base, modulateConfig->markCount, modulateConfig->spaceCount);
192         mscReg &= ~((uint8_t)CMT_MSC_FSK_MASK | (uint8_t)CMT_MSC_BASE_MASK);
193         mscReg |= (uint8_t)mode;
194     }
195     else
196     {
197         mscReg &= ~(uint8_t)CMT_MSC_MCGEN_MASK;
198     }
199     /* Set the CMT mode. */
200     base->MSC = mscReg;
201 }
202 
203 /*!
204  * brief Gets the mode of the CMT module.
205  *
206  * param base   CMT peripheral base address.
207  * return The CMT mode.
208  *     kCMT_DirectIROCtl     Carrier modulator is disabled; the IRO signal is directly in software control.
209  *     kCMT_TimeMode         Carrier modulator is enabled in time mode.
210  *     kCMT_FSKMode          Carrier modulator is enabled in FSK mode.
211  *     kCMT_BasebandMode     Carrier modulator is enabled in baseband mode.
212  */
CMT_GetMode(CMT_Type * base)213 cmt_mode_t CMT_GetMode(CMT_Type *base)
214 {
215     uint8_t mode = base->MSC;
216     cmt_mode_t ret;
217 
218     if (0U == (mode & CMT_MSC_MCGEN_MASK))
219     { /* Carrier modulator disabled and the IRO signal is in direct software control. */
220         ret = kCMT_DirectIROCtl;
221     }
222     else
223     {
224         /* Carrier modulator is enabled. */
225         if (0U != (mode & CMT_MSC_BASE_MASK))
226         {
227             /* Base band mode. */
228             ret = kCMT_BasebandMode;
229         }
230         else if (0U != (mode & CMT_MSC_FSK_MASK))
231         {
232             /* FSK mode. */
233             ret = kCMT_FSKMode;
234         }
235         else
236         {
237             /* Time mode. */
238             ret = kCMT_TimeMode;
239         }
240     }
241 
242     return ret;
243 }
244 
245 /*!
246  * brief Gets the actual CMT clock frequency.
247  *
248  * param base        CMT peripheral base address.
249  * param busClock_Hz CMT module input clock - bus clock frequency.
250  * return The CMT clock frequency.
251  */
CMT_GetCMTFrequency(CMT_Type * base,uint32_t busClock_Hz)252 uint32_t CMT_GetCMTFrequency(CMT_Type *base, uint32_t busClock_Hz)
253 {
254     uint32_t frequency;
255     uint32_t divider;
256 
257     /* Get intermediate frequency. */
258     frequency = busClock_Hz / (((uint32_t)base->PPS & CMT_PPS_PPSDIV_MASK) + 1U);
259 
260     /* Get the second divider. */
261     divider = (((uint32_t)base->MSC & CMT_MSC_CMTDIV_MASK) >> CMT_MSC_CMTDIV_SHIFT);
262     /* Get CMT frequency. */
263     switch ((cmt_second_clkdiv_t)divider)
264     {
265         case kCMT_SecondClkDiv1:
266             frequency = frequency / (uint32_t)CMT_CMTDIV_ONE;
267             break;
268         case kCMT_SecondClkDiv2:
269             frequency = frequency / (uint32_t)CMT_CMTDIV_TWO;
270             break;
271         case kCMT_SecondClkDiv4:
272             frequency = frequency / (uint32_t)CMT_CMTDIV_FOUR;
273             break;
274         case kCMT_SecondClkDiv8:
275             frequency = frequency / (uint32_t)CMT_CMTDIV_EIGHT;
276             break;
277         default:
278             frequency = frequency / (uint32_t)CMT_CMTDIV_ONE;
279             break;
280     }
281 
282     return frequency;
283 }
284 
285 /*!
286  * brief Sets the modulation mark and space time period for the CMT modulator.
287  *
288  * This function sets the mark time period of the CMT modulator counter
289  * to control the mark time of the output modulated signal from the carrier generator output signal.
290  * If the CMT clock frequency is Fcmt and the carrier out signal frequency is fcg:
291  *      - In Time and Baseband mode: The mark period of the generated signal equals (markCount + 1) / (Fcmt/8).
292  *                                   The space period of the generated signal equals spaceCount / (Fcmt/8).
293  *      - In FSK mode: The mark period of the generated signal equals (markCount + 1)/fcg.
294  *                     The space period of the generated signal equals spaceCount / fcg.
295  *
296  * param base Base address for current CMT instance.
297  * param markCount The number of clock period for CMT modulator signal mark period,
298  *                   in the range of 0 ~ 0xFFFF.
299  * param spaceCount The number of clock period for CMT modulator signal space period,
300  *                   in the range of the 0 ~ 0xFFFF.
301  */
CMT_SetModulateMarkSpace(CMT_Type * base,uint32_t markCount,uint32_t spaceCount)302 void CMT_SetModulateMarkSpace(CMT_Type *base, uint32_t markCount, uint32_t spaceCount)
303 {
304     /* Set modulate mark. */
305     base->CMD1 = (uint8_t)((markCount >> CMT_MODULATE_COUNT_WIDTH) & CMT_CMD1_MB_MASK);
306     base->CMD2 = (uint8_t)(markCount & CMT_CMD2_MB_MASK);
307     /* Set modulate space. */
308     base->CMD3 = (uint8_t)((spaceCount >> CMT_MODULATE_COUNT_WIDTH) & CMT_CMD3_SB_MASK);
309     base->CMD4 = (uint8_t)(spaceCount & CMT_CMD4_SB_MASK);
310 }
311 
312 /*!
313  * brief Sets the IRO (infrared output) signal state.
314  *
315  * Changes the states of the IRO signal when the kCMT_DirectIROMode mode is set
316  * and the IRO signal is enabled.
317  *
318  * param base   CMT peripheral base address.
319  * param state  The control of the IRO signal. See "cmt_infrared_output_state_t"
320  */
CMT_SetIroState(CMT_Type * base,cmt_infrared_output_state_t state)321 void CMT_SetIroState(CMT_Type *base, cmt_infrared_output_state_t state)
322 {
323     uint8_t ocReg = base->OC;
324 
325     ocReg &= ~(uint8_t)CMT_OC_IROL_MASK;
326     ocReg |= CMT_OC_IROL(state);
327 
328     /* Set the infrared output signal control. */
329     base->OC = ocReg;
330 }
331