1 /**************************************************************************//**
2 * @file sc.c
3 * @version V3.00
4 * @brief Smartcard(SC) driver source file
5 *
6 * @copyright SPDX-License-Identifier: Apache-2.0
7 * @copyright Copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
8 *****************************************************************************/
9 #include "NuMicro.h"
10
11
12 /* Below are variables used locally by SC driver and does not want to parse by doxygen unless HIDDEN_SYMBOLS is defined */
13 /** @cond HIDDEN_SYMBOLS */
14 static uint32_t g_u32CardStateIgnore[SC_INTERFACE_NUM] = {0UL, 0UL, 0UL};
15
16 /** @endcond HIDDEN_SYMBOLS */
17
18 /** @addtogroup Standard_Driver Standard Driver
19 @{
20 */
21
22 /** @addtogroup SC_Driver SC Driver
23 @{
24 */
25
26 /** @addtogroup SC_EXPORTED_FUNCTIONS SC Exported Functions
27 @{
28 */
29
30 /**
31 * @brief Indicates specified smartcard slot status
32 *
33 * @param[in] sc The pointer of smartcard module.
34 *
35 * @return Card insert status
36 * @retval TRUE Card insert
37 * @retval FALSE Card remove
38 *
39 * @details This function is used to check if specified smartcard slot is presented.
40 */
SC_IsCardInserted(SC_T * sc)41 uint32_t SC_IsCardInserted(SC_T *sc)
42 {
43 uint32_t u32Ret;
44
45 /* put conditions into two variable to remove IAR compilation warning */
46 uint32_t cond1 = ((sc->STATUS & SC_STATUS_CDPINSTS_Msk) >> SC_STATUS_CDPINSTS_Pos);
47 uint32_t cond2 = ((sc->CTL & SC_CTL_CDLV_Msk) >> SC_CTL_CDLV_Pos);
48
49 if(((sc == SC0) || (sc == SC0_NS)) && (g_u32CardStateIgnore[0] == 1UL))
50 {
51 u32Ret = (uint32_t)TRUE;
52 }
53 else if(((sc == SC1) || (sc == SC1_NS)) && (g_u32CardStateIgnore[1] == 1UL))
54 {
55 u32Ret = (uint32_t)TRUE;
56 }
57 else if(((sc == SC2) || (sc == SC2_NS)) && (g_u32CardStateIgnore[2] == 1UL))
58 {
59 u32Ret = (uint32_t)TRUE;
60 }
61 else if(cond1 != cond2)
62 {
63 u32Ret = (uint32_t)FALSE;
64 }
65 else
66 {
67 u32Ret = (uint32_t)TRUE;
68 }
69
70 return u32Ret;
71 }
72
73 /*
74 * @brief Reset the Tx and Rx FIFO of smartcard module
75 *
76 * @param[in] sc The pointer of smartcard module.
77 *
78 * @return None
79 *
80 * @details This function reset both transmit and receive FIFO of specified smartcard module.
81 */
SC_ClearFIFO(SC_T * sc)82 void SC_ClearFIFO(SC_T *sc)
83 {
84 while((sc->ALTCTL & SC_ALTCTL_SYNC_Msk) == SC_ALTCTL_SYNC_Msk) {}
85 sc->ALTCTL |= (SC_ALTCTL_TXRST_Msk | SC_ALTCTL_RXRST_Msk);
86 }
87
88 /**
89 * @brief Disable specified smartcard module
90 *
91 * @param[in] sc The pointer of smartcard module.
92 *
93 * @return None
94 *
95 * @details This function disable specified smartcard module, and force all transition to IDLE state.
96 */
SC_Close(SC_T * sc)97 void SC_Close(SC_T *sc)
98 {
99 sc->INTEN = 0UL;
100
101 while((sc->PINCTL & SC_PINCTL_SYNC_Msk) == SC_PINCTL_SYNC_Msk) {}
102 sc->PINCTL = 0UL;
103 sc->ALTCTL = 0UL;
104
105 while((sc->CTL & SC_CTL_SYNC_Msk) == SC_CTL_SYNC_Msk) {}
106 sc->CTL = 0UL;
107 }
108
109 /**
110 * @brief Initialized smartcard module
111 *
112 * @param[in] sc The pointer of smartcard module.
113 * @param[in] u32CardDet Card detect polarity, select the SC_CD pin state which indicates card absent. Could be:
114 * -\ref SC_PIN_STATE_HIGH
115 * -\ref SC_PIN_STATE_LOW
116 * -\ref SC_PIN_STATE_IGNORE, no card detect pin, always assumes card present.
117 * @param[in] u32PWR Power off polarity, select the SC_PWR pin state which could set smartcard VCC to high level. Could be:
118 * -\ref SC_PIN_STATE_HIGH
119 * -\ref SC_PIN_STATE_LOW
120 *
121 * @return None
122 *
123 * @details This function initialized smartcard module.
124 */
SC_Open(SC_T * sc,uint32_t u32CardDet,uint32_t u32PWR)125 void SC_Open(SC_T *sc, uint32_t u32CardDet, uint32_t u32PWR)
126 {
127 uint32_t u32Reg = 0UL, u32Intf;
128
129 if((sc == SC0) || (sc == SC0_NS))
130 {
131 u32Intf = 0UL;
132 }
133 else if((sc == SC1) || (sc == SC1_NS))
134 {
135 u32Intf = 1UL;
136 }
137 else
138 {
139 u32Intf = 2UL;
140 }
141
142 if(u32CardDet != SC_PIN_STATE_IGNORE)
143 {
144 u32Reg = u32CardDet ? 0UL : SC_CTL_CDLV_Msk;
145 g_u32CardStateIgnore[u32Intf] = 0UL;
146 }
147 else
148 {
149 g_u32CardStateIgnore[u32Intf] = 1UL;
150 }
151 sc->PINCTL = u32PWR ? 0UL : SC_PINCTL_PWRINV_Msk;
152
153 while((sc->CTL & SC_CTL_SYNC_Msk) == SC_CTL_SYNC_Msk) {}
154 sc->CTL = SC_CTL_SCEN_Msk | SC_CTL_TMRSEL_Msk | u32Reg;
155 }
156
157 /**
158 * @brief Reset specified smartcard module
159 *
160 * @param[in] sc The pointer of smartcard module.
161 *
162 * @return None
163 *
164 * @details This function reset specified smartcard module to its default state for activate smartcard.
165 */
SC_ResetReader(SC_T * sc)166 void SC_ResetReader(SC_T *sc)
167 {
168 uint32_t u32Intf;
169
170 if((sc == SC0) || (sc == SC0_NS))
171 {
172 u32Intf = 0UL;
173 }
174 else if((sc == SC1) || (sc == SC1_NS))
175 {
176 u32Intf = 1UL;
177 }
178 else
179 {
180 u32Intf = 2UL;
181 }
182
183 /* Reset FIFO, enable auto de-activation while card removal */
184 sc->ALTCTL |= (SC_ALTCTL_TXRST_Msk | SC_ALTCTL_RXRST_Msk | SC_ALTCTL_ADACEN_Msk);
185 /* Set Rx trigger level to 1 character, longest card detect debounce period, disable error retry (EMV ATR does not use error retry) */
186 while((sc->CTL & SC_CTL_SYNC_Msk) == SC_CTL_SYNC_Msk) {}
187 sc->CTL &= ~(SC_CTL_RXTRGLV_Msk |
188 SC_CTL_CDDBSEL_Msk |
189 SC_CTL_TXRTY_Msk |
190 SC_CTL_TXRTYEN_Msk |
191 SC_CTL_RXRTY_Msk |
192 SC_CTL_RXRTYEN_Msk);
193 while((sc->CTL & SC_CTL_SYNC_Msk) == SC_CTL_SYNC_Msk) {}
194 /* Enable auto convention, and all three smartcard internal timers */
195 sc->CTL |= SC_CTL_AUTOCEN_Msk | SC_CTL_TMRSEL_Msk;
196 /* Disable Rx timeout */
197 sc->RXTOUT = 0UL;
198 /* 372 clocks per ETU by default */
199 sc->ETUCTL = 371UL;
200
201 /* Enable necessary interrupt for smartcard operation */
202 if(g_u32CardStateIgnore[u32Intf]) /* Do not enable card detect interrupt if card present state ignore */
203 {
204 sc->INTEN = (SC_INTEN_RDAIEN_Msk |
205 SC_INTEN_TERRIEN_Msk |
206 SC_INTEN_TMR0IEN_Msk |
207 SC_INTEN_TMR1IEN_Msk |
208 SC_INTEN_TMR2IEN_Msk |
209 SC_INTEN_BGTIEN_Msk |
210 SC_INTEN_ACERRIEN_Msk);
211 }
212 else
213 {
214 sc->INTEN = (SC_INTEN_RDAIEN_Msk |
215 SC_INTEN_TERRIEN_Msk |
216 SC_INTEN_TMR0IEN_Msk |
217 SC_INTEN_TMR1IEN_Msk |
218 SC_INTEN_TMR2IEN_Msk |
219 SC_INTEN_BGTIEN_Msk |
220 SC_INTEN_ACERRIEN_Msk |
221 SC_INTEN_CDIEN_Msk);
222 }
223
224 return;
225 }
226
227 /**
228 * @brief Set Block Guard Time (BGT)
229 *
230 * @param[in] sc The pointer of smartcard module.
231 * @param[in] u32BGT Block guard time using ETU as unit, valid range are between 1 ~ 32.
232 *
233 * @return None
234 *
235 * @details This function is used to configure block guard time (BGT) of specified smartcard module.
236 */
SC_SetBlockGuardTime(SC_T * sc,uint32_t u32BGT)237 void SC_SetBlockGuardTime(SC_T *sc, uint32_t u32BGT)
238 {
239 sc->CTL = (sc->CTL & ~SC_CTL_BGT_Msk) | ((u32BGT - 1UL) << SC_CTL_BGT_Pos);
240 }
241
242 /**
243 * @brief Set Character Guard Time (CGT)
244 *
245 * @param[in] sc The pointer of smartcard module.
246 * @param[in] u32CGT Character guard time using ETU as unit, valid range are between 11 ~ 267.
247 *
248 * @return None
249 *
250 * @details This function is used to configure character guard time (CGT) of specified smartcard module.
251 * @note Before using this API, user should set the correct stop bit length first.
252 */
SC_SetCharGuardTime(SC_T * sc,uint32_t u32CGT)253 void SC_SetCharGuardTime(SC_T *sc, uint32_t u32CGT)
254 {
255 /* CGT is "START bit" + "8-bits" + "Parity bit" + "STOP bit(s)" + "EGT counts" */
256 u32CGT -= ((sc->CTL & SC_CTL_NSB_Msk) == SC_CTL_NSB_Msk) ? 11UL : 12UL;
257 sc->EGT = u32CGT;
258 }
259
260 /**
261 * @brief Stop all smartcard timer
262 *
263 * @param[in] sc The pointer of smartcard module.
264 *
265 * @return None
266 *
267 * @note This function stop the timers within specified smartcard module, \b not timer module.
268 */
SC_StopAllTimer(SC_T * sc)269 void SC_StopAllTimer(SC_T *sc)
270 {
271 while((sc->ALTCTL & SC_ALTCTL_SYNC_Msk) == SC_ALTCTL_SYNC_Msk) {}
272 sc->ALTCTL &= ~(SC_ALTCTL_CNTEN0_Msk | SC_ALTCTL_CNTEN1_Msk | SC_ALTCTL_CNTEN2_Msk);
273 }
274
275 /**
276 * @brief Configure and start smartcard timer
277 *
278 * @param[in] sc The pointer of smartcard module.
279 * @param[in] u32TimerNum Timer to start. Valid values are 0, 1, 2.
280 * @param[in] u32Mode Timer operating mode, valid values are:
281 * - \ref SC_TMR_MODE_0
282 * - \ref SC_TMR_MODE_1
283 * - \ref SC_TMR_MODE_2
284 * - \ref SC_TMR_MODE_3
285 * - \ref SC_TMR_MODE_4
286 * - \ref SC_TMR_MODE_5
287 * - \ref SC_TMR_MODE_6
288 * - \ref SC_TMR_MODE_7
289 * - \ref SC_TMR_MODE_8
290 * - \ref SC_TMR_MODE_F
291 * @param[in] u32ETUCount Timer timeout duration, ETU based. For timer 0, valid range are between 1 ~ 0x1000000 ETUs.
292 * For timer 1 and timer 2, valid range are between 1 ~ 0x100 ETUs.
293 *
294 * @return None
295 *
296 * @note This function start the timer within specified smartcard module, \b not timer module.
297 * @note Depend on the timer operating mode, timer may not start counting immediately and starts when condition match.
298 */
SC_StartTimer(SC_T * sc,uint32_t u32TimerNum,uint32_t u32Mode,uint32_t u32ETUCount)299 void SC_StartTimer(SC_T *sc, uint32_t u32TimerNum, uint32_t u32Mode, uint32_t u32ETUCount)
300 {
301 uint32_t u32Reg = u32Mode | (SC_TMRCTL0_CNT_Msk & (u32ETUCount - 1UL));
302 while((sc->ALTCTL & SC_ALTCTL_SYNC_Msk) == SC_ALTCTL_SYNC_Msk) {}
303 if(u32TimerNum == 0UL)
304 {
305 while((sc->TMRCTL0 & SC_TMRCTL0_SYNC_Msk) == SC_TMRCTL0_SYNC_Msk) {}
306 sc->TMRCTL0 = u32Reg;
307 sc->ALTCTL |= SC_ALTCTL_CNTEN0_Msk;
308 }
309 else if(u32TimerNum == 1UL)
310 {
311 while((sc->TMRCTL1 & SC_TMRCTL1_SYNC_Msk) == SC_TMRCTL1_SYNC_Msk) {}
312 sc->TMRCTL1 = u32Reg;
313 sc->ALTCTL |= SC_ALTCTL_CNTEN1_Msk;
314 }
315 else /* timer 2 */
316 {
317 while((sc->TMRCTL2 & SC_TMRCTL2_SYNC_Msk) == SC_TMRCTL2_SYNC_Msk) {}
318 sc->TMRCTL2 = u32Reg;
319 sc->ALTCTL |= SC_ALTCTL_CNTEN2_Msk;
320 }
321 }
322
323 /**
324 * @brief Stop a smartcard timer
325 *
326 * @param[in] sc The pointer of smartcard module.
327 * @param[in] u32TimerNum Timer to stop. Valid values are 0, 1, 2.
328 *
329 * @return None
330 *
331 * @note This function stop the timer within specified smartcard module, \b not timer module.
332 */
SC_StopTimer(SC_T * sc,uint32_t u32TimerNum)333 void SC_StopTimer(SC_T *sc, uint32_t u32TimerNum)
334 {
335 while(sc->ALTCTL & SC_ALTCTL_SYNC_Msk) {}
336
337 if(u32TimerNum == 0UL) /* timer 0 */
338 {
339 sc->ALTCTL &= ~SC_ALTCTL_CNTEN0_Msk;
340 }
341 else if(u32TimerNum == 1UL) /* timer 1 */
342 {
343 sc->ALTCTL &= ~SC_ALTCTL_CNTEN1_Msk;
344 }
345 else /* timer 2 */
346 {
347 sc->ALTCTL &= ~SC_ALTCTL_CNTEN2_Msk;
348 }
349 }
350
351 /**
352 * @brief Get smartcard clock frequency
353 *
354 * @param[in] sc The pointer of smartcard module.
355 *
356 * @return Smartcard frequency in kHZ
357 *
358 * @details This function is used to get specified smartcard module clock frequency in kHz.
359 */
SC_GetInterfaceClock(SC_T * sc)360 uint32_t SC_GetInterfaceClock(SC_T *sc)
361 {
362 uint32_t u32ClkSrc = 0, u32Num = 0, u32ClkFreq = __HIRC, u32Div = 0;
363
364 /* Get smartcard module clock source and divider */
365 if((sc == SC0) || (sc == SC0_NS))
366 {
367 u32Num = 0UL;
368 u32ClkSrc = CLK_GetModuleClockSource(SC0_MODULE);
369 u32Div = CLK_GetModuleClockDivider(SC0_MODULE);
370 }
371 else if((sc == SC1) || (sc == SC1_NS))
372 {
373 u32Num = 1UL;
374 u32ClkSrc = CLK_GetModuleClockSource(SC1_MODULE);
375 u32Div = CLK_GetModuleClockDivider(SC1_MODULE);
376 }
377 else if((sc == SC2) || (sc == SC2_NS))
378 {
379 u32Num = 2UL;
380 u32ClkSrc = CLK_GetModuleClockSource(SC2_MODULE);
381 u32Div = CLK_GetModuleClockDivider(SC2_MODULE);
382 }
383 else
384 {
385 u32ClkFreq = 0UL;
386 }
387
388 if(u32ClkFreq != 0UL)
389 {
390 /* Get smartcard module clock */
391 if(u32ClkSrc == 0UL)
392 {
393 u32ClkFreq = __HXT;
394 }
395 else if(u32ClkSrc == 1UL)
396 {
397 u32ClkFreq = CLK_GetPLLClockFreq();
398 }
399 else if(u32ClkSrc == 2UL)
400 {
401 if(u32Num == 1UL)
402 {
403 u32ClkFreq = CLK_GetPCLK1Freq();
404 }
405 else
406 {
407 u32ClkFreq = CLK_GetPCLK0Freq();
408 }
409 }
410 else
411 {
412 u32ClkFreq = __HIRC;
413 }
414
415 u32ClkFreq /= (u32Div + 1UL) * 1000UL;
416 }
417
418 return u32ClkFreq;
419 }
420
421 /**@}*/ /* end of group SC_EXPORTED_FUNCTIONS */
422
423 /**@}*/ /* end of group SC_Driver */
424
425 /**@}*/ /* end of group Standard_Driver */
426