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 * 2018-04-17     WangBing     the first version.
9 * 2019-04-22     tyustli      add imxrt series support
10 *
11 */
12 #include <rtthread.h>
13 
14 #ifdef BSP_USING_HWTIMER
15 
16 #define LOG_TAG             "drv.hwtimer"
17 #include <drv_log.h>
18 
19 #include <rtdevice.h>
20 #include "drv_hwtimer.h"
21 #include "fsl_gpt.h"
22 
23 #if defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL
24 #error "Please don't define 'FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL'!"
25 #endif
26 
27 /* Select IPG Clock as PERCLK_CLK clock source */
28 #define EXAMPLE_GPT_CLOCK_SOURCE_SELECT (0U)
29 /* Clock divider for PERCLK_CLK clock source */
30 #define EXAMPLE_GPT_CLOCK_DIVIDER_SELECT (5U)
31 /* Get source clock for GPT driver (GPT prescaler = 6) */
32 #ifdef SOC_IMXRT1170_SERIES
33 #undef EXAMPLE_GPT_CLOCK_DIVIDER_SELECT
34 #define EXAMPLE_GPT_CLOCK_DIVIDER_SELECT (2U)
35 // 1170 use this root directly, we have already divide this clk, can read it directly
36 #define EXAMPLE_GPT_CLK_FREQ (CLOCK_GetRootClockFreq(kCLOCK_Root_Gpt1))
37 #else
38 #define EXAMPLE_GPT_CLK_FREQ (CLOCK_GetFreq(kCLOCK_IpgClk) / (EXAMPLE_GPT_CLOCK_DIVIDER_SELECT + 1U))
39 #endif
40 
NVIC_Configuration(void)41 static void NVIC_Configuration(void)
42 {
43 #ifdef BSP_USING_HWTIMER1
44     EnableIRQ(GPT1_IRQn);
45 #endif
46 
47 #ifdef BSP_USING_HWTIMER2
48     EnableIRQ(GPT2_IRQn);
49 #endif
50 }
51 
imxrt_hwtimer_control(rt_hwtimer_t * timer,rt_uint32_t cmd,void * args)52 static rt_err_t imxrt_hwtimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args)
53 {
54     rt_err_t err = RT_EOK;
55     GPT_Type *hwtimer_dev;
56     hwtimer_dev = (GPT_Type *)timer->parent.user_data;
57 
58     RT_ASSERT(timer != RT_NULL);
59 
60     switch (cmd)
61     {
62     case HWTIMER_CTRL_FREQ_SET:
63     {
64         uint32_t clk;
65         uint32_t pre;
66         clk = EXAMPLE_GPT_CLK_FREQ;
67         pre = clk / *((uint32_t *)args) - 1;
68         GPT_SetClockDivider(hwtimer_dev, pre);
69     }
70     break;
71     default:
72         err = -RT_ENOSYS;
73         break;
74     }
75     return err;
76 }
77 
imxrt_hwtimer_count_get(rt_hwtimer_t * timer)78 static rt_uint32_t imxrt_hwtimer_count_get(rt_hwtimer_t *timer)
79 {
80     rt_uint32_t CurrentTimer_Count;
81     GPT_Type *hwtimer_dev;
82     hwtimer_dev = (GPT_Type *)timer->parent.user_data;
83 
84     RT_ASSERT(timer != RT_NULL);
85 
86     CurrentTimer_Count = GPT_GetCurrentTimerCount(hwtimer_dev);
87 
88     return CurrentTimer_Count;
89 }
90 
imxrt_hwtimer_init(rt_hwtimer_t * timer,rt_uint32_t state)91 static void imxrt_hwtimer_init(rt_hwtimer_t *timer, rt_uint32_t state)
92 {
93     GPT_Type *hwtimer_dev;
94     gpt_config_t gptConfig;
95     hwtimer_dev = (GPT_Type *)timer->parent.user_data;
96 
97     RT_ASSERT(timer != RT_NULL);
98 
99     if (state == 1)
100     {
101     #ifdef SOC_IMXRT1170_SERIES
102     #ifdef BSP_USING_HWTIMER1
103         /*Clock setting for GPT*/
104         CLOCK_SetRootClockMux(kCLOCK_Root_Gpt1, EXAMPLE_GPT_CLOCK_SOURCE_SELECT);
105         CLOCK_SetRootClockDiv(kCLOCK_Root_Gpt1, EXAMPLE_GPT_CLOCK_DIVIDER_SELECT);
106     #endif
107     #ifdef BSP_USING_HWTIMER2
108         /*Clock setting for GPT*/
109         CLOCK_SetRootClockMux(kCLOCK_Root_Gpt2, EXAMPLE_GPT_CLOCK_SOURCE_SELECT);
110         CLOCK_SetRootClockDiv(kCLOCK_Root_Gpt2, EXAMPLE_GPT_CLOCK_DIVIDER_SELECT);
111     #endif
112     #else
113         /*Clock setting for GPT*/
114         CLOCK_SetMux(kCLOCK_PerclkMux, EXAMPLE_GPT_CLOCK_SOURCE_SELECT);
115         CLOCK_SetDiv(kCLOCK_PerclkDiv, EXAMPLE_GPT_CLOCK_DIVIDER_SELECT);
116     #endif
117 
118         /* Initialize GPT module by default config */
119         GPT_GetDefaultConfig(&gptConfig);
120         GPT_Init(hwtimer_dev, &gptConfig);
121     }
122 }
123 
imxrt_hwtimer_start(rt_hwtimer_t * timer,rt_uint32_t cnt,rt_hwtimer_mode_t mode)124 static rt_err_t imxrt_hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode)
125 {
126     GPT_Type *hwtimer_dev;
127     hwtimer_dev = (GPT_Type *)timer->parent.user_data;
128 
129     RT_ASSERT(timer != RT_NULL);
130 
131     hwtimer_dev->CR |= (mode != HWTIMER_MODE_PERIOD) ? GPT_CR_FRR_MASK : 0U;
132 
133     GPT_SetOutputCompareValue(hwtimer_dev, kGPT_OutputCompare_Channel1, cnt);
134 
135     GPT_EnableInterrupts(hwtimer_dev, kGPT_OutputCompare1InterruptEnable);
136 
137     NVIC_Configuration();
138 
139     GPT_StartTimer(hwtimer_dev);
140 
141     return RT_EOK;
142 }
143 
imxrt_hwtimer_stop(rt_hwtimer_t * timer)144 static void imxrt_hwtimer_stop(rt_hwtimer_t *timer)
145 {
146     GPT_Type *hwtimer_dev;
147     hwtimer_dev = (GPT_Type *)timer->parent.user_data;
148 
149     RT_ASSERT(timer != RT_NULL);
150 
151     GPT_StopTimer(hwtimer_dev);
152 }
153 
154 static const struct rt_hwtimer_ops imxrt_hwtimer_ops =
155 {
156     .init = imxrt_hwtimer_init,
157     .start = imxrt_hwtimer_start,
158     .stop = imxrt_hwtimer_stop,
159     .count_get = imxrt_hwtimer_count_get,
160     .control = imxrt_hwtimer_control,
161 };
162 
163 static const struct rt_hwtimer_info imxrt_hwtimer_info =
164 {
165     25000000,           /* the maximum count frequency can be set */
166     6103,               /* the minimum count frequency can be set */
167     0xFFFFFFFF,
168     HWTIMER_CNTMODE_UP,
169 };
170 
171 #ifdef BSP_USING_HWTIMER1
172 static rt_hwtimer_t GPT_timer1;
173 #endif /*BSP_USING_HWTIMER1*/
174 
175 #ifdef BSP_USING_HWTIMER2
176 static rt_hwtimer_t GPT_timer2;
177 #endif
178 
rt_hw_hwtimer_init(void)179 int rt_hw_hwtimer_init(void)
180 {
181     int ret = RT_EOK;
182 
183 #ifdef BSP_USING_HWTIMER1
184     GPT_timer1.info = &imxrt_hwtimer_info;
185     GPT_timer1.ops  = &imxrt_hwtimer_ops;
186     ret = rt_device_hwtimer_register(&GPT_timer1, "gpt1", GPT1);
187 
188     if (ret != RT_EOK)
189     {
190         LOG_E("gpt1 register failed\n");
191     }
192 #endif
193 
194 #ifdef BSP_USING_HWTIMER2
195     GPT_timer2.info = &imxrt_hwtimer_info;
196     GPT_timer2.ops = &imxrt_hwtimer_ops;
197     ret = rt_device_hwtimer_register(&GPT_timer2, "gpt2", GPT2);
198 
199     if (ret != RT_EOK)
200     {
201         LOG_E("gpt1 register failed\n");
202     }
203 #endif
204 
205     return ret;
206 }
207 
208 #ifdef BSP_USING_HWTIMER1
209 
GPT1_IRQHandler(void)210 void GPT1_IRQHandler(void)
211 {
212     if (GPT_GetStatusFlags(GPT1, kGPT_OutputCompare1Flag) != 0)
213     {
214         GPT_ClearStatusFlags(GPT1, kGPT_OutputCompare1Flag);
215         rt_device_hwtimer_isr(&GPT_timer1);
216     }
217 
218     /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F, Cortex-M7, Cortex-M7F Store immediate overlapping
219       exception return operation might vector to incorrect interrupt */
220 #if defined __CORTEX_M && (__CORTEX_M == 4U || __CORTEX_M == 7U)
221     __DSB();
222 #endif
223 }
224 
225 #endif /*BSP_USING_HWTIMER1*/
226 
227 #ifdef BSP_USING_HWTIMER2
228 
GPT2_IRQHandler(void)229 void GPT2_IRQHandler(void)
230 {
231     if (GPT_GetStatusFlags(GPT2, kGPT_OutputCompare1Flag) != 0)
232     {
233         GPT_ClearStatusFlags(GPT2, kGPT_OutputCompare1Flag);
234         rt_device_hwtimer_isr(&GPT_timer2);
235     }
236 
237     /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F, Cortex-M7, Cortex-M7F Store immediate overlapping
238       exception return operation might vector to incorrect interrupt */
239 #if defined __CORTEX_M && (__CORTEX_M == 4U || __CORTEX_M == 7U)
240     __DSB();
241 #endif
242 }
243 #endif /*BSP_USING_HWTIMER2*/
244 
245 INIT_DEVICE_EXPORT(rt_hw_hwtimer_init);
246 
247 #endif /* BSP_USING_HWTIMER */
248