1 /**************************************************************************//**
2  * @file     bmc.c
3  * @version  V3.00
4  * @brief    M460 series BMC 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 /** @addtogroup Standard_Driver Standard Driver
12   @{
13 */
14 
15 /** @addtogroup BMC_Driver BMC Driver
16   @{
17 */
18 
19 
20 /** @addtogroup BMC_EXPORTED_FUNCTIONS BMC Exported Functions
21   @{
22 */
23 
24 /**
25   * @brief      Set the BMC bit clock
26   * @param[in]  u32BitClock The expected frequency of BMC bit clock in Hz
27   * @return     Actual frequency of BMC bit clock
28   * @details    The actual clock rate may be different from the target BMC bit clock rate.
29   *             For example, if the system clock rate is 200 MHz and the target BMC bit clock rate is 3 MHz, the actual BMC bit clock
30   *             rate will be 2 MHz.
31   * \hideinitializer
32   */
BMC_SetBitClock(uint32_t u32BitClock)33 uint32_t BMC_SetBitClock(uint32_t u32BitClock)
34 {
35     uint32_t u32HCLKFreq, u32Div, u32RetValue;
36 
37     /* Get system clock frequency */
38     u32HCLKFreq = CLK_GetHCLKFreq();
39 
40     u32Div = ((u32HCLKFreq * 10UL) / u32BitClock + 5UL) / 10UL; /* Round to the nearest integer */
41 
42     BMC->CTL = (BMC->CTL & (~BMC_CTL_BTDIV_Msk)) | (u32Div << BMC_CTL_BTDIV_Pos);
43 
44     /* Return BMC bit clock rate */
45     u32RetValue = u32HCLKFreq / u32Div;
46 
47     return u32RetValue;
48 }
49 
50 /**
51   * @brief      Get the actual frequency of BMC bit clock
52   * @return     Actual BMC bit frequency in Hz
53   * @details    This API will calculate the actual BMC bit clock rate according to the HBTDIV setting.
54   * \hideinitializer
55   */
BMC_GetBitClock(void)56 uint32_t BMC_GetBitClock(void)
57 {
58     uint32_t u32HCLKFreq, u32Div;
59 
60     /* Get BTDIV setting */
61     u32Div = (BMC->CTL & BMC_CTL_BTDIV_Msk) >> BMC_CTL_BTDIV_Pos;
62 
63     /* Get system clock frequency */
64     u32HCLKFreq = CLK_GetHCLKFreq();
65 
66     /* Return BMC bit clock rate */
67     return (u32HCLKFreq / u32Div);
68 }
69 
70 /**
71   * @brief      Set the dummy delay time period of each group
72   * @param[in]  u32ChGroup BMC channel group selection, valid values are:
73   *                        - \ref BMC_GROUP_0
74   *                        - \ref BMC_GROUP_1
75   *                        - \ref BMC_GROUP_2
76   *                        - \ref BMC_GROUP_3
77   *                        - \ref BMC_GROUP_4
78   *                        - \ref BMC_GROUP_5
79   *                        - \ref BMC_GROUP_6
80   *                        - \ref BMC_GROUP_7
81   * @param[in]  u32DumDelay The expected BMC dummy delay period in microsecond
82   * @return     Actual dummy delay time period in microsecond
83   * @details    This API is used to set each group dummy delay time period.
84   * \hideinitializer
85   */
BMC_SetDummyDelayPeriod(uint32_t u32ChGroup,uint32_t u32DumDelay)86 uint32_t BMC_SetDummyDelayPeriod(uint32_t u32ChGroup, uint32_t u32DumDelay)
87 {
88     uint32_t i, u32BitNum;
89 
90     u32BitNum = ((BMC_GetBitClock() * u32DumDelay) / 1000000UL) / 8UL;
91 
92     for(i = 0UL; i < (uint32_t)BMC_CHANNEL_NUM; i += 4UL)
93     {
94         if((u32ChGroup == i) && (u32ChGroup <= BMC_GROUP_3))
95         {
96             outp8((uint32_t)&(BMC->DNUM0) + (i >> 2UL), u32BitNum);
97             break;
98         }
99         else if((u32ChGroup == i) && (u32ChGroup > BMC_GROUP_3))
100         {
101             outp8((uint32_t)&(BMC->DNUM1) + ((i >> 2UL) - 4UL), u32BitNum);
102             break;
103         }
104     }
105 
106     /* Return BMC dummy delay time period */
107     return (8UL * 1000000UL / BMC_GetBitClock() * u32BitNum);
108 }
109 
110 /**
111   * @brief      Enable interrupt function
112   * @param[in]  u32Mask The combination of all related interrupt enable bits.
113   *                     Each bit corresponds to a interrupt enable bit.
114   *                     This parameter decides which interrupts will be enabled. It is combination of:
115   *                     - \ref BMC_FTXD_INT_MASK
116   *                     - \ref BMC_TXUND_INT_MASK
117   * @return     None
118   * @details    This API is used to enable BMC related interrupts specified by u32Mask parameter.
119   * \hideinitializer
120   */
BMC_EnableInt(uint32_t u32Mask)121 void BMC_EnableInt(uint32_t u32Mask)
122 {
123     /* Enable frame transmit done interrupt flag */
124     if((u32Mask & BMC_FTXD_INT_MASK) == BMC_FTXD_INT_MASK)
125     {
126         BMC->INTEN |= BMC_INTEN_FTXDIEN_Msk;
127     }
128 
129     /* Enable transmit data under run interrupt flag */
130     if((u32Mask & BMC_TXUND_INT_MASK) == BMC_TXUND_INT_MASK)
131     {
132         BMC->INTEN |= BMC_INTEN_TXUNDIEN_Msk;
133     }
134 }
135 
136 /**
137   * @brief      Disable interrupt function
138   * @param[in]  u32Mask The combination of all related interrupt enable bits.
139   *                     Each bit corresponds to a interrupt enable bit.
140   *                     This parameter decides which interrupts will be disabled. It is combination of:
141   *                     - \ref BMC_FTXD_INT_MASK
142   *                     - \ref BMC_TXUND_INT_MASK
143   * @return     None
144   * @details    This API is used to disable BMC related interrupts specified by u32Mask parameter.
145   * \hideinitializer
146   */
BMC_DisableInt(uint32_t u32Mask)147 void BMC_DisableInt(uint32_t u32Mask)
148 {
149     /* Disable frame transmit done interrupt flag */
150     if((u32Mask & BMC_FTXD_INT_MASK) == BMC_FTXD_INT_MASK)
151     {
152         BMC->INTEN &= ~BMC_INTEN_FTXDIEN_Msk;
153     }
154 
155     /* Disable transmit data under run interrupt flag */
156     if((u32Mask & BMC_TXUND_INT_MASK) == BMC_TXUND_INT_MASK)
157     {
158         BMC->INTEN &= ~BMC_INTEN_TXUNDIEN_Msk;
159     }
160 }
161 
162 /**
163   * @brief      Get interrupt flag
164   * @param[in]  u32Mask The combination of all related interrupt sources.
165   *                     Each bit corresponds to a interrupt source.
166   *                     This parameter decides which interrupt flags will be read. It is combination of:
167   *                     - \ref BMC_FTXD_INT_MASK
168   *                     - \ref BMC_TXUND_INT_MASK
169   * @return     Interrupt flags of selected sources
170   * @details    This API is used to get BMC related interrupt flags specified by u32Mask parameter.
171   * \hideinitializer
172   */
BMC_GetIntFlag(uint32_t u32Mask)173 uint32_t BMC_GetIntFlag(uint32_t u32Mask)
174 {
175     uint32_t u32IntStatus;
176     uint32_t u32IntFlag = 0UL;
177 
178     u32IntStatus = BMC->INTSTS;
179 
180     /* Check frame transmit done interrupt flag */
181     if((u32Mask & BMC_FTXD_INT_MASK) && (u32IntStatus & BMC_INTSTS_FTXDIF_Msk))
182     {
183         u32IntFlag |= BMC_FTXD_INT_MASK;
184     }
185 
186     /* Check transmit data under run interrupt flag */
187     if((u32Mask & BMC_TXUND_INT_MASK) && (u32IntStatus & BMC_INTSTS_TXUNDIF_Msk))
188     {
189         u32IntFlag |= BMC_TXUND_INT_MASK;
190     }
191 
192     return u32IntFlag;
193 }
194 
195 /**
196   * @brief      Clear interrupt flag
197   * @param[in]  u32Mask The related interrupt source.
198   *                     This parameter decides which interrupt flag will be cleared. Possible option is:
199   *                     - \ref BMC_FTXD_INT_MASK
200   * @return     None
201   * @details    This API is used to clear BMC related interrupt flag specified by u32Mask parameter.
202   * \hideinitializer
203   */
BMC_ClearIntFlag(uint32_t u32Mask)204 void BMC_ClearIntFlag(uint32_t u32Mask)
205 {
206     if(u32Mask & BMC_FTXD_INT_MASK)
207     {
208         BMC->INTSTS = BMC_INTSTS_FTXDIF_Msk; /* Clear frame transmit done interrupt flag */
209     }
210 }
211 
212 /**
213   * @brief      Get BMC status
214   * @param[in]  u32Mask The combination of all related sources.
215   *                     Each bit corresponds to a related source.
216   *                     This parameter decides which flags will be read. It is combination of:
217   *                     - \ref BMC_G0TXUND_MASK
218   *                     - \ref BMC_G1TXUND_MASK
219   *                     - \ref BMC_G2TXUND_MASK
220   *                     - \ref BMC_G3TXUND_MASK
221   *                     - \ref BMC_G4TXUND_MASK
222   *                     - \ref BMC_G5TXUND_MASK
223   *                     - \ref BMC_G6TXUND_MASK
224   *                     - \ref BMC_G7TXUND_MASK
225   * @return     Flags of selected sources
226   * @details    This API is used to get BMC related status specified by u32Mask parameter.
227   * \hideinitializer
228   */
BMC_GetStatus(uint32_t u32Mask)229 uint32_t BMC_GetStatus(uint32_t u32Mask)
230 {
231     uint32_t u32TmpStatus;
232     uint32_t u32Flag = 0UL;
233 
234     u32TmpStatus = BMC->INTSTS;
235 
236     /* Check group 0 transmit data under run status */
237     if((u32Mask & BMC_G0TXUND_MASK) && (u32TmpStatus & BMC_INTSTS_G0TXUND_Msk))
238     {
239         u32Flag |= BMC_G0TXUND_MASK;
240     }
241 
242     /* Check group 1 transmit data under run status */
243     if((u32Mask & BMC_G1TXUND_MASK) && (u32TmpStatus & BMC_INTSTS_G1TXUND_Msk))
244     {
245         u32Flag |= BMC_G1TXUND_MASK;
246     }
247 
248     /* Check group 2 transmit data under run status */
249     if((u32Mask & BMC_G2TXUND_MASK) && (u32TmpStatus & BMC_INTSTS_G2TXUND_Msk))
250     {
251         u32Flag |= BMC_G2TXUND_MASK;
252     }
253 
254     /* Check group 3 transmit data under run status */
255     if((u32Mask & BMC_G3TXUND_MASK) && (u32TmpStatus & BMC_INTSTS_G3TXUND_Msk))
256     {
257         u32Flag |= BMC_G3TXUND_MASK;
258     }
259 
260     /* Check group 4 transmit data under run status */
261     if((u32Mask & BMC_G4TXUND_MASK) && (u32TmpStatus & BMC_INTSTS_G4TXUND_Msk))
262     {
263         u32Flag |= BMC_G4TXUND_MASK;
264     }
265 
266     /* Check group 5 transmit data under run status */
267     if((u32Mask & BMC_G5TXUND_MASK) && (u32TmpStatus & BMC_INTSTS_G5TXUND_Msk))
268     {
269         u32Flag |= BMC_G5TXUND_MASK;
270     }
271 
272     /* Check group 6 transmit data under run status */
273     if((u32Mask & BMC_G6TXUND_MASK) && (u32TmpStatus & BMC_INTSTS_G6TXUND_Msk))
274     {
275         u32Flag |= BMC_G6TXUND_MASK;
276     }
277 
278     /* Check group 7 transmit data under run status */
279     if((u32Mask & BMC_G7TXUND_MASK) && (u32TmpStatus & BMC_INTSTS_G7TXUND_Msk))
280     {
281         u32Flag |= BMC_G7TXUND_MASK;
282     }
283 
284     return u32Flag;
285 }
286 
287 /**
288   * @brief      Clear BMC status
289   * @param[in]  u32Mask The combination of all related sources.
290   *                     Each bit corresponds to a related source.
291   *                     This parameter decides which flags will be cleared. It is combination of:
292   *                     - \ref BMC_G0TXUND_MASK
293   *                     - \ref BMC_G1TXUND_MASK
294   *                     - \ref BMC_G2TXUND_MASK
295   *                     - \ref BMC_G3TXUND_MASK
296   *                     - \ref BMC_G4TXUND_MASK
297   *                     - \ref BMC_G5TXUND_MASK
298   *                     - \ref BMC_G6TXUND_MASK
299   *                     - \ref BMC_G7TXUND_MASK
300   * @return     None
301   * @details    This API is used to clear BMC related status specified by u32Mask parameter.
302   * \hideinitializer
303   */
BMC_ClearStatus(uint32_t u32Mask)304 void BMC_ClearStatus(uint32_t u32Mask)
305 {
306     if(u32Mask & BMC_G0TXUND_MASK)
307     {
308         BMC->INTSTS = BMC_INTSTS_G0TXUND_Msk; /* Check group 0 transmit data under run status */
309     }
310 
311     if(u32Mask & BMC_G1TXUND_MASK)
312     {
313         BMC->INTSTS = BMC_INTSTS_G1TXUND_Msk; /* Check group 1 transmit data under run status */
314     }
315 
316     if(u32Mask & BMC_G2TXUND_MASK)
317     {
318         BMC->INTSTS = BMC_INTSTS_G2TXUND_Msk; /* Check group 2 transmit data under run status */
319     }
320 
321     if(u32Mask & BMC_G3TXUND_MASK)
322     {
323         BMC->INTSTS = BMC_INTSTS_G3TXUND_Msk; /* Check group 3 transmit data under run status */
324     }
325 
326     if(u32Mask & BMC_G4TXUND_MASK)
327     {
328         BMC->INTSTS = BMC_INTSTS_G4TXUND_Msk; /* Check group 4 transmit data under run status */
329     }
330 
331     if(u32Mask & BMC_G5TXUND_MASK)
332     {
333         BMC->INTSTS = BMC_INTSTS_G5TXUND_Msk; /* Check group 5 transmit data under run status */
334     }
335 
336     if(u32Mask & BMC_G6TXUND_MASK)
337     {
338         BMC->INTSTS = BMC_INTSTS_G6TXUND_Msk; /* Check group 6 transmit data under run status */
339     }
340 
341     if(u32Mask & BMC_G7TXUND_MASK)
342     {
343         BMC->INTSTS = BMC_INTSTS_G7TXUND_Msk; /* Check group 7 transmit data under run status */
344     }
345 }
346 
347 
348 /*@}*/ /* end of group BMC_EXPORTED_FUNCTIONS */
349 
350 /*@}*/ /* end of group BMC_Driver */
351 
352 /*@}*/ /* end of group Standard_Driver */
353