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