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