1 #include "bflb_pwm_v2.h"
2 #include "bflb_clock.h"
3 #include "hardware/pwm_v2_reg.h"
4
bflb_pwm_v2_init(struct bflb_device_s * dev,const struct bflb_pwm_v2_config_s * config)5 void bflb_pwm_v2_init(struct bflb_device_s *dev, const struct bflb_pwm_v2_config_s *config)
6 {
7 uint32_t reg_base;
8 uint32_t regval;
9 uint64_t start_time;
10
11 reg_base = dev->reg_base;
12 /* stop pwm */
13 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
14 regval |= PWM_STOP_EN;
15 putreg32(regval, reg_base + PWM_MC0_CONFIG0_OFFSET);
16
17 start_time = bflb_mtimer_get_time_ms();
18 do {
19 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
20 regval &= PWM_STS_STOP;
21 if ((bflb_mtimer_get_time_ms() - start_time) > 100) {
22 return;
23 }
24 } while (regval == 0);
25
26 /* config clock source and dividor */
27 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
28 regval &= ~PWM_REG_CLK_SEL_MASK;
29 if (config->clk_source == BFLB_SYSTEM_XCLK) {
30 regval |= (0 << PWM_REG_CLK_SEL_SHIFT);
31 } else if (config->clk_source == BFLB_SYSTEM_PBCLK) {
32 regval |= (1 << PWM_REG_CLK_SEL_SHIFT);
33 } else if (config->clk_source == BFLB_SYSTEM_32K_CLK) {
34 regval |= (2 << PWM_REG_CLK_SEL_SHIFT);
35 } else {
36 }
37 regval &= ~PWM_CLK_DIV_MASK;
38 regval |= (uint32_t)config->clk_div << PWM_CLK_DIV_SHIFT;
39 putreg32(regval, reg_base + PWM_MC0_CONFIG0_OFFSET);
40
41 /* config pwm period */
42 regval = getreg32(reg_base + PWM_MC0_PERIOD_OFFSET);
43 regval &= ~PWM_PERIOD_MASK;
44 regval |= (uint32_t)config->period << PWM_PERIOD_SHIFT;
45 putreg32(regval, reg_base + PWM_MC0_PERIOD_OFFSET);
46 }
47
bflb_pwm_v2_deinit(struct bflb_device_s * dev)48 void bflb_pwm_v2_deinit(struct bflb_device_s *dev)
49 {
50 uint32_t reg_base;
51 uint32_t regval;
52 uint64_t start_time;
53
54 reg_base = dev->reg_base;
55 /* stop pwm */
56 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
57 regval |= PWM_STOP_EN;
58 putreg32(regval, reg_base + PWM_MC0_CONFIG0_OFFSET);
59
60 start_time = bflb_mtimer_get_time_ms();
61 do {
62 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
63 regval &= PWM_STS_STOP;
64 if ((bflb_mtimer_get_time_ms() - start_time) > 100) {
65 return;
66 }
67 } while (regval == 0);
68
69 /* restore pwm_mc0_config0 register with default value */
70 regval = PWM_STS_STOP | PWM_STOP_MODE | PWM_STOP_EN | PWM_ADC_TRG_SRC_MASK;
71 putreg32(regval, reg_base + PWM_MC0_CONFIG0_OFFSET);
72
73 /* restore pwm_mc0_config1 register with default value */
74 regval = PWM_CH3_NPL | PWM_CH3_PPL | PWM_CH2_NPL | PWM_CH2_PPL;
75 regval |= PWM_CH1_NPL | PWM_CH1_PPL | PWM_CH0_NPL | PWM_CH0_PPL;
76 regval |= PWM_CH3_NSI | PWM_CH2_NSI | PWM_CH1_NSI | PWM_CH0_NSI;
77 putreg32(regval, reg_base + PWM_MC0_CONFIG1_OFFSET);
78
79 /* restore pwm_mc0_period register with default value */
80 putreg32(0, reg_base + PWM_MC0_PERIOD_OFFSET);
81
82 /* restore pwm_mc0_dead_time register with default value */
83 putreg32(0, reg_base + PWM_MC0_DEAD_TIME_OFFSET);
84
85 /* restore pwm_mc0_chx_thre(x=0...3) register with default value */
86 putreg32(0, reg_base + PWM_MC0_CH0_THRE_OFFSET);
87 putreg32(1, reg_base + PWM_MC0_CH1_THRE_OFFSET);
88 putreg32(2, reg_base + PWM_MC0_CH2_THRE_OFFSET);
89 putreg32(3, reg_base + PWM_MC0_CH3_THRE_OFFSET);
90
91 /* restore pwm_mc0_int_mask register with default value */
92 putreg32(0xFFFFFFFF, reg_base + PWM_MC0_INT_MASK_OFFSET);
93 /* clear all interrupt */
94 putreg32(0xFFFFFFFF, reg_base + PWM_MC0_INT_CLEAR_OFFSET);
95 /* restore pwm_mc0_int_en register with default value */
96 putreg32(0xFFFFFFFF, reg_base + PWM_MC0_INT_EN_OFFSET);
97 }
98
bflb_pwm_v2_set_period(struct bflb_device_s * dev,uint16_t period)99 void bflb_pwm_v2_set_period(struct bflb_device_s *dev, uint16_t period)
100 {
101 uint32_t reg_base;
102 uint32_t regval;
103
104 reg_base = dev->reg_base;
105 regval = getreg32(reg_base + PWM_MC0_PERIOD_OFFSET);
106 regval &= ~PWM_PERIOD_MASK;
107 regval |= (uint32_t)period << PWM_PERIOD_SHIFT;
108 putreg32(regval, reg_base + PWM_MC0_PERIOD_OFFSET);
109 }
110
bflb_pwm_v2_start(struct bflb_device_s * dev)111 void bflb_pwm_v2_start(struct bflb_device_s *dev)
112 {
113 uint32_t reg_base;
114 uint32_t regval;
115 uint64_t start_time;
116
117 reg_base = dev->reg_base;
118 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
119 regval &= ~PWM_STOP_EN;
120 putreg32(regval, reg_base + PWM_MC0_CONFIG0_OFFSET);
121
122 start_time = bflb_mtimer_get_time_ms();
123 do {
124 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
125 regval &= PWM_STS_STOP;
126 if ((bflb_mtimer_get_time_ms() - start_time) > 100) {
127 return;
128 }
129 } while (regval != 0);
130 }
131
bflb_pwm_v2_stop(struct bflb_device_s * dev)132 void bflb_pwm_v2_stop(struct bflb_device_s *dev)
133 {
134 uint32_t reg_base;
135 uint32_t regval;
136 uint64_t start_time;
137
138 reg_base = dev->reg_base;
139 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
140 regval |= PWM_STOP_EN;
141 putreg32(regval, reg_base + PWM_MC0_CONFIG0_OFFSET);
142
143 start_time = bflb_mtimer_get_time_ms();
144 do {
145 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
146 regval &= PWM_STS_STOP;
147 if ((bflb_mtimer_get_time_ms() - start_time) > 100) {
148 return;
149 }
150 } while (regval == 0);
151 }
152
bflb_pwm_v2_get_frequency(struct bflb_device_s * dev)153 float bflb_pwm_v2_get_frequency(struct bflb_device_s *dev)
154 {
155 uint32_t reg_base;
156 uint32_t regval;
157 uint32_t tmp;
158 float src, div, period;
159
160 reg_base = dev->reg_base;
161 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
162 /* get clock source frequency */
163 tmp = (regval & PWM_REG_CLK_SEL_MASK) >> PWM_REG_CLK_SEL_SHIFT;
164 switch (tmp) {
165 case 0:
166 src = (float)bflb_clk_get_system_clock(0); /* TODO: because this function has not been implemented */
167 break;
168 case 1:
169 src = (float)bflb_clk_get_system_clock(1); /* TODO: because this function has not been implemented */
170 break;
171 case 2:
172 src = (float)bflb_clk_get_system_clock(2); /* TODO: because this function has not been implemented */
173 break;
174 default:
175 src = 0.0f;
176 break;
177 }
178 /* get clock dividor */
179 tmp = (regval & PWM_CLK_DIV_MASK) >> PWM_CLK_DIV_SHIFT;
180 div = tmp ? (float)tmp : 1.0f;
181 /* get pwm period count */
182 regval = getreg32(reg_base + PWM_MC0_PERIOD_OFFSET);
183 tmp = (regval & PWM_PERIOD_MASK) >> PWM_PERIOD_SHIFT;
184 period = (float)tmp;
185 /* calculate freaueny */
186 return (src / div / period);
187 }
188
bflb_pwm_v2_channel_init(struct bflb_device_s * dev,uint8_t ch,struct bflb_pwm_v2_channel_config_s * config)189 void bflb_pwm_v2_channel_init(struct bflb_device_s *dev, uint8_t ch, struct bflb_pwm_v2_channel_config_s *config)
190 {
191 uint32_t reg_base;
192 uint32_t regval;
193
194 reg_base = dev->reg_base;
195 regval = getreg32(reg_base + PWM_MC0_CONFIG1_OFFSET);
196 if (config->positive_polarity == PWM_POLARITY_ACTIVE_LOW) {
197 regval &= ~(PWM_CH0_PPL << ch * 2);
198 } else {
199 regval |= (PWM_CH0_PPL << ch * 2);
200 }
201 if (config->negative_polarity == PWM_POLARITY_ACTIVE_LOW) {
202 regval &= ~(PWM_CH0_NPL << ch * 2);
203 } else {
204 regval |= (PWM_CH0_NPL << ch * 2);
205 }
206 if (config->positive_stop_state == PWM_STATE_ACTIVE) {
207 regval |= (PWM_CH0_PSI << ch * 4);
208 } else {
209 regval &= ~(PWM_CH0_PSI << ch * 4);
210 }
211 if (config->negative_stop_state == PWM_STATE_INACTIVE) {
212 regval &= ~(PWM_CH0_NSI << ch * 4);
213 } else {
214 regval |= (PWM_CH0_NSI << ch * 4);
215 }
216 if (config->positive_brake_state == PWM_STATE_ACTIVE) {
217 regval |= (PWM_CH0_PBS << ch * 2);
218 } else {
219 regval &= ~(PWM_CH0_PBS << ch * 2);
220 }
221 if (config->negative_brake_state == PWM_STATE_ACTIVE) {
222 regval |= (PWM_CH0_NBS << ch * 2);
223 } else {
224 regval &= ~(PWM_CH0_NBS << ch * 2);
225 }
226 putreg32(regval, reg_base + PWM_MC0_CONFIG1_OFFSET);
227 regval = getreg32(reg_base + PWM_MC0_DEAD_TIME_OFFSET);
228 regval &= ~(PWM_CH0_DTG_MASK << ch * 8);
229 regval |= ((uint32_t)config->dead_time << ch * 8);
230 putreg32(regval, reg_base + PWM_MC0_DEAD_TIME_OFFSET);
231 }
232
bflb_pwm_v2_channel_set_threshold(struct bflb_device_s * dev,uint8_t ch,uint16_t low_threhold,uint16_t high_threhold)233 void bflb_pwm_v2_channel_set_threshold(struct bflb_device_s *dev, uint8_t ch, uint16_t low_threhold, uint16_t high_threhold)
234 {
235 uint32_t regval;
236
237 regval = ((uint32_t)high_threhold << 16) | low_threhold;
238 putreg32(regval, dev->reg_base + PWM_MC0_CH0_THRE_OFFSET + ch * 4);
239 }
240
bflb_pwm_v2_channel_positive_start(struct bflb_device_s * dev,uint8_t ch)241 void bflb_pwm_v2_channel_positive_start(struct bflb_device_s *dev, uint8_t ch)
242 {
243 uint32_t reg_base;
244 uint32_t regval;
245
246 reg_base = dev->reg_base;
247 regval = getreg32(reg_base + PWM_MC0_CONFIG1_OFFSET);
248 regval |= (PWM_CH0_PEN << 4 * ch);
249 putreg32(regval, reg_base + PWM_MC0_CONFIG1_OFFSET);
250 }
251
bflb_pwm_v2_channel_negative_start(struct bflb_device_s * dev,uint8_t ch)252 void bflb_pwm_v2_channel_negative_start(struct bflb_device_s *dev, uint8_t ch)
253 {
254 uint32_t reg_base;
255 uint32_t regval;
256
257 reg_base = dev->reg_base;
258 regval = getreg32(reg_base + PWM_MC0_CONFIG1_OFFSET);
259 regval |= (PWM_CH0_NEN << 4 * ch);
260 putreg32(regval, reg_base + PWM_MC0_CONFIG1_OFFSET);
261 }
262
bflb_pwm_v2_channel_positive_stop(struct bflb_device_s * dev,uint8_t ch)263 void bflb_pwm_v2_channel_positive_stop(struct bflb_device_s *dev, uint8_t ch)
264 {
265 uint32_t reg_base;
266 uint32_t regval;
267
268 reg_base = dev->reg_base;
269 regval = getreg32(reg_base + PWM_MC0_CONFIG1_OFFSET);
270 regval &= ~(PWM_CH0_PEN << 4 * ch);
271 putreg32(regval, reg_base + PWM_MC0_CONFIG1_OFFSET);
272 }
273
bflb_pwm_v2_channel_negative_stop(struct bflb_device_s * dev,uint8_t ch)274 void bflb_pwm_v2_channel_negative_stop(struct bflb_device_s *dev, uint8_t ch)
275 {
276 uint32_t reg_base;
277 uint32_t regval;
278
279 reg_base = dev->reg_base;
280 regval = getreg32(reg_base + PWM_MC0_CONFIG1_OFFSET);
281 regval &= ~(PWM_CH0_NEN << 4 * ch);
282 putreg32(regval, reg_base + PWM_MC0_CONFIG1_OFFSET);
283 }
284
bflb_pwm_v2_int_enable(struct bflb_device_s * dev,uint32_t int_en,bool enable)285 void bflb_pwm_v2_int_enable(struct bflb_device_s *dev, uint32_t int_en, bool enable)
286 {
287 uint32_t reg_base;
288 uint32_t regval_mask, regval_en;
289
290 reg_base = dev->reg_base;
291 regval_mask = getreg32(reg_base + PWM_MC0_INT_MASK_OFFSET);
292 regval_en = getreg32(reg_base + PWM_MC0_INT_EN_OFFSET);
293 if (enable) {
294 regval_mask &= ~int_en;
295 regval_en |= int_en;
296 } else {
297 regval_mask |= int_en;
298 regval_en &= ~int_en;
299 }
300 putreg32(regval_mask, reg_base + PWM_MC0_INT_MASK_OFFSET);
301 putreg32(regval_en, reg_base + PWM_MC0_INT_EN_OFFSET);
302 }
303
bflb_pwm_v2_int_clear(struct bflb_device_s * dev,uint32_t int_clear)304 void bflb_pwm_v2_int_clear(struct bflb_device_s *dev, uint32_t int_clear)
305 {
306 putreg32(int_clear, dev->reg_base + PWM_MC0_INT_CLEAR_OFFSET);
307 }
308
bflb_pwm_v2_get_intstatus(struct bflb_device_s * dev)309 uint32_t bflb_pwm_v2_get_intstatus(struct bflb_device_s *dev)
310 {
311 uint32_t reg_base;
312 uint32_t regval_sts, regval_mask, regval_en;
313
314 reg_base = dev->reg_base;
315 regval_sts = getreg32(reg_base + PWM_MC0_INT_STS_OFFSET);
316 regval_mask = getreg32(reg_base + PWM_MC0_INT_MASK_OFFSET);
317 regval_en = getreg32(reg_base + PWM_MC0_INT_EN_OFFSET);
318 return (regval_sts & ~regval_mask & regval_en);
319 }
320
bflb_pwm_v2_feature_control(struct bflb_device_s * dev,int cmd,size_t arg)321 int bflb_pwm_v2_feature_control(struct bflb_device_s *dev, int cmd, size_t arg)
322 {
323 int ret = 0;
324 uint32_t reg_base;
325 uint32_t regval;
326
327 reg_base = dev->reg_base;
328 switch (cmd) {
329 case PWM_CMD_SET_EXT_BRAKE_POLARITY:
330 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
331 if (arg == PWM_POLARITY_ACTIVE_HIGH) {
332 regval |= PWM_EXT_BREAK_PL;
333 } else {
334 regval &= ~PWM_EXT_BREAK_PL;
335 }
336 putreg32(regval, reg_base + PWM_MC0_CONFIG0_OFFSET);
337 break;
338
339 case PWM_CMD_SET_EXT_BRAKE_ENABLE:
340 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
341 if (arg == true) {
342 regval |= PWM_EXT_BREAK_EN;
343 } else {
344 regval &= ~PWM_EXT_BREAK_EN;
345 }
346 putreg32(regval, reg_base + PWM_MC0_CONFIG0_OFFSET);
347 break;
348
349 case PWM_CMD_SET_SW_BRAKE_ENABLE:
350 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
351 if (arg == true) {
352 regval |= PWM_SW_BREAK_EN;
353 } else {
354 regval &= ~PWM_SW_BREAK_EN;
355 }
356 putreg32(regval, reg_base + PWM_MC0_CONFIG0_OFFSET);
357 break;
358
359 case PWM_CMD_SET_STOP_ON_REPT:
360 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
361 if (arg == true) {
362 regval |= PWM_STOP_ON_REPT;
363 } else {
364 regval &= ~PWM_STOP_ON_REPT;
365 }
366 putreg32(regval, reg_base + PWM_MC0_CONFIG0_OFFSET);
367 break;
368
369 case PWM_CMD_SET_REPT_COUNT:
370 regval = getreg32(reg_base + PWM_MC0_PERIOD_OFFSET);
371 regval &= ~(PWM_INT_PERIOD_CNT_MASK);
372 regval |= (arg << PWM_INT_PERIOD_CNT_SHIFT);
373 putreg32(regval, reg_base + PWM_MC0_PERIOD_OFFSET);
374 break;
375
376 case PWM_CMD_SET_TRIG_ADC_SRC:
377 regval = getreg32(reg_base + PWM_MC0_CONFIG0_OFFSET);
378 regval &= ~(PWM_ADC_TRG_SRC_MASK);
379 regval |= (arg << PWM_ADC_TRG_SRC_SHIFT);
380 putreg32(regval, reg_base + PWM_MC0_CONFIG0_OFFSET);
381 break;
382
383 default:
384 ret = -EPERM;
385 break;
386 }
387 return ret;
388 }
389