1 /*
2 * Copyright (c) 2022-2024 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-05-09 HPMicro First version
9 * 2023-04-12 HPMicro Adapt hpm_sdk v1.0.0
10 * 2023-05-13 HPMicro Fix compiling error on HPM6360/HPM6200
11 * 2023-06-10 HPMicro Add PWMv2 support
12 */
13
14 #include <rtthread.h>
15
16 #if defined(BSP_USING_PWM) || defined(BSP_USING_PWMV2)
17 #if defined(BSP_USING_PWMV2)
18 #define HPMSOC_HAS_HPMSDK_PWMV2
19 #endif
20 #include <rthw.h>
21 #include <rtdevice.h>
22 #include "board.h"
23 #include "drv_gpio.h"
24 #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
25 #include "hpm_pwmv2_drv.h"
26 #else
27 #include "hpm_pwm_drv.h"
28 #endif
29 #include "hpm_clock_drv.h"
30
31 #ifdef HPM_PWM3
32 #define PWM_INSTANCE_NUM 4
33 #elif defined(HPM_PWM2)
34 #define PWM_INSTANCE_NUM 3
35 #elif defined(HPM_PWM1)
36 #define PWM_INSTANCE_NUM 2
37 #else
38 #define PWM_INSTANCE_NUM 1
39 #endif
40
41 #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
42 static PWMV2_Type * pwm_base_tbl[PWM_INSTANCE_NUM] = {
43 #else
44 static PWM_Type * pwm_base_tbl[PWM_INSTANCE_NUM] = {
45 #endif
46 HPM_PWM0,
47 #ifdef HPM_PWM1
48 HPM_PWM1,
49 #endif
50 #ifdef HPM_PWM2
51 HPM_PWM2,
52 #endif
53 #ifdef HPM_PWM3
54 HPM_PWM3
55 #endif
56 };
57
58 #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
59
60 #ifdef PWMV2_CNT_3
61 #define PWMV2_CNT_NUM 4
62 #elif PWMV2_CNT_2
63 #define PWMV2_CNT_NUM 3
64 #elif PWMV2_CNT_1
65 #define PWMV2_CNT_NUM 2
66 #else
67 #define PWMV2_CNT_NUM 1
68 #endif
69
70 static pwm_counter_t pwmv2_counter_tbl[PWMV2_CNT_NUM * 2] = {
71 pwm_counter_0,
72 pwm_counter_0,
73 #ifdef PWMV2_CNT_1
74 pwm_counter_1,
75 pwm_counter_1,
76 #endif
77 #ifdef PWMV2_CNT_2
78 pwm_counter_2,
79 pwm_counter_2,
80 #endif
81 #ifdef PWMV2_CNT_3
82 pwm_counter_3,
83 pwm_counter_3,
84 #endif
85 };
86 #endif
87
hpm_generate_central_aligned_waveform(uint8_t pwm_index,uint8_t channel,uint32_t period,uint32_t pulse)88 rt_err_t hpm_generate_central_aligned_waveform(uint8_t pwm_index, uint8_t channel, uint32_t period, uint32_t pulse)
89 {
90 #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
91 PWMV2_Type * pwm_base;
92 pwm_counter_t pwm_counter;
93 #else
94 PWM_Type * pwm_base;
95 pwm_cmp_config_t cmp_config[2] = {0};
96 pwm_config_t pwm_config = {0};
97 #endif
98 uint32_t duty;
99 uint32_t reload = 0;
100 uint32_t freq;
101 pwm_base = pwm_base_tbl[pwm_index];
102
103 init_pwm_pins(pwm_base);
104 freq = board_init_pwm_clock(pwm_base);
105 if(period != 0) {
106 reload = (uint64_t)freq * period / 1000000000;
107 } else {
108 reload = 0;
109 }
110 duty = (uint64_t)freq * pulse / 1000000000;
111
112 #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
113
114 pwm_counter = pwmv2_counter_tbl[channel];
115
116 pwmv2_disable_counter(pwm_base, pwm_counter);
117 pwmv2_reset_counter(pwm_base, pwm_counter);
118 pwmv2_shadow_register_unlock(pwm_base);
119
120 pwmv2_set_shadow_val(pwm_base, channel / 2, reload, 0, false); /**< cnt use 0-3 shadow */
121 pwmv2_set_shadow_val(pwm_base, channel * 2 + 4, reload + 1, 0, false);
122 pwmv2_set_shadow_val(pwm_base, channel * 2 + 5, reload, 0, false);
123
124 pwmv2_counter_select_data_offset_from_shadow_value(pwm_base, pwm_counter, channel / 2);
125 pwmv2_counter_burst_disable(pwm_base, pwm_counter);
126 pwmv2_set_reload_update_time(pwm_base, pwm_counter, pwm_reload_update_on_reload);
127
128 pwmv2_select_cmp_source(pwm_base, channel * 2, cmp_value_from_shadow_val, channel * 2 + 4);
129 pwmv2_select_cmp_source(pwm_base, channel * 2 + 1, cmp_value_from_shadow_val, channel * 2 + 5);
130
131 pwmv2_shadow_register_lock(pwm_base);
132 pwmv2_disable_four_cmp(pwm_base, channel);
133 pwmv2_channel_enable_output(pwm_base, channel);
134 pwmv2_enable_counter(pwm_base, pwm_counter);
135 pwmv2_start_pwm_output(pwm_base, pwm_counter);
136
137 pwmv2_shadow_register_unlock(pwm_base);
138 pwmv2_set_shadow_val(pwm_base, channel * 2, (reload - duty) >> 1, 0, false);
139 pwmv2_set_shadow_val(pwm_base, channel * 2, (reload + duty) >> 1, 0, false);
140 pwmv2_shadow_register_lock(pwm_base);
141 #else
142
143 pwm_stop_counter(pwm_base);
144 pwm_get_default_pwm_config(pwm_base, &pwm_config);
145
146 /*
147 * reload and start counter
148 */
149 pwm_set_reload(pwm_base, 0, reload);
150 pwm_set_start_count(pwm_base, 0, 0);
151
152 /*
153 * config cmp1 and cmp2
154 */
155
156 cmp_config[0].mode = pwm_cmp_mode_output_compare;
157 cmp_config[0].cmp = (reload - duty) >> 1;
158 cmp_config[0].update_trigger = pwm_shadow_register_update_on_shlk;
159
160 cmp_config[1].mode = pwm_cmp_mode_output_compare;
161 cmp_config[1].cmp = (reload + duty) >> 1;
162 cmp_config[1].update_trigger = pwm_shadow_register_update_on_shlk;
163
164
165 pwm_config.enable_output = true;
166 pwm_config.dead_zone_in_half_cycle = 0;
167 pwm_config.invert_output = false;
168 /*
169 * config pwm
170 */
171 if (status_success != pwm_setup_waveform(pwm_base, channel, &pwm_config, channel * 2, cmp_config, 2)) {
172 return -RT_ERROR;
173 }
174 pwm_start_counter(pwm_base);
175 pwm_issue_shadow_register_lock_event(pwm_base);
176
177 #endif
178 return RT_EOK;
179
180 }
181
hpm_set_central_aligned_waveform(uint8_t pwm_index,uint8_t channel,uint32_t period,uint32_t pulse)182 rt_err_t hpm_set_central_aligned_waveform(uint8_t pwm_index, uint8_t channel, uint32_t period, uint32_t pulse)
183 {
184 #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
185 PWMV2_Type * pwm_base;
186 #else
187 PWM_Type * pwm_base;
188 pwm_config_t pwm_config = {0};
189 #endif
190
191 uint32_t duty;
192 uint32_t reload = 0;
193 uint32_t freq;
194
195 pwm_base = pwm_base_tbl[pwm_index];
196 freq = board_init_pwm_clock(pwm_base);
197 if(period != 0) {
198 reload = (uint64_t)freq * period / 1000000000;
199 } else {
200 reload = 0;
201 }
202 duty = (uint64_t)freq * pulse / 1000000000;
203
204 #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
205 pwmv2_shadow_register_unlock(pwm_base);
206 pwmv2_set_shadow_val(pwm_base, channel / 2, reload, 0, false); /**< cnt use 0-3 shadow */
207 pwmv2_set_shadow_val(pwm_base, channel * 2 + 4, (reload - duty) >> 1, 0, false);
208 pwmv2_set_shadow_val(pwm_base, channel * 2 + 5, (reload + duty) >> 1, 0, false);
209 pwmv2_shadow_register_lock(pwm_base);
210 #else
211 pwm_get_default_pwm_config(pwm_base, &pwm_config);
212 pwm_set_reload(pwm_base, 0, reload);
213 pwm_update_raw_cmp_central_aligned(pwm_base, channel * 2, channel * 2 + 1, (reload - duty) >> 1, (reload + duty) >> 1);
214 pwm_issue_shadow_register_lock_event(pwm_base);
215 #endif
216
217 return RT_EOK;
218 }
219
hpm_disable_pwm(uint8_t pwm_index,uint8_t channel)220 rt_err_t hpm_disable_pwm(uint8_t pwm_index, uint8_t channel)
221 {
222 #if defined(HPMSOC_HAS_HPMSDK_PWMV2)
223 PWMV2_Type * pwm_base;
224
225 pwm_base = pwm_base_tbl[pwm_index];
226 pwmv2_shadow_register_unlock(pwm_base);
227 pwmv2_set_shadow_val(pwm_base, channel * 2 + 4, 0, 0, false);
228 pwmv2_set_shadow_val(pwm_base, channel * 2 + 5, 0, 0, false);
229 pwmv2_shadow_register_lock(pwm_base);
230 #else
231 pwm_disable_output(pwm_base_tbl[pwm_index], channel);
232 #endif
233 return RT_EOK;
234
235 }
236
hpm_pwm_control(struct rt_device_pwm * device,int cmd,void * arg)237 rt_err_t hpm_pwm_control(struct rt_device_pwm * device, int cmd, void *arg)
238 {
239 uint8_t channel;
240 uint32_t period;
241 uint32_t pulse;
242 rt_err_t sta = RT_EOK;
243 unsigned char pwm_name;
244 struct rt_pwm_configuration * configuration;
245 configuration = (struct rt_pwm_configuration * )arg;
246 channel = configuration->channel;
247 period = configuration->period;
248 pulse = configuration->pulse;
249 if (strcmp("pwm0", device->parent.parent.name) == 0) {
250 pwm_name = 0;
251 } else if (strcmp("pwm1", device->parent.parent.name) == 0) {
252 pwm_name = 1;
253 } else if (strcmp("pwm2", device->parent.parent.name) == 0) {
254 pwm_name = 2;
255 } else if (strcmp("pwm3", device->parent.parent.name) == 0) {
256 pwm_name = 3;
257 } else {
258 return -RT_ERROR;
259 }
260
261 switch(cmd) {
262 case PWM_CMD_ENABLE: {
263 sta = hpm_generate_central_aligned_waveform(pwm_name, channel, period, pulse);
264 break;
265 }
266 case PWM_CMD_DISABLE: {
267 hpm_disable_pwm(pwm_name, channel);
268 break;
269 }
270 case PWM_CMD_SET: {
271 sta = hpm_set_central_aligned_waveform(pwm_name, channel, period, pulse);
272 break;
273 }
274 case PWM_CMD_GET: {
275 sta = RT_EOK;
276 break;
277 }
278 default: {
279 sta = -RT_ERROR;
280 break;
281 }
282 }
283 return sta;
284 }
285
hpm_pwm_dev_control(rt_device_t device,int cmd,void * arg)286 rt_err_t hpm_pwm_dev_control(rt_device_t device, int cmd, void *arg)
287 {
288 uint8_t channel;
289 uint32_t period;
290 uint32_t pulse;
291 rt_err_t sta = RT_EOK;
292 uint8_t pwm_name;
293 struct rt_pwm_configuration * configuration;
294 configuration = (struct rt_pwm_configuration * )arg;
295 channel = configuration->channel;
296 period = configuration->period;
297 pulse = configuration->pulse;
298 if (strcmp("pwm0", device->parent.name) == 0) {
299 pwm_name = 0;
300 } else if (strcmp("pwm1", device->parent.name) == 0) {
301 pwm_name = 1;
302 } else if (strcmp("pwm2", device->parent.name) == 0) {
303 pwm_name = 2;
304 } else if (strcmp("pwm3", device->parent.name) == 0) {
305 pwm_name = 3;
306 } else {
307 return -RT_ERROR;
308 }
309
310 switch(cmd) {
311 case PWM_CMD_ENABLE: {
312 sta = hpm_generate_central_aligned_waveform(pwm_name, channel, period, pulse);
313 break;
314 }
315 case PWM_CMD_DISABLE: {
316 hpm_disable_pwm(pwm_name, channel);
317 break;
318 }
319 case PWM_CMD_SET: {
320 sta = hpm_set_central_aligned_waveform(pwm_name, channel, period, pulse);
321 break;
322 }
323 case PWM_CMD_GET: {
324 sta = RT_EOK;
325 break;
326 }
327 default: {
328 sta = -RT_ERROR;
329 break;
330 }
331 }
332 return sta;
333 }
334
335 const static struct rt_pwm_ops hpm_pwm_ops = {
336 .control = &hpm_pwm_control
337 };
338
339 static struct rt_device hpm_pwm_parent = {
340 .control = hpm_pwm_dev_control
341 };
342
343 #ifdef HPM_PWM0
344 static struct rt_device_pwm hpm_dev_pwm0 = {
345 .ops = &hpm_pwm_ops,
346 };
347 #endif
348
349 #ifdef HPM_PWM1
350 static struct rt_device_pwm hpm_dev_pwm1 = {
351 .ops = &hpm_pwm_ops,
352 };
353 #endif
354
355 #ifdef HPM_PWM2
356 static struct rt_device_pwm hpm_dev_pwm2 = {
357 .ops = &hpm_pwm_ops,
358 };
359 #endif
360
361 #ifdef HPM_PWM3
362 static struct rt_device_pwm hpm_dev_pwm3 = {
363 .ops = &hpm_pwm_ops,
364 };
365 #endif
366
367
rt_hw_pwm_init(void)368 int rt_hw_pwm_init(void)
369 {
370 int ret = RT_EOK;
371
372 #ifdef HPM_PWM0
373 hpm_dev_pwm0.parent = hpm_pwm_parent;
374 ret = rt_device_pwm_register(&hpm_dev_pwm0, "pwm0", &hpm_pwm_ops, RT_NULL);
375 #endif
376
377 #ifdef HPM_PWM1
378 hpm_dev_pwm1.parent = hpm_pwm_parent;
379 ret = rt_device_pwm_register(&hpm_dev_pwm1, "pwm1", &hpm_pwm_ops, RT_NULL);
380 #endif
381 #ifdef HPM_PWM2
382 hpm_dev_pwm2.parent = hpm_pwm_parent;
383 ret = rt_device_pwm_register(&hpm_dev_pwm2, "pwm2", &hpm_pwm_ops, RT_NULL);
384 #endif
385 #ifdef HPM_PWM3
386 hpm_dev_pwm3.parent = hpm_pwm_parent;
387 ret = rt_device_pwm_register(&hpm_dev_pwm3, "pwm3", &hpm_pwm_ops, RT_NULL);
388 #endif
389
390 return ret;
391 }
392
393 INIT_BOARD_EXPORT(rt_hw_pwm_init);
394
395 #endif /* BSP_USING_PWM */
396