• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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