1 // Copyright (C) 2022 Beken Corporation
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <common/bk_include.h>
16 #include <common/bk_compiler.h>
17 #include "icu_driver.h"
18 #include <os/mem.h>
19 #include <driver/pwm.h>
20 #include "pwm_hal.h"
21 #include "pwm_driver.h"
22 #include "clock_driver.h"
23 #include "power_driver.h"
24 #include <driver/int.h>
25 #include "sys_driver.h"
26 #include "gpio_driver.h"
27 #include <driver/gpio.h>
28
29 static void pwm_isr(void) __BK_SECTION(".itcm");
30
31 //TODO list
32 // 1. Check if a PWM channel already in using
33 // 2. Support PWM timer/counter API
34
35 typedef struct {
36 pwm_chan_t chan1;
37 pwm_chan_t chan2;
38 bool is_valid;
39 } pwm_group_info_t;
40
41 #define PWM_GROUP_NUM (SOC_PWM_CHAN_NUM_PER_UNIT >> 1)
42 #define PWM_GPIO_MODE_MAX 4
43
44 typedef struct {
45 pwm_hal_t hal;
46 //Important notes: currently no lock for bits
47 //Concurrently operation is NOT allowed!!!
48 uint32_t chan_init_bits;
49 pwm_group_info_t groups[PWM_GROUP_NUM];
50 } pwm_driver_t;
51
52 pwm_driver_t s_pwm = {0};
53 static pwm_isr_t s_pwm_isr[SOC_PWM_CHAN_NUM_PER_UNIT] = {NULL};
54 static bool s_pwm_driver_is_init = false;
55
56 #define PWM_RETURN_ON_INVALID_CHAN(chan) do {\
57 if ((chan) >= SOC_PWM_CHAN_NUM_PER_UNIT) {\
58 return BK_ERR_PWM_CHAN_ID;\
59 }\
60 } while(0)
61
62 #define PWM_RETURN_ON_INVALID_CHAN_CLOCK(clock) do {\
63 if ((clock) >= PWM_CHAN_CLOCK_MAX) {\
64 return BK_ERR_PWM_CHAN_CLOCK;\
65 }\
66 } while(0)
67
68 #define PWM_RETURN_ON_NOT_INIT() do {\
69 if (!s_pwm_driver_is_init) {\
70 return BK_ERR_PWM_NOT_INIT;\
71 }\
72 } while(0)
73
74 #define PWM_RETURN_ON_CHAN_NOT_INIT(chan) do {\
75 if (!(s_pwm.chan_init_bits & BIT((chan)))) {\
76 return BK_ERR_PWM_CHAN_NOT_INIT;\
77 }\
78 } while(0)
79
80 #define PWM_RETURN_ON_INVALID_GROUP(chan) do {\
81 if (chan >= PWM_GROUP_NUM) {\
82 return BK_ERR_PWM_GROUP_ID;\
83 }\
84 } while(0)
85
86 #define PWM_RETURN_ON_INVALID_GPIO_MODE(chan) do {\
87 if (chan >= PWM_GPIO_MODE_MAX) {\
88 return BK_ERR_PWM_INVALID_GPIO_MODE;\
89 }\
90 } while(0)
91
92
93 #define PWM_RETURN_ON_CHAN_NOT_STOP(chan) do {\
94 } while(0)
95
96 #define PWM_SET_PIN(id) do {\
97 gpio_dev_unmap(PWM##id##_LL_PIN);\
98 gpio_dev_map(PWM##id##_LL_PIN, GPIO_DEV_PWM##id);\
99 bk_gpio_pull_up(PWM##id##_LL_PIN);\
100 } while(0)
101
102 static void pwm_init_gpio(pwm_id_t id);
pwm_init_gpio(pwm_id_t id)103 static void pwm_init_gpio(pwm_id_t id)
104 {
105 #if (SOC_PWM_CHAN_NUM_PER_UNIT > 6)
106 if(id == 10) {
107 PWM_SET_PIN(10);
108 return;
109 }
110
111 if(id == 11) {
112 PWM_SET_PIN(11);
113 return;
114 }
115 #endif
116
117 switch(id) {
118 case PWM_ID_0:
119 PWM_SET_PIN(0);
120 break;
121
122 case PWM_ID_1:
123 PWM_SET_PIN(1);
124 break;
125
126 case PWM_ID_2:
127 PWM_SET_PIN(2);
128 break;
129
130 case PWM_ID_3:
131 PWM_SET_PIN(3);
132 break;
133
134 case PWM_ID_4:
135 PWM_SET_PIN(4);
136 break;
137
138 case PWM_ID_5:
139 PWM_SET_PIN(5);
140 break;
141
142 default:
143 break;
144 }
145 }
146
147 //TODO call it via gpio hal
pwm_set_gpio(pwm_chan_t chan)148 static void pwm_set_gpio(pwm_chan_t chan)
149 {
150 pwm_init_gpio(chan);
151 }
152
pwm_chan_enable_interrupt_common(pwm_chan_t chan)153 static void pwm_chan_enable_interrupt_common(pwm_chan_t chan)
154 {
155 if (pwm_hal_is_pwm2_interrupt(&s_pwm.hal, chan))
156 icu_enable_pwm2_interrupt();
157 else {
158 #if (CONFIG_SYSTEM_CTRL)
159 sys_drv_int_enable(PWM_INTERRUPT_CTRL_BIT);
160 #else
161 icu_enable_pwm_interrupt();
162 #endif
163 }
164 pwm_hal_enable_interrupt(&s_pwm.hal, chan);
165 }
166
167 /* Once the global PWM interrupt is enabled, we never disable it.
168 * It should be OK, because if all PWM are stop, there will be no
169 * PWM interrupt even though the global PWM interrupt is enabled.
170 *
171 * We can choose to disable the global PWM interrupt if all PWM
172 * channels are stopped, but it make the code complex!
173 **/
pwm_chan_disable_interrupt_common(pwm_chan_t chan)174 static void pwm_chan_disable_interrupt_common(pwm_chan_t chan)
175 {
176 pwm_hal_disable_interrupt(&s_pwm.hal, chan);
177 pwm_hal_clear_chan_interrupt_status(&s_pwm.hal, chan);
178 }
179
180 /* Init common to PWM/Capture init
181 * 1. Set channel init bit
182 * 2. Power up channel
183 * 3. Set channel specific clock
184 */
pwm_chan_init_common(pwm_chan_t chan)185 static void pwm_chan_init_common(pwm_chan_t chan)
186 {
187 s_pwm.chan_init_bits |= BIT(chan);
188
189
190 #if (CONFIG_SYSTEM_CTRL)
191 sys_drv_dev_clk_pwr_up(CLK_PWR_ID_PWM_1, CLK_PWR_CTRL_PWR_UP);
192 sys_drv_dev_clk_pwr_up(CLK_PWR_ID_PWM_2, CLK_PWR_CTRL_PWR_UP);
193 #else
194 power_pwm_pwr_up(chan);
195
196 /* The hardware support to enable LPO clock, however no customer
197 * currently use LPO clock, here we always disable LPO clock for
198 * simplicity.
199 **/
200 clk_disable_pwm_clk_lpo(chan);
201 #endif
202
203 //TODO call hal
204 pwm_set_gpio(chan);
205 pwm_hal_set_init_signal_high(&s_pwm.hal, chan);
206 }
207
pwm_chan_deinit_common(pwm_chan_t chan)208 static void pwm_chan_deinit_common(pwm_chan_t chan)
209 {
210 s_pwm.chan_init_bits &= ~BIT(chan);
211 pwm_hal_stop_common(&s_pwm.hal, chan);
212 pwm_hal_reset_config_to_default(&s_pwm.hal, chan);
213
214 #if (CONFIG_SYSTEM_CTRL)
215 sys_drv_dev_clk_pwr_up(CLK_PWR_ID_PWM_1, CLK_PWR_CTRL_PWR_DOWN);
216 sys_drv_dev_clk_pwr_up(CLK_PWR_ID_PWM_2, CLK_PWR_CTRL_PWR_DOWN);
217 #else
218 power_pwm_pwr_down(chan);
219 #endif
220 }
221
222 //TODO we should remove pwm_init finally
223 //Implement pwm_init/pwm_exit to make it compitable with existing driver model
bk_pwm_driver_init(void)224 bk_err_t bk_pwm_driver_init(void)
225 {
226 if (s_pwm_driver_is_init)
227 return BK_OK;
228
229 os_memset(&s_pwm, 0, sizeof(s_pwm));
230
231 /* Hardware support to configure DCO clock, considering no customers use
232 * DCO clock, we hard-coded to 26M clock for simplicity.
233 *
234 */
235 #if (CONFIG_SYSTEM_CTRL)
236 sys_drv_pwm_select_clock(SYS_SEL_PWM0, PWM_SCLK_XTAL);
237 sys_drv_pwm_select_clock(SYS_SEL_PWM1, PWM_SCLK_XTAL);
238 #else
239 clk_set_pwms_clk_26m();
240 #endif
241
242 //TODO optimize ISR module
243 os_memset(&s_pwm_isr, 0, sizeof(s_pwm_isr));
244 bk_int_isr_register(INT_SRC_PWM, pwm_isr, NULL);
245 #if (CONFIG_PWM_HAS_TWO_INT)
246 if (icu_is_pwm_has_two_int())
247 bk_int_isr_register(INT_SRC_PWM, pwm_isr, NULL);
248 #endif
249 os_memset(&s_pwm, 0, sizeof(s_pwm));
250 pwm_hal_init(&s_pwm.hal);
251
252 s_pwm_driver_is_init = true;
253 return BK_OK;
254 }
255
bk_pwm_driver_deinit(void)256 bk_err_t bk_pwm_driver_deinit(void)
257 {
258 if (!s_pwm_driver_is_init)
259 return BK_OK;
260
261 for (int chan = 0; chan < SOC_PWM_CHAN_NUM_PER_UNIT; chan++)
262 pwm_chan_deinit_common(chan);
263
264 s_pwm_driver_is_init = false;
265 return BK_OK;
266 }
267
pwm_adjust_init_signal_via_duty(pwm_chan_t chan,uint32_t period,uint32_t duty1,uint32_t duty2,uint32_t duty3)268 static void pwm_adjust_init_signal_via_duty(pwm_chan_t chan, uint32_t period,
269 uint32_t duty1, uint32_t duty2, uint32_t duty3)
270 {
271 /** If duty ratio is 0% and initial signal is high,
272 * then the PWM signal will always be high.
273 * To avoid that, we manually configure init signal to low if
274 * duty ratio is 0%.
275 */
276 if (duty1 == 0)
277 pwm_hal_set_init_signal_low(&s_pwm.hal, chan);
278
279 /** If duty ratio is 100% and initial signal is low,
280 * then the PWM signal will always be low.
281 * To avoid that, we manually configure init signal to high if
282 * duty ratio is 100%.
283 */
284 if (duty1 == period)
285 pwm_hal_set_init_signal_high(&s_pwm.hal, chan);
286 }
287
bk_pwm_init(pwm_chan_t chan,const pwm_init_config_t * config)288 bk_err_t bk_pwm_init(pwm_chan_t chan, const pwm_init_config_t *config)
289 {
290 PWM_RETURN_ON_NOT_INIT();
291 BK_RETURN_ON_NULL(config);
292 PWM_RETURN_ON_INVALID_CHAN(chan);
293
294 if (!pwm_hal_is_duty_valid(config->period_cycle, config->duty_cycle,
295 config->duty2_cycle, config->duty3_cycle))
296 return BK_ERR_PWM_PERIOD_DUTY;
297
298 pwm_chan_init_common(chan);
299 pwm_adjust_init_signal_via_duty(chan, config->period_cycle, config->duty_cycle,
300 config->duty2_cycle, config->duty3_cycle);
301
302 pwm_hal_config_t hal_config = {0};
303 hal_config.t4 = config->period_cycle;
304 hal_config.t1 = config->duty_cycle;
305
306 if (config->duty2_cycle > 0)
307 hal_config.t2 = hal_config.t1 + config->duty2_cycle;
308
309 if (config->duty3_cycle > 0)
310 hal_config.t3 = hal_config.t2 + config->duty3_cycle;
311
312 PWM_LOGI("init, chan(%d), t1=%x, t2=%x, t3=%x, t4=%x\n",
313 chan, hal_config.t1, hal_config.t2, hal_config.t3, hal_config.t4);
314
315 return pwm_hal_init_pwm(&s_pwm.hal, chan, &hal_config);
316 }
317
bk_pwm_deinit(pwm_chan_t chan)318 bk_err_t bk_pwm_deinit(pwm_chan_t chan)
319 {
320 pwm_chan_deinit_common(chan);
321 return BK_OK;
322 }
323
bk_pwm_start(pwm_chan_t chan)324 bk_err_t bk_pwm_start(pwm_chan_t chan)
325 {
326 PWM_RETURN_ON_CHAN_NOT_INIT(chan);
327 pwm_hal_start_common(&s_pwm.hal, chan);
328 return BK_OK;
329 }
330
bk_pwm_stop(pwm_chan_t chan)331 bk_err_t bk_pwm_stop(pwm_chan_t chan)
332 {
333 PWM_RETURN_ON_CHAN_NOT_INIT(chan);
334 pwm_hal_stop_common(&s_pwm.hal, chan);
335 return BK_OK;
336 }
337
bk_pwm_register_isr(pwm_chan_t chan,pwm_isr_t isr)338 bk_err_t bk_pwm_register_isr(pwm_chan_t chan, pwm_isr_t isr)
339 {
340 PWM_RETURN_ON_NOT_INIT();
341 PWM_RETURN_ON_INVALID_CHAN(chan);
342
343 GLOBAL_INT_DECLARATION();
344 GLOBAL_INT_DISABLE();
345 s_pwm_isr[chan] = isr;
346 GLOBAL_INT_RESTORE();
347
348 return BK_OK;
349 }
350
351 /* The PWM channel should be started before interrupt can be enabled.
352 */
bk_pwm_enable_interrupt(pwm_chan_t chan)353 bk_err_t bk_pwm_enable_interrupt(pwm_chan_t chan)
354 {
355 PWM_RETURN_ON_CHAN_NOT_INIT(chan);
356 PWM_RETURN_ON_INVALID_CHAN(chan);
357
358 if (pwm_hal_is_chan_started(&s_pwm.hal, chan)) {
359 pwm_chan_enable_interrupt_common(chan);
360 return BK_OK;
361 } else
362 return BK_ERR_PWM_CHAN_NOT_START;
363 }
364
bk_pwm_disable_interrupt(pwm_chan_t chan)365 bk_err_t bk_pwm_disable_interrupt(pwm_chan_t chan)
366 {
367 PWM_RETURN_ON_CHAN_NOT_INIT(chan);
368 PWM_RETURN_ON_INVALID_CHAN(chan);
369
370 pwm_chan_disable_interrupt_common(chan);
371 return BK_OK;
372 }
373
bk_pwm_set_period_duty(pwm_chan_t chan,pwm_period_duty_config_t * config)374 bk_err_t bk_pwm_set_period_duty(pwm_chan_t chan, pwm_period_duty_config_t *config)
375 {
376 uint32_t t1 = 0;
377 uint32_t t2 = 0;
378 uint32_t t3 = 0;
379 uint32_t t4 = 0;
380
381 BK_RETURN_ON_NULL(config);
382 PWM_RETURN_ON_INVALID_CHAN(chan);
383 PWM_RETURN_ON_CHAN_NOT_INIT(chan);
384
385 if (!pwm_hal_is_duty_valid(config->period_cycle, config->duty_cycle,
386 config->duty2_cycle, config->duty3_cycle))
387 return BK_ERR_PWM_PERIOD_DUTY;
388
389 pwm_adjust_init_signal_via_duty(chan, config->period_cycle, config->duty_cycle,
390 config->duty2_cycle, config->duty3_cycle);
391
392 pwm_hal_set_t1(&s_pwm.hal, chan, config->duty_cycle);
393
394 t1 = config->duty_cycle;
395 t2 = config->duty2_cycle;
396 if (t2 > 0)
397 t2 += t1;
398
399 t3 = config->duty3_cycle;
400 if (t3 > 0)
401 t3 += t2;
402
403 t4 = config->period_cycle;
404
405 pwm_hal_set_t1(&s_pwm.hal, chan, t1);
406 pwm_hal_set_t2(&s_pwm.hal, chan, t2);
407 pwm_hal_set_t3(&s_pwm.hal, chan, t3);
408 pwm_hal_set_t4(&s_pwm.hal, chan, t4);
409
410 //The new configuration take effect only loading it
411 pwm_hal_load_new_config(&s_pwm.hal, chan);
412 return BK_OK;
413 }
414
pwm_is_0_duty_ratio(pwm_chan_t chan)415 static bool pwm_is_0_duty_ratio(pwm_chan_t chan)
416 {
417 return (pwm_hal_get_t1(&s_pwm.hal, chan) == 0);
418 }
419
pwm_is_100_duty_ratio(pwm_chan_t chan)420 static bool pwm_is_100_duty_ratio(pwm_chan_t chan)
421 {
422 return (pwm_hal_get_t1(&s_pwm.hal, chan) == pwm_hal_get_t4(&s_pwm.hal, chan));
423 }
424
bk_pwm_set_init_signal_low(pwm_chan_t chan)425 bk_err_t bk_pwm_set_init_signal_low(pwm_chan_t chan)
426 {
427 PWM_RETURN_ON_INVALID_CHAN(chan);
428 PWM_RETURN_ON_CHAN_NOT_INIT(chan);
429
430 if (pwm_is_100_duty_ratio(chan))
431 pwm_hal_set_init_signal_high(&s_pwm.hal, chan);
432 else
433 pwm_hal_set_init_signal_low(&s_pwm.hal, chan);
434
435 pwm_hal_load_new_config(&s_pwm.hal, chan);
436 return BK_OK;
437 }
438
bk_pwm_set_init_signal_high(pwm_chan_t chan)439 bk_err_t bk_pwm_set_init_signal_high(pwm_chan_t chan)
440 {
441 PWM_RETURN_ON_INVALID_CHAN(chan);
442 PWM_RETURN_ON_CHAN_NOT_INIT(chan);
443
444 if (pwm_is_0_duty_ratio(chan))
445 pwm_hal_set_init_signal_low(&s_pwm.hal, chan);
446 else
447 pwm_hal_set_init_signal_high(&s_pwm.hal, chan);
448 return BK_OK;
449 }
450
451 //TODO finish it
bk_pwm_set_gpio(pwm_chan_t id,uint32 mode)452 bk_err_t bk_pwm_set_gpio(pwm_chan_t id, uint32 mode)
453 {
454 PWM_RETURN_ON_INVALID_CHAN(id);
455 PWM_RETURN_ON_CHAN_NOT_INIT(id);
456 PWM_RETURN_ON_INVALID_GPIO_MODE(id);
457
458 #if (SOC_PWM_CHAN_NUM_PER_UNIT > 6)
459 if( (id == 6) || (id == 7) || (id == 8) ||(id == 9) )
460 return gpio_pwms_sel(id, mode);
461 #endif
462 pwm_set_gpio(id);
463
464 return BK_OK;
465 }
466
bk_pwm_capture_init(pwm_chan_t chan,const pwm_capture_init_config_t * config)467 bk_err_t bk_pwm_capture_init(pwm_chan_t chan, const pwm_capture_init_config_t *config)
468 {
469 PWM_RETURN_ON_NOT_INIT();
470 BK_RETURN_ON_NULL(config);
471 PWM_RETURN_ON_INVALID_CHAN(chan);
472
473 if (!pwm_hal_is_capture_edge_valid(config->edge))
474 return BK_ERR_PWM_CAPTURE_EDGE;
475
476 pwm_chan_init_common(chan);
477 s_pwm_isr[chan] = config->isr;
478
479 pwm_hal_capture_config_t hal_config = {
480 .edge = config->edge,
481 };
482
483 return pwm_hal_init_capture(&s_pwm.hal, chan, &hal_config);
484 }
485
bk_pwm_capture_deinit(pwm_chan_t chan)486 bk_err_t bk_pwm_capture_deinit(pwm_chan_t chan)
487 {
488 PWM_RETURN_ON_NOT_INIT();
489 PWM_RETURN_ON_INVALID_CHAN(chan);
490 pwm_chan_deinit_common(chan);
491 return BK_OK;
492 }
493
bk_pwm_capture_start(pwm_chan_t chan)494 bk_err_t bk_pwm_capture_start(pwm_chan_t chan)
495 {
496 PWM_RETURN_ON_CHAN_NOT_INIT(chan);
497 PWM_RETURN_ON_INVALID_CHAN(chan);
498 pwm_hal_start_common(&s_pwm.hal, chan);
499 pwm_chan_enable_interrupt_common(chan); //interrupt should be enabled after capture start
500 return BK_OK;
501 }
502
bk_pwm_capture_stop(pwm_chan_t chan)503 bk_err_t bk_pwm_capture_stop(pwm_chan_t chan)
504 {
505 PWM_RETURN_ON_CHAN_NOT_INIT(chan);
506 PWM_RETURN_ON_INVALID_CHAN(chan);
507 pwm_hal_stop_common(&s_pwm.hal, chan);
508 return BK_OK;
509 }
510
511 //It's up the caller to make sure the channel ID is correct
bk_pwm_capture_get_value(pwm_chan_t chan)512 uint32_t bk_pwm_capture_get_value(pwm_chan_t chan)
513 {
514 return pwm_hal_get_capture_value(&s_pwm.hal, chan);
515 }
516
pwm_group_find_channel(pwm_chan_t chan)517 static pwm_group_t pwm_group_find_channel(pwm_chan_t chan)
518 {
519 for (int i = 0; i < PWM_GROUP_NUM; i++) {
520 if (s_pwm.groups[i].is_valid && ((s_pwm.groups[i].chan1 == chan) ||
521 (s_pwm.groups[i].chan2 == chan)))
522 return i;
523 }
524
525 return PWM_GROUP_ID_INVALID;
526 }
527
pwm_group_find(pwm_chan_t chan1,pwm_chan_t chan2)528 static pwm_group_t pwm_group_find(pwm_chan_t chan1, pwm_chan_t chan2)
529 {
530 for (int i = 0; i < PWM_GROUP_NUM; i++) {
531 if (s_pwm.groups[i].is_valid) {
532
533 if ((s_pwm.groups[i].chan1 == chan1) &&
534 (s_pwm.groups[i].chan2 == chan2))
535 return i;
536
537 if ((s_pwm.groups[i].chan1 == chan2) &&
538 (s_pwm.groups[i].chan2 == chan1))
539 return i;
540 }
541 }
542
543 return PWM_GROUP_ID_INVALID;
544 }
545
pwm_group_is_existed(pwm_group_t group)546 static bool pwm_group_is_existed(pwm_group_t group)
547 {
548 if (group >= PWM_GROUP_NUM)
549 return false;
550
551 return (s_pwm.groups[group].is_valid == true);
552 }
553
pwm_group_add(pwm_chan_t chan1,pwm_chan_t chan2)554 static pwm_group_t pwm_group_add(pwm_chan_t chan1, pwm_chan_t chan2)
555 {
556 for (int i = 0; i < PWM_GROUP_NUM; i++) {
557 if (!s_pwm.groups[i].is_valid) {
558 s_pwm.groups[i].is_valid = true;
559 s_pwm.groups[i].chan1 = chan1;
560 s_pwm.groups[i].chan2 = chan2;
561 return i;
562 }
563 }
564 return PWM_GROUP_ID_INVALID;
565 }
566
pwm_group_delete(pwm_group_t group)567 static void pwm_group_delete(pwm_group_t group)
568 {
569 if (group < PWM_GROUP_NUM)
570 s_pwm.groups[group].is_valid = false;
571 }
572
pwm_group_validate_param(pwm_chan_t chan1,pwm_chan_t chan2,uint32_t period_cycle,uint32_t chan1_duty_cycle,uint32_t chan2_duty_cycle)573 static bk_err_t pwm_group_validate_param(pwm_chan_t chan1, pwm_chan_t chan2,
574 uint32_t period_cycle, uint32_t chan1_duty_cycle, uint32_t chan2_duty_cycle)
575
576 {
577 PWM_RETURN_ON_INVALID_CHAN(chan1);
578 PWM_RETURN_ON_INVALID_CHAN(chan2);
579
580 if (chan1 == chan2)
581 return BK_ERR_PWM_GROUP_SAME_CHAN;
582
583 if (PWM_GROUP_ID_INVALID != pwm_group_find(chan1, chan2))
584 return BK_ERR_PWM_GROUP_EXIST;
585
586 if (PWM_GROUP_ID_INVALID != pwm_group_find_channel(chan1))
587 return BK_ERR_PWM_GROUP_CHAN_USED;
588
589 if (PWM_GROUP_ID_INVALID != pwm_group_find_channel(chan2))
590 return BK_ERR_PWM_GROUP_CHAN_USED;
591
592 if (period_cycle < (chan1_duty_cycle + chan2_duty_cycle))
593 return BK_ERR_PWM_GROUP_DUTY;
594
595 //duty is 0 is meanless
596 if ((chan1_duty_cycle == 0) || (chan2_duty_cycle == 0))
597 return BK_ERR_PWM_GROUP_DUTY;
598
599 return BK_OK;
600 }
601
bk_pwm_group_init(const pwm_group_init_config_t * config,pwm_group_t * group)602 bk_err_t bk_pwm_group_init(const pwm_group_init_config_t *config, pwm_group_t *group)
603 {
604 pwm_init_config_t pwm_config;
605 uint32_t dead_cycle = 0;
606 int ret;
607
608 PWM_RETURN_ON_NOT_INIT();
609 BK_RETURN_ON_NULL(group);
610
611 *group = PWM_GROUP_ID_INVALID;
612 ret = pwm_group_validate_param(config->chan1, config->chan2, config->period_cycle,
613 config->chan1_duty_cycle, config->chan2_duty_cycle);
614 if (ret != BK_OK)
615 return ret;
616
617 /* Relationship between period/duty
618 *
619 * T14/T24 - Period cycle P, P = period_cycle
620 * T11 - PWM channel 1 duty cycle, T11 = chan1_duty_cycle
621 * T21 - PWM channel 2 signal reverse time1
622 * T22 - PWM cahnnel 2 signal reverse time2
623 * D2 = (T22 - T21) = chan2_duty_cycle, it's channe 2's high signal duty cycle
624 * D = (P - chan1_duty_cycle - chan2_duty_cycle)/2, the dead cycle
625 *
626 * T21 = T11 + D
627 * T22 = T21 + chan2_duty_cycle
628 *
629 * |<--D----->|<--D2-----|<--D----->|
630 * ______________
631 * channe1 | |________________________________|
632 * 0 T11 T14
633 * __________
634 * channel2 |_________________________| |__________|
635 * 0 T21 T22 T24
636 *
637 */
638 pwm_config.period_cycle = config->period_cycle;
639 pwm_config.duty_cycle = config->chan1_duty_cycle;
640 pwm_config.duty2_cycle = 0;
641 pwm_config.duty3_cycle = 0;
642 ret = bk_pwm_init(config->chan1, &pwm_config);
643 if (ret != BK_OK)
644 return ret;
645 pwm_hal_set_init_signal_high(&s_pwm.hal, config->chan1);
646
647 dead_cycle = (config->period_cycle - config->chan1_duty_cycle - config->chan2_duty_cycle) >> 1;
648 pwm_config.duty_cycle = config->chan1_duty_cycle + dead_cycle;
649 pwm_config.duty2_cycle = config->chan2_duty_cycle;
650 ret = bk_pwm_init(config->chan2, &pwm_config);
651 if (ret != BK_OK)
652 return ret;
653 pwm_hal_set_init_signal_low(&s_pwm.hal, config->chan2);
654
655 //TODO peter adjust the PWM initial signal according to DUTY value
656
657 *group = pwm_group_add(config->chan1, config->chan2);
658
659 PWM_LOGI("group period=%x chan1_duty=%x chan2_duty=%x\n",
660 config->period_cycle, config->chan1_duty_cycle, config->chan2_duty_cycle);
661 PWM_LOGI("group T21=%x T22=%x\n", pwm_config.duty_cycle, pwm_config.duty2_cycle);
662
663 return BK_OK;
664 }
665
bk_pwm_group_deinit(pwm_group_t group)666 bk_err_t bk_pwm_group_deinit(pwm_group_t group)
667 {
668 if (pwm_group_is_existed(group))
669 return BK_OK;
670
671 bk_pwm_group_stop(group);
672 pwm_chan_deinit_common(s_pwm.groups[group].chan1);
673 pwm_chan_deinit_common(s_pwm.groups[group].chan2);
674 pwm_group_delete(group);
675 return BK_OK;
676 }
677
bk_pwm_group_start(pwm_group_t group)678 bk_err_t bk_pwm_group_start(pwm_group_t group)
679 {
680 pwm_chan_t chan1;
681 pwm_chan_t chan2;
682
683 if (!pwm_group_is_existed(group))
684 return BK_ERR_PWM_GROUP_NOT_EXIST;
685
686 chan1 = s_pwm.groups[group].chan1;
687 chan2 = s_pwm.groups[group].chan2;
688 if (pwm_hal_is_hardware_group(&s_pwm.hal, chan1, chan2))
689 pwm_hal_start_hardware_group(&s_pwm.hal, chan1, chan2);
690
691 pwm_hal_start_common(&s_pwm.hal, chan1);
692 pwm_hal_start_common(&s_pwm.hal, chan2);
693 return BK_OK;
694 }
695
bk_pwm_group_stop(pwm_group_t group)696 bk_err_t bk_pwm_group_stop(pwm_group_t group)
697 {
698 pwm_chan_t chan1;
699 pwm_chan_t chan2;
700
701 if (!pwm_group_is_existed(group))
702 return BK_OK;
703
704 chan1 = s_pwm.groups[group].chan1;
705 chan2 = s_pwm.groups[group].chan2;
706 if (pwm_hal_is_hardware_group(&s_pwm.hal, chan1, chan2))
707 pwm_hal_stop_hardware_group(&s_pwm.hal, chan1, chan2);
708
709 pwm_hal_stop_common(&s_pwm.hal, chan1);
710 pwm_hal_stop_common(&s_pwm.hal, chan2);
711 return BK_OK;
712 }
713
bk_pwm_group_set_config(pwm_group_t group,const pwm_group_config_t * config)714 bk_err_t bk_pwm_group_set_config(pwm_group_t group, const pwm_group_config_t *config)
715 {
716 return BK_OK;
717 }
718
bk_pwm_group_set_init_signal(pwm_group_t group,const pwm_group_config_t * config)719 bk_err_t bk_pwm_group_set_init_signal(pwm_group_t group, const pwm_group_config_t *config)
720 {
721 return BK_OK;
722 }
723
bk_pwm_set_mode_timer(pwm_chan_t chan)724 bk_err_t bk_pwm_set_mode_timer(pwm_chan_t chan)
725 {
726 PWM_RETURN_ON_INVALID_CHAN(chan);
727
728 pwm_hal_set_mode_timer(&s_pwm.hal, chan);
729 return BK_OK;
730 }
731
pwm_isr(void)732 static void pwm_isr(void)
733 {
734 pwm_hal_t *hal = &s_pwm.hal;
735 uint32_t int_status;
736 int chan;
737
738 int_status = pwm_hal_get_interrupt_status(hal);
739 pwm_hal_clear_interrupt_status(hal, int_status);
740 for (chan = 0; chan < SOC_PWM_CHAN_NUM_PER_UNIT; chan++) {
741 if (pwm_hal_is_interrupt_triggered(hal, chan, int_status)) {
742 if (s_pwm_isr[chan])
743 s_pwm_isr[chan](chan);
744 }
745 }
746 }
747