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