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 }