1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024-02-21 Yilin Sun Initial revision.
9 */
10
11 #include "drv_hwtimer.h"
12
13 #ifdef BSP_USING_HWTIMER
14
15 #include "fsl_mrt.h"
16
17 typedef struct
18 {
19 rt_hwtimer_t timer_device;
20 mrt_chnl_t channel;
21 char *name;
22 } mcx_hwtimer_obj_t;
23
mcx_hwtimer_mode_set(mcx_hwtimer_obj_t * handle,rt_hwtimer_mode_t mode)24 static inline rt_err_t mcx_hwtimer_mode_set(mcx_hwtimer_obj_t *handle, rt_hwtimer_mode_t mode)
25 {
26 mrt_timer_mode_t mrt_mode;
27 switch (mode)
28 {
29 case HWTIMER_MODE_ONESHOT:
30 mrt_mode = kMRT_OneShotMode;
31 break;
32
33 case HWTIMER_MODE_PERIOD:
34 mrt_mode = kMRT_RepeatMode;
35 break;
36
37 default:
38 return -RT_EINVAL;
39 }
40
41 MRT_SetupChannelMode(MRT0, handle->channel, mrt_mode);
42
43 return RT_EOK;
44 }
45
mcx_hwtimer_init(rt_hwtimer_t * timer,rt_uint32_t state)46 static void mcx_hwtimer_init(rt_hwtimer_t *timer, rt_uint32_t state)
47 {
48 mrt_config_t mrt_config;
49 MRT_GetDefaultConfig(&mrt_config);
50
51 MRT_Init(MRT0, &mrt_config);
52 }
53
mcx_hwtimer_start(rt_hwtimer_t * timer,rt_uint32_t cnt,rt_hwtimer_mode_t mode)54 static rt_err_t mcx_hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode)
55 {
56 rt_err_t ret = RT_EOK;
57
58 mcx_hwtimer_obj_t *handle = timer->parent.user_data;
59
60 MRT_StopTimer(MRT0, handle->channel);
61
62 ret = mcx_hwtimer_mode_set(handle, mode);
63 if (ret != RT_EOK)
64 {
65 return ret;
66 }
67
68 MRT_StartTimer(MRT0, handle->channel, cnt);
69 MRT_EnableInterrupts(MRT0, handle->channel, kMRT_TimerInterruptEnable);
70
71 return ret;
72 }
73
mcx_hwtimer_stop(rt_hwtimer_t * timer)74 static void mcx_hwtimer_stop(rt_hwtimer_t *timer)
75 {
76 mcx_hwtimer_obj_t *handle = timer->parent.user_data;
77 MRT_StopTimer(MRT0, handle->channel);
78 MRT_DisableInterrupts(MRT0, handle->channel, kMRT_TimerInterruptEnable);
79 }
80
mcx_hwtimer_count_get(rt_hwtimer_t * timer)81 static rt_uint32_t mcx_hwtimer_count_get(rt_hwtimer_t *timer)
82 {
83 mcx_hwtimer_obj_t *handle = timer->parent.user_data;
84
85 return MRT_GetCurrentTimerCount(MRT0, handle->channel);
86 }
87
mcx_hwtimer_control(rt_hwtimer_t * timer,rt_uint32_t cmd,void * args)88 static rt_err_t mcx_hwtimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args)
89 {
90 rt_err_t ret = RT_EOK;
91
92 mcx_hwtimer_obj_t *handle = timer->parent.user_data;
93 switch (cmd)
94 {
95 case HWTIMER_CTRL_STOP:
96 mcx_hwtimer_stop(timer);
97 break;
98
99 case HWTIMER_CTRL_MODE_SET:
100 ret = mcx_hwtimer_mode_set(handle, *(rt_hwtimer_mode_t *)args);
101 if (ret != RT_EOK)
102 {
103 return ret;
104 }
105 break;
106
107 default:
108 return -RT_EINVAL;
109 }
110
111 return RT_EOK;
112 }
113
114 static mcx_hwtimer_obj_t mcx_hwtimer_list[] =
115 {
116 { .name = "timer0", .channel = kMRT_Channel_0, },
117 { .name = "timer1", .channel = kMRT_Channel_1, },
118 { .name = "timer2", .channel = kMRT_Channel_2, },
119 { .name = "timer3", .channel = kMRT_Channel_3, },
120 };
121
122 static struct rt_hwtimer_info mcx_hwtimer_info =
123 {
124 .cntmode = HWTIMER_CNTMODE_DW,
125 .maxcnt = 0x00FFFFFF, /* 24bit counter */
126 .minfreq = 150000000,
127 .maxfreq = 150000000,
128 };
129
130 static const struct rt_hwtimer_ops mcx_hwtimer_ops =
131 {
132 .init = mcx_hwtimer_init,
133 .control = mcx_hwtimer_control,
134 .start = mcx_hwtimer_start,
135 .stop = mcx_hwtimer_stop,
136 .count_get = mcx_hwtimer_count_get,
137 };
138
rt_hw_hwtimer_init(void)139 int rt_hw_hwtimer_init(void)
140 {
141 /* MRT frequency is fixed to AHB clock */
142 uint32_t mrt_freq = CLOCK_GetFreq(kCLOCK_BusClk);
143
144 mcx_hwtimer_info.minfreq = mrt_freq;
145 mcx_hwtimer_info.maxfreq = mrt_freq;
146
147 for (uint8_t i = 0; i < ARRAY_SIZE(mcx_hwtimer_list); i++)
148 {
149 mcx_hwtimer_list[i].timer_device.info = &mcx_hwtimer_info;
150 mcx_hwtimer_list[i].timer_device.ops = &mcx_hwtimer_ops;
151
152 rt_err_t ret = rt_device_hwtimer_register(&mcx_hwtimer_list[i].timer_device, mcx_hwtimer_list[i].name, &mcx_hwtimer_list[i]);
153 if (ret != RT_EOK)
154 {
155 return ret;
156 }
157 }
158
159 EnableIRQ(MRT0_IRQn);
160
161 return RT_EOK;
162 }
163
MRT0_IRQHandler(void)164 void MRT0_IRQHandler(void)
165 {
166 /* Get channel interrupt flags */
167 uint32_t mrt_flag = MRT0->IRQ_FLAG;
168
169 /* Clear interrupt flags (W1C). */
170 MRT0->IRQ_FLAG = mrt_flag;
171
172 for (uint8_t i = 0; i < 4; i++)
173 {
174 if (mrt_flag & (1U << i))
175 {
176 rt_device_hwtimer_isr(&mcx_hwtimer_list[i].timer_device);
177 }
178 }
179 }
180
181 INIT_DEVICE_EXPORT(rt_hw_hwtimer_init);
182
183 #endif /* BSP_USING_HWTIMER */
184