1 /**************************************************************************//**
2 *
3 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Change Logs:
8 * Date            Author           Notes
9 * 2020-12-3       Wayne            First version
10 *
11 ******************************************************************************/
12 
13 #include <rtconfig.h>
14 
15 #if defined(BSP_USING_TIMER) && defined(RT_USING_HWTIMER)
16 
17 #include <rtdevice.h>
18 #include "NuMicro.h"
19 #include <drv_sys.h>
20 #include "nu_timer.h"
21 
22 /* Private define ---------------------------------------------------------------*/
23 #define NU_TIMER_DEVICE(timer) (nu_timer_t)(timer)
24 
25 enum
26 {
27     TIMER_START = -1,
28 #if defined(BSP_USING_TIMER0)
29     TIMER0_IDX,
30 #endif
31 #if defined(BSP_USING_TIMER1)
32     TIMER1_IDX,
33 #endif
34 #if defined(BSP_USING_TIMER2)
35     TIMER2_IDX,
36 #endif
37 #if defined(BSP_USING_TIMER3)
38     TIMER3_IDX,
39 #endif
40     /* BSP_USING_TIMER4 is reserved for Systick usage. */
41     TIMER_CNT
42 };
43 
44 /* Private typedef --------------------------------------------------------------*/
45 struct nu_timer
46 {
47     rt_hwtimer_t  parent;
48     char         *name;
49     uint32_t      idx;
50     IRQn_Type     irqn;
51     E_SYS_IPRST   rstidx;
52     E_SYS_IPCLK   clkidx;
53 };
54 typedef struct nu_timer *nu_timer_t;
55 
56 /* Private functions ------------------------------------------------------------*/
57 static void nu_timer_init(rt_hwtimer_t *timer, rt_uint32_t state);
58 static rt_err_t nu_timer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t opmode);
59 static void nu_timer_stop(rt_hwtimer_t *timer);
60 static rt_uint32_t nu_timer_count_get(rt_hwtimer_t *timer);
61 static rt_err_t nu_timer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args);
62 
63 /* Public functions -------------------------------------------------------------*/
64 
65 
66 /* Private variables ------------------------------------------------------------*/
67 static struct nu_timer nu_timer_arr [] =
68 {
69 #if defined(BSP_USING_TIMER0)
70     {
71         .name = "timer0",
72         .idx  = 0,
73         .irqn = IRQ_TMR0,
74         .rstidx = TIMER0RST,
75         .clkidx = TIMER0CKEN,
76     },
77 #endif
78 #if defined(BSP_USING_TIMER1)
79     {
80         .name = "timer1",
81         .idx  = 1,
82         .irqn = IRQ_TMR1,
83         .rstidx = TIMER1RST,
84         .clkidx = TIMER1CKEN,
85     },
86 #endif
87 #if defined(BSP_USING_TIMER2)
88     {
89         .name = "timer2",
90         .idx  = 2,
91         .irqn = IRQ_TMR2,
92         .rstidx = TIMER2RST,
93         .clkidx = TIMER2CKEN,
94     },
95 #endif
96 #if defined(BSP_USING_TIMER3)
97     {
98         .name = "timer3",
99         .idx  = 3,
100         .irqn = IRQ_TMR3,
101         .rstidx = TIMER3RST,
102         .clkidx = TIMER3CKEN,
103     },
104 #endif
105     /* BSP_USING_TIMER4 is reserved for Systick usage. */
106 };
107 
108 static struct rt_hwtimer_info nu_timer_info =
109 {
110     12000000,            /* maximum count frequency */
111     46875,               /* minimum count frequency */
112     0xFFFFFF,            /* the maximum counter value */
113     HWTIMER_CNTMODE_UP,  /* Increment or Decreasing count mode */
114 };
115 
116 static struct rt_hwtimer_ops nu_timer_ops =
117 {
118     nu_timer_init,
119     nu_timer_start,
120     nu_timer_stop,
121     nu_timer_count_get,
122     nu_timer_control
123 };
124 
125 /* Functions define ------------------------------------------------------------*/
nu_timer_init(rt_hwtimer_t * timer,rt_uint32_t state)126 static void nu_timer_init(rt_hwtimer_t *timer, rt_uint32_t state)
127 {
128     nu_timer_t psNuTmr = NU_TIMER_DEVICE(timer);
129     RT_ASSERT(psNuTmr != RT_NULL);
130 
131     if (1 == state)
132     {
133         uint32_t timer_clk;
134         struct rt_hwtimer_info *info = &nu_timer_info;
135 
136         timer_clk = TIMER_GetModuleClock(psNuTmr->idx);
137         info->maxfreq = timer_clk;
138         info->minfreq = timer_clk / 256;
139         TIMER_Open(psNuTmr->idx, TIMER_ONESHOT_MODE, 1);
140         TIMER_EnableInt(psNuTmr->idx);
141         rt_hw_interrupt_umask(psNuTmr->irqn);
142     }
143     else
144     {
145         rt_hw_interrupt_mask(psNuTmr->irqn);
146         TIMER_DisableInt(psNuTmr->idx);
147         TIMER_Close(psNuTmr->idx);
148     }
149 }
150 
nu_timer_start(rt_hwtimer_t * timer,rt_uint32_t cnt,rt_hwtimer_mode_t opmode)151 static rt_err_t nu_timer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t opmode)
152 {
153     rt_err_t ret = -RT_EINVAL;
154     rt_uint32_t u32OpMode;
155 
156     nu_timer_t psNuTmr = NU_TIMER_DEVICE(timer);
157     RT_ASSERT(psNuTmr != RT_NULL);
158 
159     if (cnt <= 1 || cnt > 0xFFFFFF)
160     {
161         goto exit_nu_timer_start;
162     }
163 
164     switch (opmode)
165     {
166     case HWTIMER_MODE_PERIOD:
167         u32OpMode = TIMER_PERIODIC_MODE;
168         break;
169 
170     case HWTIMER_MODE_ONESHOT:
171         u32OpMode = TIMER_ONESHOT_MODE;
172         break;
173 
174     default:
175         goto exit_nu_timer_start;
176     }
177 
178     TIMER_SET_CMP_VALUE(psNuTmr->idx, cnt);
179     TIMER_SET_OPMODE(psNuTmr->idx, u32OpMode);
180     TIMER_EnableInt(psNuTmr->idx);
181     rt_hw_interrupt_umask(psNuTmr->irqn);
182 
183     TIMER_Start(psNuTmr->idx);
184 
185     ret = RT_EOK;
186 
187 exit_nu_timer_start:
188 
189     return -(ret);
190 }
191 
nu_timer_stop(rt_hwtimer_t * timer)192 static void nu_timer_stop(rt_hwtimer_t *timer)
193 {
194     nu_timer_t psNuTmr = NU_TIMER_DEVICE(timer);
195     RT_ASSERT(psNuTmr != RT_NULL);
196 
197     rt_hw_interrupt_mask(psNuTmr->irqn);
198     TIMER_DisableInt(psNuTmr->idx);
199     TIMER_Stop(psNuTmr->idx);
200     TIMER_ClearCounter(psNuTmr->idx);
201 }
202 
nu_timer_count_get(rt_hwtimer_t * timer)203 static rt_uint32_t nu_timer_count_get(rt_hwtimer_t *timer)
204 {
205     nu_timer_t psNuTmr = NU_TIMER_DEVICE(timer);
206     RT_ASSERT(psNuTmr != RT_NULL);
207 
208     return TIMER_GetCounter(psNuTmr->idx);
209 }
210 
nu_timer_control(rt_hwtimer_t * timer,rt_uint32_t cmd,void * args)211 static rt_err_t nu_timer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args)
212 {
213     rt_err_t ret = RT_EOK;
214     nu_timer_t psNuTmr = NU_TIMER_DEVICE(timer);
215     RT_ASSERT(psNuTmr != RT_NULL);
216 
217     switch (cmd)
218     {
219     case HWTIMER_CTRL_FREQ_SET:
220     {
221         uint32_t clk;
222         uint32_t pre;
223 
224         clk = TIMER_GetModuleClock(psNuTmr->idx);
225         pre = clk / *((uint32_t *)args) - 1;
226         TIMER_SET_PRESCALE_VALUE(psNuTmr->idx, pre);
227         *((uint32_t *)args) = clk / (pre + 1) ;
228     }
229     break;
230 
231     case HWTIMER_CTRL_STOP:
232         TIMER_Stop(psNuTmr->idx);
233         break;
234 
235     default:
236         ret = -RT_EINVAL;
237         break;
238     }
239 
240     return -(ret);
241 }
242 
243 /**
244  * All UART interrupt service routine
245  */
nu_timer_isr(int vector,void * param)246 static void nu_timer_isr(int vector, void *param)
247 {
248     nu_timer_t psNuTmr = NU_TIMER_DEVICE(param);
249     RT_ASSERT(psNuTmr != RT_NULL);
250 
251     if (TIMER_GetIntFlag(psNuTmr->idx))
252     {
253         TIMER_ClearIntFlag(psNuTmr->idx);
254         rt_device_hwtimer_isr(&psNuTmr->parent);
255     }
256 }
257 
rt_hw_timer_init(void)258 int rt_hw_timer_init(void)
259 {
260     int i;
261     rt_err_t ret = RT_EOK;
262     for (i = (TIMER_START + 1); i < TIMER_CNT; i++)
263     {
264         nu_sys_ipclk_enable(nu_timer_arr[i].clkidx);
265 
266         nu_sys_ip_reset(nu_timer_arr[i].rstidx);
267 
268         /* Register Etimer information. */
269         nu_timer_arr[i].parent.info = &nu_timer_info;
270 
271         /* Register Etimer operation. */
272         nu_timer_arr[i].parent.ops = &nu_timer_ops;
273 
274         /* Register Etimer interrupt service routine. */
275         rt_hw_interrupt_install(nu_timer_arr[i].irqn, nu_timer_isr, &nu_timer_arr[i], nu_timer_arr[i].name);
276 
277         /* Register RT hwtimer device. */
278         ret = rt_device_hwtimer_register(&nu_timer_arr[i].parent, nu_timer_arr[i].name, &nu_timer_arr[i]);
279         RT_ASSERT(ret == RT_EOK);
280     }
281     return 0;
282 }
283 INIT_BOARD_EXPORT(rt_hw_timer_init);
284 
285 #endif //#if defined(BSP_USING_TIMER) && defined(RT_USING_HWTIMER)
286