• 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 #pragma once
16 
17 #include <soc/soc.h>
18 #include "pwm_hw.h"
19 #include "hal_port.h"
20 #include <driver/hal/hal_pwm_types.h>
21 
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25 
26 #define PWM_LL_REG_BASE(_pwm_unit_id) (SOC_PWM23_REG_BASE)
27 #define PWM_LL_GROUP(chan) ((chan) / SOC_PWM_CHAN_NUM_PER_GROUP)
28 #define PWM_LL_CHAN(chan) ((chan) % SOC_PWM_CHAN_NUM_PER_GROUP)
29 
30 #define PWM0_LL_PIN		8
31 #define PWM1_LL_PIN		9
32 #define PWM2_LL_PIN		24
33 #define PWM3_LL_PIN		25
34 #define PWM4_LL_PIN		32
35 #define PWM5_LL_PIN		33
36 #define PWM6_LL_PIN		34
37 #define PWM7_LL_PIN		35
38 #define PWM8_LL_PIN		36
39 #define PWM9_LL_PIN		37
40 
41 typedef enum {
42 	GROUP_CHAN0 = 0,
43 	GROUP_CHAN1 = 1,
44 } group_chan_t;
45 
pwm_ll_init(pwm_hw_t * hw)46 static inline void pwm_ll_init(pwm_hw_t *hw)
47 {
48 	for (int group = 0; group < SOC_PWM_GROUP_NUM; group++)
49 		hw->group[group].ctrl.v = 0;
50 }
51 
pwm_ll_set_enable(pwm_hw_t * hw,uint32_t group,uint32_t chan,uint32_t value)52 static inline void pwm_ll_set_enable(pwm_hw_t *hw, uint32_t group, uint32_t chan, uint32_t value)
53 {
54 	if (chan == GROUP_CHAN0)
55 		hw->group[group].ctrl.chan0_en = value;
56 	else
57 		hw->group[group].ctrl.chan1_en = value;
58 }
59 
pwm_ll_enable(pwm_hw_t * hw,uint32_t chan)60 static inline void pwm_ll_enable(pwm_hw_t *hw, uint32_t chan)
61 {
62 	pwm_ll_set_enable(hw, PWM_LL_GROUP(chan), PWM_LL_CHAN(chan), 1);
63 }
64 
pwm_ll_disable(pwm_hw_t * hw,uint32_t chan)65 static inline void pwm_ll_disable(pwm_hw_t *hw, uint32_t chan)
66 {
67 	pwm_ll_set_enable(hw, PWM_LL_GROUP(chan), PWM_LL_CHAN(chan), 0);
68 }
69 
pwm_ll_is_chan_started(pwm_hw_t * hw,uint32_t chan)70 static inline bool pwm_ll_is_chan_started(pwm_hw_t *hw, uint32_t chan)
71 {
72 	if (PWM_LL_CHAN(chan) == GROUP_CHAN0)
73 		return (hw->group[PWM_LL_GROUP(chan)].ctrl.chan0_en == 1);
74 	else
75 		return (hw->group[PWM_LL_GROUP(chan)].ctrl.chan1_en == 1);
76 }
77 
pwm_ll_set_interrupt(pwm_hw_t * hw,uint32_t group,uint32_t chan,uint32_t value)78 static inline void pwm_ll_set_interrupt(pwm_hw_t *hw, uint32_t group, uint32_t chan, uint32_t value)
79 {
80 	if (chan == GROUP_CHAN0)
81 		hw->group[group].ctrl.chan0_int_en = value;
82 	else
83 		hw->group[group].ctrl.chan1_int_en = value;
84 }
85 
pwm_ll_enable_interrupt(pwm_hw_t * hw,uint32_t chan)86 static inline void pwm_ll_enable_interrupt(pwm_hw_t *hw, uint32_t chan)
87 {
88 	pwm_ll_set_interrupt(hw, PWM_LL_GROUP(chan), PWM_LL_CHAN(chan), 1);
89 }
90 
pwm_ll_disable_interrupt(pwm_hw_t * hw,uint32_t chan)91 static inline void pwm_ll_disable_interrupt(pwm_hw_t *hw, uint32_t chan)
92 {
93 	pwm_ll_set_interrupt(hw, PWM_LL_GROUP(chan), PWM_LL_CHAN(chan), 0);
94 }
95 
96 /* If we found it impact the performance, we can rewrite it in register way!*/
pwm_ll_get_interrupt_status(pwm_hw_t * hw)97 static inline uint32_t pwm_ll_get_interrupt_status(pwm_hw_t *hw)
98 {
99 	uint32_t status = 0;
100 
101 	for (int group = 0; group < SOC_PWM_GROUP_NUM; group++) {
102 		status |= hw->group[group].ctrl.chan0_int_st << (group << 1);
103 		status |= hw->group[group].ctrl.chan1_int_st << ((group << 1) + 1);
104 	}
105 
106 	return status;
107 }
108 
pwm_ll_clear_interrupt_status(pwm_hw_t * hw,uint32_t status)109 static inline void pwm_ll_clear_interrupt_status(pwm_hw_t *hw, uint32_t status)
110 {
111 	hw->group[0].ctrl.chan0_int_st = status & BIT(0);
112 	hw->group[0].ctrl.chan1_int_st = (status >> 1) & BIT(0);
113 	hw->group[1].ctrl.chan0_int_st = (status >> 2) & BIT(0);
114 	hw->group[1].ctrl.chan1_int_st = (status >> 3) & BIT(0);
115 	hw->group[2].ctrl.chan0_int_st = (status >> 4) & BIT(0);
116 	hw->group[2].ctrl.chan1_int_st = (status >> 5) & BIT(0);
117 }
118 
pwm_ll_set_chan_interrupt_status(pwm_hw_t * hw,uint32_t group,uint32_t chan)119 static inline void pwm_ll_set_chan_interrupt_status(pwm_hw_t *hw, uint32_t group, uint32_t chan)
120 {
121 	if (chan == GROUP_CHAN0)
122 		hw->group[group].ctrl.chan0_int_st = 1;
123 	else
124 		hw->group[group].ctrl.chan1_int_st = 1;
125 }
126 
pwm_ll_clear_chan_interrupt_status(pwm_hw_t * hw,uint32_t chan)127 static inline void pwm_ll_clear_chan_interrupt_status(pwm_hw_t *hw, uint32_t chan)
128 {
129 	pwm_ll_set_chan_interrupt_status(hw, PWM_LL_GROUP(chan), PWM_LL_CHAN(chan));
130 }
131 
pwm_ll_is_interrupt_triggered(pwm_hw_t * hw,uint32_t chan,uint32_t status)132 static inline bool pwm_ll_is_interrupt_triggered(pwm_hw_t *hw, uint32_t chan, uint32_t status)
133 {
134 	return (status & BIT(chan));
135 }
136 
pwm_ll_set_mode(pwm_hw_t * hw,uint32_t chan,uint32_t mode)137 static inline void pwm_ll_set_mode(pwm_hw_t *hw, uint32_t chan, uint32_t mode)
138 {
139 	uint32_t group = PWM_LL_GROUP(chan);
140 	uint32_t group_chan = PWM_LL_CHAN(chan);
141 
142 	if (group_chan == GROUP_CHAN0)
143 		hw->group[group].ctrl.chan0_mode = mode;
144 	else
145 		hw->group[group].ctrl.chan1_mode = mode;
146 }
147 
148 #define pwm_ll_set_mode_idle(hw, chan) pwm_ll_set_mode(hw, chan, PWM_V_MODE_IDLE)
149 #define pwm_ll_set_mode_pwm(hw, chan) pwm_ll_set_mode(hw, chan, PWM_V_MODE_PWM)
150 #define pwm_ll_set_mode_timer(hw, chan) pwm_ll_set_mode(hw, chan, PWM_V_MODE_TIMER)
151 #define pwm_ll_set_mode_counter(hw, chan) pwm_ll_set_mode(hw, chan, PWM_V_MODE_COUNTER)
152 #define pwm_ll_set_mode_capture_pos(hw, chan) pwm_ll_set_mode(hw, chan, PWM_V_MODE_CAPTURE_POS)
153 #define pwm_ll_set_mode_capture_neg(hw, chan) pwm_ll_set_mode(hw, chan, PWM_V_MODE_CAPTURE_NEG)
154 #define pwm_ll_set_mode_capture_edge(hw, chan) pwm_ll_set_mode(hw, chan, PWM_V_MODE_CAPTURE_EDGE)
155 
pwm_ll_set_t4(pwm_hw_t * hw,uint32_t chan,uint32_t t4)156 static inline void pwm_ll_set_t4(pwm_hw_t *hw, uint32_t chan, uint32_t t4)
157 {
158 	hw->group[PWM_LL_GROUP(chan)].duty_cycle[PWM_LL_CHAN(chan)].t4 = t4;
159 }
160 
pwm_ll_set_t1(pwm_hw_t * hw,uint32_t chan,uint32_t t1)161 static inline void pwm_ll_set_t1(pwm_hw_t *hw, uint32_t chan, uint32_t t1)
162 {
163 	hw->group[PWM_LL_GROUP(chan)].duty_cycle[PWM_LL_CHAN(chan)].t1 = t1;
164 }
165 
pwm_ll_set_t2(pwm_hw_t * hw,uint32_t chan,uint32_t t2)166 static inline void pwm_ll_set_t2(pwm_hw_t *hw, uint32_t chan, uint32_t t2)
167 {
168 	hw->group[PWM_LL_GROUP(chan)].duty_cycle[PWM_LL_CHAN(chan)].t2 = t2;
169 }
170 
pwm_ll_set_t3(pwm_hw_t * hw,uint32_t chan,uint32_t t3)171 static inline void pwm_ll_set_t3(pwm_hw_t *hw, uint32_t chan, uint32_t t3)
172 {
173 	hw->group[PWM_LL_GROUP(chan)].duty_cycle[PWM_LL_CHAN(chan)].t3 = t3;
174 }
175 
pwm_ll_get_t1(pwm_hw_t * hw,uint32_t chan)176 static inline uint32_t pwm_ll_get_t1(pwm_hw_t *hw, uint32_t chan)
177 {
178 	return hw->group[PWM_LL_GROUP(chan)].duty_cycle[PWM_LL_CHAN(chan)].t1;
179 }
180 
pwm_ll_get_t4(pwm_hw_t * hw,uint32_t chan)181 static inline uint32_t pwm_ll_get_t4(pwm_hw_t *hw, uint32_t chan)
182 {
183 	return hw->group[PWM_LL_GROUP(chan)].duty_cycle[PWM_LL_CHAN(chan)].t4;
184 }
185 
pwm_ll_get_capture_value(pwm_hw_t * hw,uint32_t chan)186 static inline uint32_t pwm_ll_get_capture_value(pwm_hw_t *hw, uint32_t chan)
187 {
188 	uint32_t group = PWM_LL_GROUP(chan);
189 	uint32_t group_chan = PWM_LL_CHAN(chan);
190 
191 	if (group_chan == GROUP_CHAN0) {
192 		hw->group[group].cnt_read_ctrl.rd0 = 1;
193 
194 		//Wait hardware to prepare the data
195 		BK_WHILE (hw->group[group].cnt_read_ctrl.rd0);
196 
197 		return hw->group[group].cnt_or_capture_rdata[0];
198 	} else {
199 		hw->group[group].cnt_read_ctrl.rd1 = 1;
200 
201 		//Wait hardware to prepare the data
202 		BK_WHILE (hw->group[group].cnt_read_ctrl.rd1);
203 
204 		return hw->group[group].cnt_or_capture_rdata[1];
205 	}
206 }
207 
pwm_ll_is_duty_valid(uint32_t period,uint32_t duty1,uint32_t duty2,uint32_t duty3)208 static inline bool pwm_ll_is_duty_valid(uint32_t period, uint32_t duty1, uint32_t duty2,
209 										uint32_t duty3)
210 {
211 	if (period == 0)
212 		return false;
213 
214 	//Not consider (duty1 + duty2 + duty3) overflow
215 	if ((duty1 + duty2 + duty3) > period)
216 		return false;
217 
218 	//Not consier (duty2 + duty3) overflow
219 	if ((duty1 == 0) && ((duty2 + duty3) != 0))
220 		return false;
221 
222 	if ((duty2 == 0) && (duty3 != 0))
223 		return false;
224 
225 	return true;
226 }
227 
pwm_ll_is_capture_edge_valid(uint32_t edge)228 static inline bool pwm_ll_is_capture_edge_valid(uint32_t edge)
229 {
230 	return ((edge == PWM_CAPTURE_POS) || (edge == PWM_CAPTURE_NEG) || (edge == PWM_CAPTURE_EDGE));
231 }
232 
233 //TODO may need to reset more!
pwm_ll_reset_config_to_default(pwm_hw_t * hw,uint32_t chan)234 static inline void pwm_ll_reset_config_to_default(pwm_hw_t *hw, uint32_t chan)
235 {
236 	pwm_ll_set_t1(hw, chan, 0);
237 	pwm_ll_set_t2(hw, chan, 0);
238 	pwm_ll_set_t3(hw, chan, 0);
239 	pwm_ll_set_t4(hw, chan, 0);
240 }
241 
pwm_ll_load_new_config(pwm_hw_t * hw,uint32_t chan)242 static inline void pwm_ll_load_new_config(pwm_hw_t *hw, uint32_t chan)
243 {
244 	if (PWM_LL_CHAN(chan) == GROUP_CHAN0)
245 		hw->group[PWM_LL_GROUP(chan)].ctrl.chan0_cfg_update = 1;
246 	else
247 		hw->group[PWM_LL_GROUP(chan)].ctrl.chan1_cfg_update = 1;
248 }
249 
pwm_ll_set_init_signal(pwm_hw_t * hw,uint32_t group,uint32_t chan,uint32_t v)250 static inline void pwm_ll_set_init_signal(pwm_hw_t *hw, uint32_t group, uint32_t chan, uint32_t v)
251 {
252 	if (chan == GROUP_CHAN0)
253 		hw->group[group].ctrl.chan0_init_level = v;
254 	else
255 		hw->group[group].ctrl.chan1_init_level = v;
256 }
257 
pwm_ll_set_init_signal_low(pwm_hw_t * hw,uint32_t chan)258 static inline void pwm_ll_set_init_signal_low(pwm_hw_t *hw, uint32_t chan)
259 {
260 	pwm_ll_set_init_signal(hw, PWM_LL_GROUP(chan), PWM_LL_CHAN(chan), 0);
261 }
262 
pwm_ll_set_init_signal_high(pwm_hw_t * hw,uint32_t chan)263 static inline void pwm_ll_set_init_signal_high(pwm_hw_t *hw, uint32_t chan)
264 {
265 	pwm_ll_set_init_signal(hw, PWM_LL_GROUP(chan), PWM_LL_CHAN(chan), 1);
266 }
267 
pwm_ll_is_hardware_group(pwm_hw_t * hw,uint32_t chan1,uint32_t chan2)268 static inline bool pwm_ll_is_hardware_group(pwm_hw_t *hw, uint32_t chan1, uint32_t chan2)
269 {
270 	uint32_t small = chan1;
271 	uint32_t big = chan2;
272 
273 	if (chan1 > chan2) {
274 		small = chan2;
275 		big = chan1;
276 	}
277 
278 	if (((big - small) == 1) && ((small % SOC_PWM_CHAN_NUM_PER_GROUP) == 0))
279 		return true;
280 
281 	return false;
282 }
283 
284 //The caller make sure the parameters are valid!
pwm_ll_start_hardware_group(pwm_hw_t * hw,uint32_t chan1,uint32_t chan2)285 static inline void pwm_ll_start_hardware_group(pwm_hw_t *hw, uint32_t chan1, uint32_t chan2)
286 {
287 	uint32_t group = PWM_LL_GROUP(chan1);
288 
289 	hw->group[group].ctrl.group_en = 1;
290 	hw->group[group].ctrl.group_pwm_en = 1;
291 }
292 
293 //The caller make sure the parameters are valid!
pwm_ll_stop_hardware_group(pwm_hw_t * hw,uint32_t chan1,uint32_t chan2)294 static inline void pwm_ll_stop_hardware_group(pwm_hw_t *hw, uint32_t chan1, uint32_t chan2)
295 {
296 	uint32_t group = PWM_LL_GROUP(chan1);
297 
298 	hw->group[group].ctrl.group_en = 0;
299 	hw->group[group].ctrl.group_pwm_en = 0;
300 }
301 
302 #define pwm_ll_is_pwm2_interrupt(hw, chan) false
303 
304 #ifdef __cplusplus
305 }
306 #endif
307