1 /**
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
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 * Description: Provides pwm driver source \n
16 *
17 * History: \n
18 * 2022-09-16, Create file. \n
19 */
20
21 #include "common_def.h"
22 #include "osal_interrupt.h"
23 #include "hal_pwm.h"
24 #include "pwm.h"
25
26 #define PWM_CYCLES_MAX_NUMBER 32767 /* Max number of PWM cycles */
27
28 static bool g_pwm_inited = false;
29 static bool g_pwm_opened[CONFIG_PWM_CHANNEL_NUM] = { false };
30 #if defined(CONFIG_PWM_USING_V151)
31 static uint16_t g_pwm_group[CONFIG_PWM_GROUP_NUM] = { 0 };
32 #endif /* CONFIG_PWM_USING_v151 */
33 static hal_pwm_funcs_t *g_hal_funcs = NULL;
34
uapi_pwm_check(uint8_t channel)35 static errcode_t uapi_pwm_check(uint8_t channel)
36 {
37 if (unlikely(channel >= CONFIG_PWM_CHANNEL_NUM)) {
38 return ERRCODE_PWM_INVALID_PARAMETER;
39 }
40
41 if (unlikely(!g_pwm_inited)) {
42 return ERRCODE_PWM_NOT_INIT;
43 }
44
45 if (unlikely(!g_pwm_opened[channel])) {
46 return ERRCODE_PWM_NOT_OPEN;
47 }
48
49 return ERRCODE_SUCC;
50 }
51
52 #if defined(CONFIG_PWM_USING_V151)
uapi_pwm_group_check(uint8_t group)53 static errcode_t uapi_pwm_group_check(uint8_t group)
54 {
55 if (unlikely(group >= CONFIG_PWM_GROUP_NUM)) {
56 return ERRCODE_PWM_INVALID_PARAMETER;
57 }
58
59 return ERRCODE_SUCC;
60 }
61
uapi_pwm_get_group(uint8_t * group,uint8_t channel)62 static errcode_t uapi_pwm_get_group(uint8_t* group, uint8_t channel)
63 {
64 uint8_t index;
65 for (index = 0; index < CONFIG_PWM_GROUP_NUM; index++) {
66 if ((g_pwm_group[index] & (uint16_t)(1 << channel)) > 0) {
67 *group = index;
68 break;
69 }
70 }
71
72 if (index == CONFIG_PWM_GROUP_NUM) {
73 return ERRCODE_PWM_INVALID_PARAMETER;
74 }
75 return ERRCODE_SUCC;
76 }
77 #endif /* CONFIG_PWM_USING_v151 */
78
uapi_pwm_init(void)79 errcode_t uapi_pwm_init(void)
80 {
81 if (g_pwm_inited) {
82 return ERRCODE_SUCC;
83 }
84
85 pwm_port_clock_enable(true);
86
87 pwm_port_register_hal_funcs();
88 g_hal_funcs = hal_pwm_get_funcs();
89 errcode_t ret = g_hal_funcs->init();
90 if (ret != ERRCODE_SUCC) {
91 return ret;
92 }
93
94 g_pwm_inited = true;
95
96 return ret;
97 }
98
uapi_pwm_deinit(void)99 void uapi_pwm_deinit(void)
100 {
101 if (!g_pwm_inited) {
102 return;
103 }
104
105 for (uint8_t channel_i = (uint8_t)PWM_0; channel_i < (uint8_t)CONFIG_PWM_CHANNEL_NUM; channel_i++) {
106 if (g_pwm_opened[channel_i]) {
107 (void)uapi_pwm_close(channel_i);
108 }
109 }
110
111 g_hal_funcs->deinit();
112
113 pwm_port_unregister_hal_funcs();
114
115 pwm_port_clock_enable(false);
116
117 g_pwm_inited = false;
118 }
119
uapi_pwm_open(uint8_t channel,const pwm_config_t * cfg)120 errcode_t uapi_pwm_open(uint8_t channel, const pwm_config_t *cfg)
121 {
122 if (unlikely(channel >= CONFIG_PWM_CHANNEL_NUM)) {
123 return ERRCODE_PWM_INVALID_PARAMETER;
124 }
125
126 if (unlikely(!g_pwm_inited)) {
127 return ERRCODE_PWM_NOT_INIT;
128 }
129 if (unlikely(g_pwm_opened[channel])) {
130 (void)uapi_pwm_close(channel);
131 }
132
133 if (unlikely(cfg->cycles > PWM_CYCLES_MAX_NUMBER)) {
134 return ERRCODE_PWM_INVALID_PARAMETER;
135 }
136 #if defined(CONFIG_PWM_USING_V151)
137 if (pwm_port_param_check(cfg) != ERRCODE_SUCC) {
138 return ERRCODE_PWM_INVALID_PARAMETER;
139 }
140 #endif
141 uint32_t id = osal_irq_lock();
142 g_hal_funcs->registerfunc((pwm_channel_t)channel, (hal_pwm_callback_t)uapi_pwm_isr);
143
144 g_hal_funcs->set_time(PWM_SET_LOW_TIME, (pwm_channel_t)channel, cfg->low_time);
145 g_hal_funcs->set_time(PWM_SET_HIGH_TIME, (pwm_channel_t)channel, cfg->high_time);
146
147 #if defined(CONFIG_PWM_USING_V151)
148 g_hal_funcs->set_time(PWM_SET_OFFSET_TIME, (pwm_channel_t)channel, cfg->offset_time);
149 #endif /* CONFIG_PWM_USING_V151 */
150
151 g_hal_funcs->set_cycles((pwm_channel_t)channel, cfg->cycles);
152
153 if (cfg->repeat) {
154 g_hal_funcs->set_action(channel, PWM_ACTION_CONTINUE_SET);
155 }
156 osal_irq_restore(id);
157
158 g_pwm_opened[channel] = true;
159 return ERRCODE_SUCC;
160 }
161
162
uapi_pwm_close(uint8_t channel)163 errcode_t uapi_pwm_close(uint8_t channel)
164 {
165 errcode_t ret;
166 ret = uapi_pwm_check(channel);
167 if (ret != ERRCODE_SUCC) {
168 return ret;
169 }
170 #if defined(CONFIG_PWM_USING_V151)
171 uint8_t close_group = 0;
172 ret = uapi_pwm_get_group(&close_group, channel);
173 if (ret != ERRCODE_SUCC) {
174 return ret;
175 }
176 #endif /* CONFIG_PWM_USING_V151 */
177
178 uint32_t id = osal_irq_lock();
179 #if defined(CONFIG_PWM_USING_V150)
180 g_hal_funcs->set_action(channel, PWM_ACTION_STOP);
181 g_hal_funcs->set_action(channel, PWM_ACTION_CONTINUE_CLR);
182 #else
183 uint16_t pre_channel_id = (uint16_t)(1 << channel);
184 uint16_t post_channel_id = g_pwm_group[close_group];
185 g_hal_funcs->set_group((pwm_v151_group_t)close_group, pre_channel_id);
186 g_hal_funcs->set_action(close_group, PWM_ACTION_STOP);
187 g_hal_funcs->set_group((pwm_v151_group_t)close_group, post_channel_id);
188 g_pwm_group[close_group] = post_channel_id;
189 #endif /* CONFIG_PWM_USING_V150 */
190 osal_irq_restore(id);
191
192 uapi_pwm_unregister_interrupt((pwm_channel_t)channel);
193
194 g_pwm_opened[channel] = false;
195
196 return ret;
197 }
198
uapi_pwm_start(uint8_t channel)199 errcode_t uapi_pwm_start(uint8_t channel)
200 {
201 errcode_t ret = ERRCODE_SUCC;
202 ret = uapi_pwm_check(channel);
203 if (ret != ERRCODE_SUCC) {
204 return ret;
205 }
206 #if defined(CONFIG_PWM_USING_V151)
207 uint8_t start_group = 0;
208 ret = uapi_pwm_get_group(&start_group, channel);
209 if (ret != ERRCODE_SUCC) {
210 return ret;
211 }
212 #endif /* CONFIG_PWM_USING_V151 */
213
214 uint32_t id = osal_irq_lock();
215 #if defined(CONFIG_PWM_USING_V150)
216 g_hal_funcs->set_action(channel, PWM_ACTION_START);
217 #else
218 uint16_t pre_channel_id = (uint16_t)(1 << channel);
219 uint16_t post_channel_id = g_pwm_group[start_group];
220 g_hal_funcs->set_group((pwm_v151_group_t)start_group, pre_channel_id);
221 g_hal_funcs->set_action(start_group, PWM_ACTION_START);
222 g_hal_funcs->set_group((pwm_v151_group_t)start_group, post_channel_id);
223 g_pwm_group[start_group] = post_channel_id;
224 #endif /* CONFIG_PWM_USING_V150 */
225 osal_irq_restore(id);
226
227 return ret;
228 }
229
uapi_pwm_get_frequency(uint8_t channel)230 uint32_t uapi_pwm_get_frequency(uint8_t channel)
231 {
232 return pwm_port_get_clock_value((pwm_channel_t)channel);
233 }
234
235 #if defined(CONFIG_PWM_USING_V150)
uapi_pwm_stop(uint8_t channel)236 errcode_t uapi_pwm_stop(uint8_t channel)
237 {
238 errcode_t ret = uapi_pwm_check(channel);
239 if (ret != ERRCODE_SUCC) {
240 return ret;
241 }
242
243 uint32_t id = osal_irq_lock();
244 g_hal_funcs->set_action(channel, PWM_ACTION_STOP);
245 osal_irq_restore(id);
246
247 return ret;
248 }
249
uapi_pwm_update_duty_ratio(uint8_t channel,uint32_t low_time,uint32_t high_time)250 errcode_t uapi_pwm_update_duty_ratio(uint8_t channel, uint32_t low_time, uint32_t high_time)
251 {
252 errcode_t ret = uapi_pwm_check(channel);
253 if (ret != ERRCODE_SUCC) {
254 return ret;
255 }
256
257 uint32_t id = osal_irq_lock();
258 g_hal_funcs->set_time(PWM_SET_LOW_TIME, (pwm_channel_t)channel, low_time);
259 g_hal_funcs->set_time(PWM_SET_HIGH_TIME, (pwm_channel_t)channel, high_time);
260 g_hal_funcs->set_action(channel, PWM_ACTION_REFRESH);
261 osal_irq_restore(id);
262
263 return ret;
264 }
265 #endif /* CONFIG_PWM_USING_V150 */
266
uapi_pwm_isr(uint8_t channel)267 errcode_t uapi_pwm_isr(uint8_t channel)
268 {
269 if (unlikely(channel >= CONFIG_PWM_CHANNEL_NUM)) {
270 return ERRCODE_PWM_INVALID_PARAMETER;
271 }
272
273 uint32_t id = osal_irq_lock();
274 g_hal_funcs->isrclear((pwm_channel_t)channel);
275 osal_irq_restore(id);
276
277 return ERRCODE_SUCC;
278 }
279
uapi_pwm_register_interrupt(uint8_t channel,pwm_callback_t callback)280 errcode_t uapi_pwm_register_interrupt(uint8_t channel, pwm_callback_t callback)
281 {
282 errcode_t ret = uapi_pwm_check(channel);
283 if (ret != ERRCODE_SUCC) {
284 return ret;
285 }
286 pwm_port_register_irq((pwm_channel_t)channel);
287
288 g_hal_funcs->registerfunc((pwm_channel_t)channel, (hal_pwm_callback_t)callback);
289
290 return ret;
291 }
292
uapi_pwm_unregister_interrupt(uint8_t channel)293 errcode_t uapi_pwm_unregister_interrupt(uint8_t channel)
294 {
295 errcode_t ret = uapi_pwm_check(channel);
296 if (ret != ERRCODE_SUCC) {
297 return ret;
298 }
299 pwm_port_unregister_irq((pwm_channel_t)channel);
300
301 g_hal_funcs->unregisterfunc((pwm_channel_t)channel);
302
303 return ret;
304 }
305
306 #if defined(CONFIG_PWM_USING_V151)
uapi_pwm_set_group(uint8_t group,const uint8_t * channel_set,uint32_t channel_set_len)307 errcode_t uapi_pwm_set_group(uint8_t group, const uint8_t *channel_set, uint32_t channel_set_len)
308 {
309 uint16_t channel_id = 0;
310 if ((group >= CONFIG_PWM_GROUP_NUM) || (channel_set == NULL) || (channel_set_len == 0)) {
311 return ERRCODE_PWM_INVALID_PARAMETER;
312 }
313
314 for (uint32_t i = 0; i < channel_set_len; i++) {
315 channel_id |= (1 << channel_set[i]);
316 }
317
318 for (uint32_t i = 0; i < CONFIG_PWM_GROUP_NUM; i++) {
319 if ((g_pwm_group[i] & channel_id) > 0) {
320 return ERRCODE_PWM_INVALID_PARAMETER;
321 }
322 }
323
324 uint32_t id = osal_irq_lock();
325 g_hal_funcs->set_group((pwm_v151_group_t)group, channel_id);
326 g_pwm_group[group] = channel_id;
327 osal_irq_restore(id);
328
329 return ERRCODE_SUCC;
330 }
331
uapi_pwm_clear_group(uint8_t group)332 errcode_t uapi_pwm_clear_group(uint8_t group)
333 {
334 if (group >= CONFIG_PWM_GROUP_NUM) {
335 return ERRCODE_PWM_INVALID_PARAMETER;
336 }
337
338 uint32_t id = osal_irq_lock();
339 g_hal_funcs->set_group((pwm_v151_group_t)group, 0);
340 g_pwm_group[group] = 0;
341 osal_irq_restore(id);
342
343 return ERRCODE_SUCC;
344 }
345
uapi_pwm_start_group(uint8_t group)346 errcode_t uapi_pwm_start_group(uint8_t group)
347 {
348 errcode_t ret = uapi_pwm_group_check(group);
349 if (ret != ERRCODE_SUCC) {
350 return ret;
351 }
352
353 uint32_t id = osal_irq_lock();
354 g_hal_funcs->set_action(group, PWM_ACTION_START);
355 osal_irq_restore(id);
356
357 return ret;
358 }
359
uapi_pwm_stop_group(uint8_t group)360 errcode_t uapi_pwm_stop_group(uint8_t group)
361 {
362 errcode_t ret = uapi_pwm_group_check(group);
363 if (ret != ERRCODE_SUCC) {
364 return ret;
365 }
366
367 uint32_t id = osal_irq_lock();
368 g_hal_funcs->set_action(group, PWM_ACTION_STOP);
369 osal_irq_restore(id);
370
371 return ret;
372 }
373
374 #if defined(CONFIG_PWM_PRELOAD)
uapi_pwm_config_preload(uint8_t group,uint8_t channel,const pwm_config_t * cfg)375 errcode_t uapi_pwm_config_preload(uint8_t group, uint8_t channel, const pwm_config_t *cfg)
376 {
377 if ((channel >= CONFIG_PWM_CHANNEL_NUM) || (group >= CONFIG_PWM_GROUP_NUM) || (cfg == NULL)) {
378 return ERRCODE_PWM_INVALID_PARAMETER;
379 }
380
381 if (unlikely(!g_pwm_inited)) {
382 return ERRCODE_PWM_NOT_INIT;
383 }
384
385 if (unlikely(cfg->cycles > PWM_CYCLES_MAX_NUMBER)) {
386 return ERRCODE_PWM_INVALID_PARAMETER;
387 }
388
389 uint32_t id = osal_irq_lock();
390 g_hal_funcs->set_time(PWM_SET_LOW_TIME, (pwm_channel_t)channel, cfg->low_time);
391 g_hal_funcs->set_time(PWM_SET_HIGH_TIME, (pwm_channel_t)channel, cfg->high_time);
392
393 g_hal_funcs->set_time(PWM_SET_OFFSET_TIME, (pwm_channel_t)channel, cfg->offset_time);
394
395 g_hal_funcs->set_cycles((pwm_channel_t)channel, cfg->cycles);
396 g_hal_funcs->config_preload(group);
397 osal_irq_restore(id);
398
399 return ERRCODE_SUCC;
400 }
401 #endif /* CONFIG_PWM_PRELOAD */
402 #endif /* CONFIG_PWM_USING_V151 */