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