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) 2021 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) && (g_u32CardStateIgnore[0] == 1UL))
50 {
51 u32Ret = (uint32_t)TRUE;
52 }
53 else if((sc == SC1) && (g_u32CardStateIgnore[1] == 1UL))
54 {
55 u32Ret = (uint32_t)TRUE;
56 }
57 else if((sc == SC2) && (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 uint32_t u32TimeOutCount = SC_TIMEOUT;
85
86 while((sc->ALTCTL & SC_ALTCTL_SYNC_Msk) == SC_ALTCTL_SYNC_Msk)
87 {
88 if(--u32TimeOutCount == 0) break;
89 }
90 sc->ALTCTL |= (SC_ALTCTL_TXRST_Msk | SC_ALTCTL_RXRST_Msk);
91 }
92
93 /**
94 * @brief Disable specified smartcard module
95 *
96 * @param[in] sc The pointer of smartcard module.
97 *
98 * @return None
99 *
100 * @details This function disable specified smartcard module, and force all transition to IDLE state.
101 */
SC_Close(SC_T * sc)102 void SC_Close(SC_T *sc)
103 {
104 uint32_t u32TimeOutCount;
105
106 sc->INTEN = 0UL;
107
108 u32TimeOutCount = SC_TIMEOUT;
109 while((sc->PINCTL & SC_PINCTL_SYNC_Msk) == SC_PINCTL_SYNC_Msk)
110 {
111 if(--u32TimeOutCount == 0UL) break;
112 }
113 sc->PINCTL = 0UL;
114 sc->ALTCTL = 0UL;
115
116 u32TimeOutCount = SC_TIMEOUT;
117 while((sc->CTL & SC_CTL_SYNC_Msk) == SC_CTL_SYNC_Msk)
118 {
119 if(--u32TimeOutCount == 0UL) break;
120 }
121 sc->CTL = 0UL;
122 }
123
124 /**
125 * @brief Initialized smartcard module
126 *
127 * @param[in] sc The pointer of smartcard module.
128 * @param[in] u32CardDet Card detect polarity, select the SC_CD pin state which indicates card absent. Could be:
129 * -\ref SC_PIN_STATE_HIGH
130 * -\ref SC_PIN_STATE_LOW
131 * -\ref SC_PIN_STATE_IGNORE, no card detect pin, always assumes card present.
132 * @param[in] u32PWR Power off polarity, select the SC_PWR pin state which could set smartcard VCC to high level. Could be:
133 * -\ref SC_PIN_STATE_HIGH
134 * -\ref SC_PIN_STATE_LOW
135 *
136 * @return None
137 *
138 * @details This function initialized smartcard module.
139 */
SC_Open(SC_T * sc,uint32_t u32CardDet,uint32_t u32PWR)140 void SC_Open(SC_T *sc, uint32_t u32CardDet, uint32_t u32PWR)
141 {
142 uint32_t u32Reg = 0UL, u32Intf, u32TimeOutCount;
143
144 if(sc == SC0)
145 {
146 u32Intf = 0UL;
147 }
148 else if(sc == SC1)
149 {
150 u32Intf = 1UL;
151 }
152 else
153 {
154 u32Intf = 2UL;
155 }
156
157 if(u32CardDet != SC_PIN_STATE_IGNORE)
158 {
159 u32Reg = u32CardDet ? 0UL : SC_CTL_CDLV_Msk;
160 g_u32CardStateIgnore[u32Intf] = 0UL;
161 }
162 else
163 {
164 g_u32CardStateIgnore[u32Intf] = 1UL;
165 }
166 sc->PINCTL = u32PWR ? 0UL : SC_PINCTL_PWRINV_Msk;
167 u32TimeOutCount = SC_TIMEOUT;
168 while((sc->CTL & SC_CTL_SYNC_Msk) == SC_CTL_SYNC_Msk)
169 {
170 if(--u32TimeOutCount == 0UL) break;
171 }
172 sc->CTL = SC_CTL_SCEN_Msk | SC_CTL_TMRSEL_Msk | u32Reg;
173 }
174
175 /**
176 * @brief Reset specified smartcard module
177 *
178 * @param[in] sc The pointer of smartcard module.
179 *
180 * @return None
181 *
182 * @details This function reset specified smartcard module to its default state for activate smartcard.
183 */
SC_ResetReader(SC_T * sc)184 void SC_ResetReader(SC_T *sc)
185 {
186 uint32_t u32Intf, u32TimeOutCount;
187
188 if(sc == SC0)
189 {
190 u32Intf = 0UL;
191 }
192 else if(sc == SC1)
193 {
194 u32Intf = 1UL;
195 }
196 else
197 {
198 u32Intf = 2UL;
199 }
200
201 /* Reset FIFO, enable auto de-activation while card removal */
202 sc->ALTCTL |= (SC_ALTCTL_TXRST_Msk | SC_ALTCTL_RXRST_Msk | SC_ALTCTL_ADACEN_Msk);
203 /* Set Rx trigger level to 1 character, longest card detect debounce period, disable error retry (EMV ATR does not use error retry) */
204 u32TimeOutCount = SC_TIMEOUT;
205 while((sc->CTL & SC_CTL_SYNC_Msk) == SC_CTL_SYNC_Msk)
206 {
207 if(--u32TimeOutCount == 0) break;
208 }
209 sc->CTL &= ~(SC_CTL_RXTRGLV_Msk |
210 SC_CTL_CDDBSEL_Msk |
211 SC_CTL_TXRTY_Msk |
212 SC_CTL_TXRTYEN_Msk |
213 SC_CTL_RXRTY_Msk |
214 SC_CTL_RXRTYEN_Msk);
215 u32TimeOutCount = SC_TIMEOUT;
216 while((sc->CTL & SC_CTL_SYNC_Msk) == SC_CTL_SYNC_Msk)
217 {
218 if(--u32TimeOutCount == 0) break;
219 }
220 /* Enable auto convention, and all three smartcard internal timers */
221 sc->CTL |= SC_CTL_AUTOCEN_Msk | SC_CTL_TMRSEL_Msk;
222 /* Disable Rx timeout */
223 sc->RXTOUT = 0UL;
224 /* 372 clocks per ETU by default */
225 sc->ETUCTL = 371UL;
226
227 /* Enable necessary interrupt for smartcard operation */
228 if(g_u32CardStateIgnore[u32Intf]) /* Do not enable card detect interrupt if card present state ignore */
229 {
230 sc->INTEN = (SC_INTEN_RDAIEN_Msk |
231 SC_INTEN_TERRIEN_Msk |
232 SC_INTEN_TMR0IEN_Msk |
233 SC_INTEN_TMR1IEN_Msk |
234 SC_INTEN_TMR2IEN_Msk |
235 SC_INTEN_BGTIEN_Msk |
236 SC_INTEN_ACERRIEN_Msk);
237 }
238 else
239 {
240 sc->INTEN = (SC_INTEN_RDAIEN_Msk |
241 SC_INTEN_TERRIEN_Msk |
242 SC_INTEN_TMR0IEN_Msk |
243 SC_INTEN_TMR1IEN_Msk |
244 SC_INTEN_TMR2IEN_Msk |
245 SC_INTEN_BGTIEN_Msk |
246 SC_INTEN_ACERRIEN_Msk |
247 SC_INTEN_CDIEN_Msk);
248 }
249 }
250
251 /**
252 * @brief Set Block Guard Time (BGT)
253 *
254 * @param[in] sc The pointer of smartcard module.
255 * @param[in] u32BGT Block guard time using ETU as unit, valid range are between 1 ~ 32.
256 *
257 * @return None
258 *
259 * @details This function is used to configure block guard time (BGT) of specified smartcard module.
260 */
SC_SetBlockGuardTime(SC_T * sc,uint32_t u32BGT)261 void SC_SetBlockGuardTime(SC_T *sc, uint32_t u32BGT)
262 {
263 sc->CTL = (sc->CTL & ~SC_CTL_BGT_Msk) | ((u32BGT - 1UL) << SC_CTL_BGT_Pos);
264 }
265
266 /**
267 * @brief Set Character Guard Time (CGT)
268 *
269 * @param[in] sc The pointer of smartcard module.
270 * @param[in] u32CGT Character guard time using ETU as unit, valid range are between 11 ~ 267.
271 *
272 * @return None
273 *
274 * @details This function is used to configure character guard time (CGT) of specified smartcard module.
275 * @note Before using this API, user should set the correct stop bit length first.
276 */
SC_SetCharGuardTime(SC_T * sc,uint32_t u32CGT)277 void SC_SetCharGuardTime(SC_T *sc, uint32_t u32CGT)
278 {
279 /* CGT is "START bit" + "8-bits" + "Parity bit" + "STOP bit(s)" + "EGT counts" */
280 u32CGT -= ((sc->CTL & SC_CTL_NSB_Msk) == SC_CTL_NSB_Msk) ? 11UL : 12UL;
281 sc->EGT = u32CGT;
282 }
283
284 /**
285 * @brief Stop all smartcard timer
286 *
287 * @param[in] sc The pointer of smartcard module.
288 *
289 * @return None
290 *
291 * @note This function stop the timers within specified smartcard module, \b not timer module.
292 */
SC_StopAllTimer(SC_T * sc)293 void SC_StopAllTimer(SC_T *sc)
294 {
295 uint32_t u32TimeOutCount = SC_TIMEOUT;
296
297 while((sc->ALTCTL & SC_ALTCTL_SYNC_Msk) == SC_ALTCTL_SYNC_Msk)
298 {
299 if(--u32TimeOutCount == 0) break;
300 }
301 sc->ALTCTL &= ~(SC_ALTCTL_CNTEN0_Msk | SC_ALTCTL_CNTEN1_Msk | SC_ALTCTL_CNTEN2_Msk);
302 }
303
304 /**
305 * @brief Configure and start smartcard timer
306 *
307 * @param[in] sc The pointer of smartcard module.
308 * @param[in] u32TimerNum Timer to start. Valid values are 0, 1, 2.
309 * @param[in] u32Mode Timer operating mode, valid values are:
310 * - \ref SC_TMR_MODE_0
311 * - \ref SC_TMR_MODE_1
312 * - \ref SC_TMR_MODE_2
313 * - \ref SC_TMR_MODE_3
314 * - \ref SC_TMR_MODE_4
315 * - \ref SC_TMR_MODE_5
316 * - \ref SC_TMR_MODE_6
317 * - \ref SC_TMR_MODE_7
318 * - \ref SC_TMR_MODE_8
319 * - \ref SC_TMR_MODE_F
320 * @param[in] u32ETUCount Timer timeout duration, ETU based. For timer 0, valid range are between 1 ~ 0x1000000 ETUs.
321 * For timer 1 and timer 2, valid range are between 1 ~ 0x100 ETUs.
322 *
323 * @return None
324 *
325 * @note This function start the timer within specified smartcard module, \b not timer module.
326 * @note Depend on the timer operating mode, timer may not start counting immediately and starts when condition match.
327 */
SC_StartTimer(SC_T * sc,uint32_t u32TimerNum,uint32_t u32Mode,uint32_t u32ETUCount)328 void SC_StartTimer(SC_T *sc, uint32_t u32TimerNum, uint32_t u32Mode, uint32_t u32ETUCount)
329 {
330 uint32_t u32Reg = u32Mode | (SC_TMRCTL0_CNT_Msk & (u32ETUCount - 1UL));
331 uint32_t u32TimeOutCount = 0UL;
332
333 u32TimeOutCount = SC_TIMEOUT;
334 while((sc->ALTCTL & SC_ALTCTL_SYNC_Msk) == SC_ALTCTL_SYNC_Msk)
335 {
336 if(--u32TimeOutCount == 0UL) break;
337 }
338 if(u32TimerNum == 0UL)
339 {
340 u32TimeOutCount = SC_TIMEOUT;
341 while((sc->TMRCTL0 & SC_TMRCTL0_SYNC_Msk) == SC_TMRCTL0_SYNC_Msk)
342 {
343 if(--u32TimeOutCount == 0UL) break;
344 }
345 sc->TMRCTL0 = u32Reg;
346 sc->ALTCTL |= SC_ALTCTL_CNTEN0_Msk;
347 }
348 else if(u32TimerNum == 1UL)
349 {
350 u32TimeOutCount = SC_TIMEOUT;
351 while((sc->TMRCTL1 & SC_TMRCTL1_SYNC_Msk) == SC_TMRCTL1_SYNC_Msk)
352 {
353 if(--u32TimeOutCount == 0UL) break;
354 }
355 sc->TMRCTL1 = u32Reg;
356 sc->ALTCTL |= SC_ALTCTL_CNTEN1_Msk;
357 }
358 else /* timer 2 */
359 {
360 u32TimeOutCount = SC_TIMEOUT;
361 while((sc->TMRCTL2 & SC_TMRCTL2_SYNC_Msk) == SC_TMRCTL2_SYNC_Msk)
362 {
363 if(--u32TimeOutCount == 0UL) break;
364 }
365 sc->TMRCTL2 = u32Reg;
366 sc->ALTCTL |= SC_ALTCTL_CNTEN2_Msk;
367 }
368 }
369
370 /**
371 * @brief Stop a smartcard timer
372 *
373 * @param[in] sc The pointer of smartcard module.
374 * @param[in] u32TimerNum Timer to stop. Valid values are 0, 1, 2.
375 *
376 * @return None
377 *
378 * @note This function stop the timer within specified smartcard module, \b not timer module.
379 */
SC_StopTimer(SC_T * sc,uint32_t u32TimerNum)380 void SC_StopTimer(SC_T *sc, uint32_t u32TimerNum)
381 {
382 uint32_t u32TimeOutCount = SC_TIMEOUT;
383
384 while(sc->ALTCTL & SC_ALTCTL_SYNC_Msk)
385 {
386 if(--u32TimeOutCount == 0UL) break;
387 }
388
389 if(u32TimerNum == 0UL) /* timer 0 */
390 {
391 sc->ALTCTL &= ~SC_ALTCTL_CNTEN0_Msk;
392 }
393 else if(u32TimerNum == 1UL) /* timer 1 */
394 {
395 sc->ALTCTL &= ~SC_ALTCTL_CNTEN1_Msk;
396 }
397 else /* timer 2 */
398 {
399 sc->ALTCTL &= ~SC_ALTCTL_CNTEN2_Msk;
400 }
401 }
402
403 /**
404 * @brief Get smartcard clock frequency
405 *
406 * @param[in] sc The pointer of smartcard module.
407 *
408 * @return Smartcard frequency in kHZ
409 *
410 * @details This function is used to get specified smartcard module clock frequency in kHz.
411 */
SC_GetInterfaceClock(SC_T * sc)412 uint32_t SC_GetInterfaceClock(SC_T *sc)
413 {
414 uint32_t u32ClkSrc = 0, u32Num = 0, u32ClkFreq = __HIRC, u32Div = 0;
415
416 /* Get smartcard module clock source and divider */
417 if(sc == SC0)
418 {
419 u32Num = 0UL;
420 u32ClkSrc = CLK_GetModuleClockSource(SC0_MODULE);
421 u32Div = CLK_GetModuleClockDivider(SC0_MODULE);
422 }
423 else if(sc == SC1)
424 {
425 u32Num = 1UL;
426 u32ClkSrc = CLK_GetModuleClockSource(SC1_MODULE);
427 u32Div = CLK_GetModuleClockDivider(SC1_MODULE);
428 }
429 else if(sc == SC2)
430 {
431 u32Num = 2UL;
432 u32ClkSrc = CLK_GetModuleClockSource(SC2_MODULE);
433 u32Div = CLK_GetModuleClockDivider(SC2_MODULE);
434 }
435 else
436 {
437 u32ClkFreq = 0UL;
438 }
439
440 if(u32ClkFreq != 0UL)
441 {
442 /* Get smartcard module clock */
443 if(u32ClkSrc == 0UL)
444 {
445 u32ClkFreq = __HXT;
446 }
447 else if(u32ClkSrc == 1UL)
448 {
449 u32ClkFreq = CLK_GetPLLClockFreq();
450 }
451 else if(u32ClkSrc == 2UL)
452 {
453 if(u32Num == 1UL)
454 {
455 u32ClkFreq = CLK_GetPCLK1Freq();
456 }
457 else
458 {
459 u32ClkFreq = CLK_GetPCLK0Freq();
460 }
461 }
462 else
463 {
464 u32ClkFreq = __HIRC;
465 }
466
467 u32ClkFreq /= (u32Div + 1UL) * 1000UL;
468 }
469
470 return u32ClkFreq;
471 }
472
473 /**@}*/ /* end of group SC_EXPORTED_FUNCTIONS */
474
475 /**@}*/ /* end of group SC_Driver */
476
477 /**@}*/ /* end of group Standard_Driver */
478