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  * 2023-04-01       wcx1024979076    first version
9  */
10 
11 #include "drv_hwtimer.h"
12 #include <rtthread.h>
13 #include <rtdevice.h>
14 
15 #ifdef BSP_USING_HWTIMER
16 
17 #define DBG_LEVEL   DBG_LOG
18 #include <rtdbg.h>
19 #define LOG_TAG "DRV.HWTIMER"
20 
21 
22 typedef struct _gptimer
23 {
24     const char *name;
25     rt_hwtimer_t timer;
26     struct bflb_device_s *bflb_timer;
27 } _gptimer_t;
28 
29 static void _hwtimer_init(rt_hwtimer_t *timer, rt_uint32_t state);
30 static rt_err_t _hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode);
31 static void _hwtimer_stop(rt_hwtimer_t *timer);
32 static rt_uint32_t _hwtimer_count_get(rt_hwtimer_t *timer);
33 static rt_err_t _hwtimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args);
34 
35 static void _hwtmr_isr(_gptimer_t *gptmr);
36 
37 static const struct rt_hwtimer_ops _hwtimer_ops = {
38     .init = _hwtimer_init,
39     .start = _hwtimer_start,
40     .stop = _hwtimer_stop,
41     .count_get = _hwtimer_count_get,
42     .control = _hwtimer_control
43 };
44 
45 static const struct rt_hwtimer_info _hwtimer_info = {
46     .maxfreq = 1000000UL,
47     .minfreq = 1000000UL,
48     .maxcnt = 0xFFFFFFFFUL,
49     .cntmode = HWTIMER_MODE_PERIOD
50 };
51 
52 #ifdef BSP_USING_TIMER0
53 static _gptimer_t timer0 = {.name = "timer0"};
54 #endif /* BSP_USING_TIMER0 */
55 #ifdef BSP_USING_TIMER1
56 static _gptimer_t timer1 = {.name = "timer1" };
57 #endif /* BSP_USING_TIMER1 */
58 
59 static _gptimer_t *s_gptimers[] = {
60 #ifdef BSP_USING_TIMER0
61        &timer0,
62 #endif  /* BSP_USING_TIMER0 */
63 #ifdef BSP_USING_TIMER1
64        &timer1,
65 #endif /* BSP_USING_TIMER1 */
66     };
67 
68 #ifdef BSP_USING_TIMER0
timer0_isr(int irq,void * arg)69 void timer0_isr(int irq, void *arg)
70 {
71     _hwtmr_isr(&timer0);
72 }
73 #endif  /* BSP_USING_TIMER0 */
74 
75 #ifdef BSP_USING_TIMER1
timer1_isr(int irq,void * arg)76 void timer1_isr(int irq, void *arg)
77 {
78     _hwtmr_isr(&timer1);
79 }
80 #endif  /* BSP_USING_TIMER1 */
81 
_hwtmr_isr(_gptimer_t * timer)82 static void _hwtmr_isr(_gptimer_t *timer)
83 {
84     bool hwtmr_stat = bflb_timer_get_compint_status(timer->bflb_timer, TIMER_COMP_ID_0);
85     if (hwtmr_stat)
86     {
87         rt_device_hwtimer_isr(&timer->timer);
88         bflb_timer_compint_clear(timer->bflb_timer, TIMER_COMP_ID_0);
89     }
90 }
91 
_hwtimer_init(rt_hwtimer_t * timer,rt_uint32_t state)92 static void _hwtimer_init(rt_hwtimer_t *timer, rt_uint32_t state)
93 {
94     _gptimer_t *_gptmr = (_gptimer_t*)timer->parent.user_data;
95 
96     struct bflb_timer_config_s cfg;
97     cfg.counter_mode = TIMER_COUNTER_MODE_PROLOAD;
98     cfg.clock_source = TIMER_CLKSRC_XTAL;
99     cfg.clock_div = 40;
100     cfg.trigger_comp_id = TIMER_COMP_ID_0;
101     cfg.comp0_val = 0;
102     cfg.comp1_val = 0;
103     cfg.comp2_val = 0;
104     cfg.preload_val = 0;
105 
106     bflb_timer_init(_gptmr->bflb_timer, &cfg);
107 }
108 
_hwtimer_start(rt_hwtimer_t * timer,rt_uint32_t cnt,rt_hwtimer_mode_t mode)109 static rt_err_t _hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode)
110 {
111     _gptimer_t *_gptmr = (_gptimer_t*) timer->parent.user_data;
112 
113     struct bflb_timer_config_s cfg;
114     if(mode == HWTIMER_MODE_ONESHOT)
115         cfg.counter_mode = TIMER_COUNTER_MODE_UP;
116     else
117         cfg.counter_mode = TIMER_COUNTER_MODE_PROLOAD;
118     cfg.clock_source = TIMER_CLKSRC_XTAL;
119     cfg.clock_div = 40;
120     cfg.trigger_comp_id = TIMER_COMP_ID_0;
121     cfg.comp0_val = cnt;
122     cfg.comp1_val = cnt;
123     cfg.comp2_val = cnt;
124     cfg.preload_val = 0;
125 
126     bflb_timer_init(_gptmr->bflb_timer, &cfg);
127     bflb_irq_enable(_gptmr->bflb_timer->irq_num);
128     bflb_timer_start(_gptmr->bflb_timer);
129 
130     return RT_EOK;
131 }
132 
_hwtimer_stop(rt_hwtimer_t * timer)133 static void _hwtimer_stop(rt_hwtimer_t *timer)
134 {
135     _gptimer_t *_gptmr = (_gptimer_t*)timer->parent.user_data;
136     bflb_timer_stop(_gptmr->bflb_timer);
137 }
138 
_hwtimer_count_get(rt_hwtimer_t * timer)139 static rt_uint32_t _hwtimer_count_get(rt_hwtimer_t *timer)
140 {
141     _gptimer_t *_gptmr = (_gptimer_t*)timer->parent.user_data;
142 
143     rt_uint32_t current_cnt = bflb_timer_get_countervalue(_gptmr->bflb_timer);
144 
145     return current_cnt;
146 }
147 
_hwtimer_control(rt_hwtimer_t * timer,rt_uint32_t cmd,void * args)148 static rt_err_t _hwtimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args)
149 {
150     rt_err_t err = RT_EOK;
151     _gptimer_t *_gptmr = (_gptimer_t*) timer->parent.user_data;
152     switch (cmd)
153     {
154     case HWTIMER_CTRL_FREQ_SET:
155         err = -RT_ERROR;
156         break;
157     case HWTIMER_CTRL_INFO_GET:
158         *(rt_hwtimer_t*)args = _gptmr->timer;
159         break;
160     case HWTIMER_CTRL_MODE_SET:
161         _gptmr->timer.mode = *(rt_uint32_t*)args;
162         break;
163     case HWTIMER_CTRL_STOP:
164         bflb_timer_stop(_gptmr->bflb_timer);
165         break;
166     }
167 
168     return err;
169 }
170 
171 
rt_hw_hwtimer_init(void)172 int rt_hw_hwtimer_init(void)
173 {
174     int ret = RT_EOK;
175     for (uint32_t i = 0; i < sizeof(s_gptimers) / sizeof(s_gptimers[0]); i++)
176     {
177         s_gptimers[i]->timer.info = &_hwtimer_info;
178         s_gptimers[i]->timer.ops = &_hwtimer_ops;
179         s_gptimers[i]->bflb_timer = bflb_device_get_by_name(s_gptimers[i]->name);
180         ret = rt_device_hwtimer_register(&s_gptimers[i]->timer, s_gptimers[i]->name, s_gptimers[i]);
181         if (ret != RT_EOK)
182         {
183             LOG_E("%s register failed", s_gptimers[i]->name);
184         }
185     }
186 
187 #ifdef BSP_USING_TIMER0
188     bflb_irq_attach(bflb_device_get_by_name("timer0")->irq_num, timer0_isr, NULL);
189 #endif  /* BSP_USING_TIMER0 */
190 
191 #ifdef BSP_USING_TIMER1
192     bflb_irq_attach(bflb_device_get_by_name("timer1")->irq_num, timer1_isr, NULL);
193 #endif  /* BSP_USING_TIMER1 */
194 
195     return ret;
196 }
197 
198 INIT_DEVICE_EXPORT(rt_hw_hwtimer_init);
199 #endif /* BSP_USING_HWTIMER */
200