1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-07-15 Emuzit first version
9 */
10 #include <rthw.h>
11 #include <drivers/hwtimer.h>
12 #include "ch56x_sys.h"
13 #include "ch56x_timer.h"
14 #include "isr_sp.h"
15
16 #if !defined(BSP_USING_TMR0) && !defined(BSP_USING_TMR1) && !defined(BSP_USING_TMR2)
17 #error "Please define at least one TMRx"
18 #endif
19
20 struct hwtimer_device
21 {
22 struct rt_hwtimer_device parent;
23 struct rt_hwtimer_info hwtimer_info;
24 volatile struct timer_registers *reg_base;
25 rt_hwtimer_mode_t tmode;
26 irq_number_t irqn;
27 char *name;
28 };
29
30 #ifdef BSP_USING_TMR0
31 static struct hwtimer_device hwtimer_device_0 =
32 {
33 .hwtimer_info =
34 {
35 .maxfreq = 80000000,
36 .minfreq = 80000000,
37 .maxcnt = 0x3ffffff,
38 .cntmode = HWTIMER_CNTMODE_UP,
39 },
40 .reg_base = (struct timer_registers *)TMR0_REG_BASE,
41 .tmode = HWTIMER_MODE_PERIOD,
42 .irqn = TMR0_IRQn,
43 .name = "timer0",
44 };
45 #endif
46
47 #ifdef BSP_USING_TMR1
48 static struct hwtimer_device hwtimer_device_1 =
49 {
50 .hwtimer_info =
51 {
52 .maxfreq = 80000000,
53 .minfreq = 80000000,
54 .maxcnt = 0x3ffffff,
55 .cntmode = HWTIMER_CNTMODE_UP,
56 },
57 .reg_base = (struct timer_registers *)TMR1_REG_BASE,
58 .tmode = HWTIMER_MODE_PERIOD,
59 .irqn = TMR1_IRQn,
60 .name = "timer1",
61 };
62 #endif
63
64 #ifdef BSP_USING_TMR2
65 static struct hwtimer_device hwtimer_device_2 =
66 {
67 .hwtimer_info =
68 {
69 .maxfreq = 80000000,
70 .minfreq = 80000000,
71 .maxcnt = 0x3ffffff,
72 .cntmode = HWTIMER_CNTMODE_UP,
73 },
74 .reg_base = (struct timer_registers *)TMR2_REG_BASE,
75 .tmode = HWTIMER_MODE_PERIOD,
76 .irqn = TMR2_IRQn,
77 .name = "timer2",
78 };
79 #endif
80
81 static void hwtimer_stop(struct rt_hwtimer_device *timer);
82
hwtimer_init(struct rt_hwtimer_device * timer,uint32_t state)83 static void hwtimer_init(struct rt_hwtimer_device *timer, uint32_t state)
84 {
85 struct hwtimer_device *hwtimer_device = (void *)timer;
86
87 RT_ASSERT(hwtimer_device != RT_NULL);
88
89 /* no resource processing, `state` ignored */
90 hwtimer_stop(timer);
91
92 if (hwtimer_device->irqn != TMR0_IRQn)
93 {
94 hwtimer_device->reg_base->CTRL_DMA.reg = 0;
95 }
96 }
97
hwtimer_start(struct rt_hwtimer_device * timer,uint32_t cnt,rt_hwtimer_mode_t mode)98 static rt_err_t hwtimer_start(struct rt_hwtimer_device *timer, uint32_t cnt, rt_hwtimer_mode_t mode)
99 {
100 struct hwtimer_device *hwtimer_device = (void *)timer;
101 volatile struct timer_registers *txreg;
102
103 RT_ASSERT(hwtimer_device != RT_NULL);
104
105 /* hwtimer_device->tmode may be different from timer->mode.
106 * For multi-cycle ONESHOT, tmode is set to PERIOD at hwtimer_start.
107 */
108 hwtimer_device->tmode = mode;
109
110 sys_clk_off_by_irqn(hwtimer_device->irqn, SYS_SLP_CLK_ON);
111 txreg = hwtimer_device->reg_base;
112 txreg->CNT_END = cnt;
113 txreg->CTRL_MOD.reg = RB_TMR_ALL_CLEAR;
114 txreg->CTRL_MOD.reg = RB_TMR_COUNT_EN;
115 txreg->INTER_EN.cyc_end = 1;
116 rt_hw_interrupt_umask(hwtimer_device->irqn);
117
118 return RT_EOK;
119 }
120
hwtimer_stop(struct rt_hwtimer_device * timer)121 static void hwtimer_stop(struct rt_hwtimer_device *timer)
122 {
123 struct hwtimer_device *hwtimer_device = (void *)timer;
124 volatile struct timer_registers *txreg;
125
126 RT_ASSERT(hwtimer_device != RT_NULL);
127
128 rt_hw_interrupt_mask(hwtimer_device->irqn);
129 /* note: RB_TMR_COUNT_EN cleared */
130 txreg = hwtimer_device->reg_base;
131 txreg->CTRL_MOD.reg = RB_TMR_ALL_CLEAR;
132 txreg->INTER_EN.reg = 0;
133 sys_clk_off_by_irqn(hwtimer_device->irqn, SYS_SLP_CLK_OFF);
134 }
135
hwtimer_count_get(struct rt_hwtimer_device * timer)136 static uint32_t hwtimer_count_get(struct rt_hwtimer_device *timer)
137 {
138 struct hwtimer_device *hwtimer_device = (void *)timer;
139
140 RT_ASSERT(hwtimer_device != RT_NULL);
141
142 return hwtimer_device->reg_base->COUNT;
143 }
144
hwtimer_control(struct rt_hwtimer_device * timer,uint32_t cmd,void * args)145 static rt_err_t hwtimer_control(
146 struct rt_hwtimer_device *timer, uint32_t cmd, void *args)
147 {
148 struct hwtimer_device *hwtimer_device = (void *)timer;
149 rt_err_t result = RT_EOK;
150
151 RT_ASSERT(hwtimer_device != RT_NULL);
152
153 switch (cmd)
154 {
155 case HWTIMER_CTRL_FREQ_SET:
156 /* clocking for ch56x timers are fixed to Fsys */
157 if (args == RT_NULL || *(uint32_t *)args != timer->info->minfreq)
158 {
159 result = -RT_EINVAL;
160 }
161 break;
162
163 case HWTIMER_CTRL_STOP:
164 case HWTIMER_CTRL_INFO_GET:
165 case HWTIMER_CTRL_MODE_SET:
166 default:
167 result = -RT_ENOSYS;
168 }
169
170 return result;
171 }
172
173 static const struct rt_hwtimer_ops hwtimer_ops =
174 {
175 .init = hwtimer_init,
176 .start = hwtimer_start,
177 .stop = hwtimer_stop,
178 .count_get = hwtimer_count_get,
179 .control = hwtimer_control,
180 };
181
rt_hw_hwtimer_init(void)182 static int rt_hw_hwtimer_init(void)
183 {
184 struct hwtimer_device *devices[3];
185
186 uint32_t Fsys = sys_hclk_get();
187
188 int n = 0;
189
190 #ifdef BSP_USING_TMR2
191 devices[n++] = &hwtimer_device_2;
192 #endif
193 #ifdef BSP_USING_TMR1
194 devices[n++] = &hwtimer_device_1;
195 #endif
196 #ifdef BSP_USING_TMR0
197 devices[n++] = &hwtimer_device_0;
198 #endif
199
200 while (--n >= 0)
201 {
202 struct hwtimer_device *hwtimer_device = devices[n];
203 /* counting frequency is fixed to Fsys */
204 hwtimer_device->hwtimer_info.maxfreq = Fsys;
205 hwtimer_device->hwtimer_info.minfreq = Fsys;
206 hwtimer_device->parent.info = &hwtimer_device->hwtimer_info;
207 hwtimer_device->parent.ops = &hwtimer_ops;
208 rt_device_hwtimer_register(
209 &hwtimer_device->parent, hwtimer_device->name, RT_NULL);
210 }
211 return RT_EOK;
212 }
213 INIT_DEVICE_EXPORT(rt_hw_hwtimer_init);
214
_hwtimer_isr_common(struct hwtimer_device * hwtimer_device)215 static void _hwtimer_isr_common(struct hwtimer_device *hwtimer_device)
216 {
217 volatile struct timer_registers *txreg = hwtimer_device->reg_base;
218
219 if (txreg->INT_FLAG.cyc_end)
220 {
221 if (hwtimer_device->tmode == HWTIMER_MODE_ONESHOT)
222 {
223 /* disable timer to emulate oneshot */
224 txreg->CTRL_MOD.reg = 0;
225 }
226 rt_device_hwtimer_isr(&hwtimer_device->parent);
227 txreg->INT_FLAG.cyc_end = 1;
228 }
229 }
230
231 #ifdef BSP_USING_TMR0
232 void tmr0_irq_handler(void) __attribute__((interrupt()));
tmr0_irq_handler(void)233 void tmr0_irq_handler(void)
234 {
235 isr_sp_enter();
236 rt_interrupt_enter();
237 _hwtimer_isr_common(&hwtimer_device_0);
238 rt_interrupt_leave();
239 isr_sp_leave();
240 }
241 #endif
242
243 #ifdef BSP_USING_TMR1
244 void tmr1_irq_handler(void) __attribute__((interrupt()));
tmr1_irq_handler(void)245 void tmr1_irq_handler(void)
246 {
247 isr_sp_enter();
248 rt_interrupt_enter();
249 _hwtimer_isr_common(&hwtimer_device_1);
250 rt_interrupt_leave();
251 isr_sp_leave();
252 }
253 #endif
254
255 #ifdef BSP_USING_TMR2
256 void tmr2_irq_handler(void) __attribute__((interrupt()));
tmr2_irq_handler(void)257 void tmr2_irq_handler(void)
258 {
259 isr_sp_enter();
260 rt_interrupt_enter();
261 _hwtimer_isr_common(&hwtimer_device_2);
262 rt_interrupt_leave();
263 isr_sp_leave();
264 }
265 #endif
266