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