1 #include "bflb_pwm_v1.h"
2 #include "bflb_clock.h"
3 #include "hardware/pwm_v1_reg.h"
4 
bflb_pwm_v1_channel_init(struct bflb_device_s * dev,uint8_t ch,const struct bflb_pwm_v1_channel_config_s * config)5 void bflb_pwm_v1_channel_init(struct bflb_device_s *dev, uint8_t ch, const struct bflb_pwm_v1_channel_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 + PWM0_CONFIG_OFFSET + ch * 0x20);
14     regval |= PWM_STOP_EN;
15     putreg32(regval, reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
16 
17     start_time = bflb_mtimer_get_time_ms();
18     do {
19         regval = getreg32(reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
20         regval &= PWM_STS_TOP;
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 + PWM0_CONFIG_OFFSET + ch * 0x20);
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     putreg32(regval, reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
38 
39     regval = getreg32(reg_base + PWM0_CLKDIV_OFFSET + ch * 0x20);
40     regval &= ~PWM_CLK_DIV_MASK;
41     regval |= (uint32_t)config->clk_div << PWM_CLK_DIV_SHIFT;
42     putreg32(regval, reg_base + PWM0_CLKDIV_OFFSET + ch * 0x20);
43 
44     /* config pwm period */
45     regval = getreg32(reg_base + PWM0_PERIOD_OFFSET + ch * 0x20);
46     regval &= ~PWM_PERIOD_MASK;
47     regval |= (uint32_t)config->period << PWM_PERIOD_SHIFT;
48     putreg32(regval, reg_base + PWM0_PERIOD_OFFSET + ch * 0x20);
49 }
50 
bflb_pwm_v1_channel_deinit(struct bflb_device_s * dev,uint8_t ch)51 void bflb_pwm_v1_channel_deinit(struct bflb_device_s *dev, uint8_t ch)
52 {
53     uint32_t reg_base;
54     uint32_t regval;
55     uint64_t start_time;
56 
57     reg_base = dev->reg_base;
58     /* stop pwmx */
59     regval = getreg32(reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
60     regval |= PWM_STOP_EN;
61     putreg32(regval, reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
62 
63     start_time = bflb_mtimer_get_time_ms();
64     do {
65         regval = getreg32(reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
66         regval &= PWM_STS_TOP;
67         if ((bflb_mtimer_get_time_ms() - start_time) > 100) {
68             return;
69         }
70     } while (regval == 0);
71 
72     /* restore pwmx_clkdiv register with default value */
73     putreg32(0, reg_base + PWM0_CLKDIV_OFFSET + ch * 0x20);
74 
75     /* restore pwmx_thre1 register with default value */
76     putreg32(0, reg_base + PWM0_THRE1_OFFSET + ch * 0x20);
77 
78     /* restore pwmx_thre2 register with default value */
79     putreg32(0, reg_base + PWM0_THRE2_OFFSET + ch * 0x20);
80 
81     /* restore pwmx_period register with default value */
82     putreg32(0, reg_base + PWM0_PERIOD_OFFSET + ch * 0x20);
83 
84     /* restore pwmx_config register with default value */
85     regval = PWM_STOP_MODE;
86     putreg32(regval, reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
87 
88     /* restore pwmx_interrupt register with default value */
89     putreg32(0, reg_base + PWM0_INTERRUPT_OFFSET + ch * 0x20);
90 
91     /* clear all interrupt */
92     putreg32(0xFFFFFFFF, reg_base + PWM_INT_CONFIG_OFFSET);
93 }
94 
bflb_pwm_v1_start(struct bflb_device_s * dev,uint8_t ch)95 void bflb_pwm_v1_start(struct bflb_device_s *dev, uint8_t ch)
96 {
97     uint32_t reg_base;
98     uint32_t regval;
99     uint32_t start_time;
100 
101     reg_base = dev->reg_base;
102 
103     regval = getreg32(reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
104     regval &= ~PWM_STOP_EN;
105     putreg32(regval, reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
106 
107     start_time = bflb_mtimer_get_time_ms();
108     do {
109         regval = getreg32(reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
110         regval &= PWM_STS_TOP;
111         if ((bflb_mtimer_get_time_ms() - start_time) > 100) {
112             return;
113         }
114     } while (regval != 0);
115 }
116 
bflb_pwm_v1_stop(struct bflb_device_s * dev,uint8_t ch)117 void bflb_pwm_v1_stop(struct bflb_device_s *dev, uint8_t ch)
118 {
119     uint32_t reg_base;
120     uint32_t regval;
121     uint32_t start_time;
122 
123     reg_base = dev->reg_base;
124 
125     regval = getreg32(reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
126     regval |= PWM_STOP_EN;
127     putreg32(regval, reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
128 
129     start_time = bflb_mtimer_get_time_ms();
130     do {
131         regval = getreg32(reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
132         regval &= PWM_STS_TOP;
133         if ((bflb_mtimer_get_time_ms() - start_time) > 100) {
134             return;
135         }
136     } while (regval == 0);
137 }
138 
bflb_pwm_v1_set_period(struct bflb_device_s * dev,uint8_t ch,uint16_t period)139 void bflb_pwm_v1_set_period(struct bflb_device_s *dev, uint8_t ch, uint16_t period)
140 {
141     uint32_t reg_base;
142     uint32_t regval;
143 
144     reg_base = dev->reg_base;
145 
146     regval = getreg32(reg_base + PWM0_PERIOD_OFFSET + ch * 0x20);
147     regval &= ~PWM_PERIOD_MASK;
148     regval |= (uint32_t)period << PWM_PERIOD_SHIFT;
149     putreg32(regval, reg_base + PWM0_PERIOD_OFFSET + ch * 0x20);
150 }
151 
bflb_pwm_v1_channel_set_threshold(struct bflb_device_s * dev,uint8_t ch,uint16_t low_threhold,uint16_t high_threhold)152 void bflb_pwm_v1_channel_set_threshold(struct bflb_device_s *dev, uint8_t ch, uint16_t low_threhold, uint16_t high_threhold)
153 {
154     uint32_t reg_base;
155     uint32_t regval;
156 
157     reg_base = dev->reg_base;
158 
159     regval = getreg32(reg_base + PWM0_THRE1_OFFSET + ch * 0x20);
160     regval &= ~PWM_THRE1_MASK;
161     regval |= low_threhold;
162     putreg32(regval, reg_base + PWM0_THRE1_OFFSET + ch * 0x20);
163 
164     regval = getreg32(reg_base + PWM0_THRE2_OFFSET + ch * 0x20);
165     regval &= ~PWM_THRE2_MASK;
166     regval |= high_threhold;
167     putreg32(regval, reg_base + PWM0_THRE2_OFFSET + ch * 0x20);
168 }
169 
bflb_pwm_v1_int_enable(struct bflb_device_s * dev,uint8_t ch,bool enable)170 void bflb_pwm_v1_int_enable(struct bflb_device_s *dev, uint8_t ch, bool enable)
171 {
172     uint32_t reg_base;
173     uint32_t regval;
174 
175     reg_base = dev->reg_base;
176     regval = getreg32(reg_base + PWM0_INTERRUPT_OFFSET + ch * 0x20);
177     if (enable) {
178         regval |= PWM_INT_ENABLE;
179     } else {
180         regval &= ~PWM_INT_ENABLE;
181     }
182     putreg32(regval, reg_base + PWM0_INTERRUPT_OFFSET + ch * 0x20);
183 }
184 
bflb_pwm_v1_get_intstatus(struct bflb_device_s * dev)185 uint32_t bflb_pwm_v1_get_intstatus(struct bflb_device_s *dev)
186 {
187     uint32_t reg_base;
188     uint32_t regval;
189 
190     reg_base = dev->reg_base;
191 
192     regval = getreg32(reg_base + PWM_INT_CONFIG_OFFSET);
193     return (regval);
194 }
195 
bflb_pwm_v1_int_clear(struct bflb_device_s * dev,uint32_t int_clear)196 void bflb_pwm_v1_int_clear(struct bflb_device_s *dev, uint32_t int_clear)
197 {
198     uint32_t reg_base;
199     uint32_t regval;
200     uint32_t timeout_count = 160 * 1000;
201 
202     reg_base = dev->reg_base;
203     regval = getreg32(reg_base + PWM_INT_CONFIG_OFFSET);
204     regval |= int_clear;
205     putreg32(regval, dev->reg_base + PWM_INT_CONFIG_OFFSET);
206     do {
207         regval = getreg32(reg_base + PWM_INT_CONFIG_OFFSET);
208         timeout_count--;
209         if (timeout_count == 0) {
210             break;
211         }
212     } while (regval & (int_clear >> PWM_INT_CLEAR_SHIFT));
213 
214     regval &= ~int_clear;
215     putreg32(regval, dev->reg_base + PWM_INT_CONFIG_OFFSET);
216 }
217 
bflb_pwm_v1_feature_control(struct bflb_device_s * dev,uint8_t ch,int cmd,size_t arg)218 int bflb_pwm_v1_feature_control(struct bflb_device_s *dev, uint8_t ch, int cmd, size_t arg)
219 {
220     int ret = 0;
221     uint32_t reg_base;
222     uint32_t regval;
223 
224     reg_base = dev->reg_base;
225     switch (cmd) {
226         case PWM_CMD_SET_STOP_MODE:
227             regval = getreg32(reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
228             if (arg == PWM_STOP_MODE_ABRUPT) {
229                 regval &= ~PWM_STOP_MODE;
230             } else {
231                 regval |= PWM_STOP_MODE;
232             }
233             putreg32(regval, reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
234             break;
235 
236         case PWM_CMD_SET_OUT_INVERT:
237             regval = getreg32(reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
238             if (arg) {
239                 regval |= PWM_OUT_INV;
240             } else {
241                 regval &= ~PWM_OUT_INV;
242             }
243             putreg32(regval, reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
244             break;
245 
246         case PWM_CMD_SET_SW_MODE:
247             regval = getreg32(reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
248             if (arg) {
249                 regval |= PWM_SW_MODE;
250             } else {
251                 regval &= ~PWM_SW_MODE;
252             }
253             putreg32(regval, reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
254             break;
255 
256         case PWM_CMD_SET_SW_FORCE_VALUE:
257             regval = getreg32(reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
258             if (arg) {
259                 regval |= PWM_SW_FORCE_VAL;
260             } else {
261                 regval &= ~PWM_SW_FORCE_VAL;
262             }
263             putreg32(regval, reg_base + PWM0_CONFIG_OFFSET + ch * 0x20);
264             break;
265 
266         case PWM_CMD_SET_REPT_COUNT:
267             regval = getreg32(reg_base + PWM0_INTERRUPT_OFFSET + ch * 0x20);
268             regval &= ~(PWM_INT_PERIOD_CNT_MASK);
269             regval |= (arg << PWM_INT_PERIOD_CNT_SHIFT);
270             putreg32(regval, reg_base + PWM0_INTERRUPT_OFFSET + ch * 0x20);
271             break;
272 
273         default:
274             ret = -EPERM;
275             break;
276     }
277     return ret;
278 }