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