1 /*
2 * Copyright (c) 2022 Talkweb Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
12 #include "hcs_macro.h"
13 #include "hdf_config_macro.h"
14 #else
15 #include "device_resource_if.h"
16 #endif
17 #include "hdf_device_desc.h"
18 #include "pwm_core.h"
19 #include "hdf_log.h"
20 #include "hdf_base_hal.h"
21 #include "stm32f4xx_ll_tim.h"
22
23 #define GPIO_STR_MAX_LENGTH 32
24
25 typedef enum {
26 PWM_CH1 = 0,
27 PWM_CH2,
28 PWM_CH3,
29 PWM_CH4,
30 PWM_CH_MAX
31 } PWM_CH;
32
33 typedef enum {
34 PWM_TIM1 = 0,
35 PWM_TIM2,
36 PWM_TIM3,
37 PWM_TIM4,
38 PWM_TIM5,
39 PWM_TIM6,
40 PWM_TIM7,
41 PWM_TIM8,
42 PWM_TIM9,
43 PWM_TIM10,
44 PWM_TIM11,
45 PWM_TIM12,
46 PWM_TIM13,
47 PWM_TIM14,
48 PWM_TIM_MAX
49 } PWM_TIM;
50
51 typedef struct {
52 PWM_CH pwmCh;
53 PWM_TIM pwmTim;
54 uint32_t prescaler;
55 uint32_t timPeroid;
56 uint32_t realHz;
57 } PwmResource;
58
59 typedef struct {
60 LL_TIM_InitTypeDef timInitStruct;
61 LL_TIM_OC_InitTypeDef timOcInitStruct;
62 } PwmConfig;
63
64 typedef struct {
65 struct IDeviceIoService ioService;
66 PwmConfig stPwmCfg;
67 struct PwmConfig *cfg;
68 PwmResource resource;
69 } PwmDevice;
70
71 typedef struct {
72 uint32_t period;
73 uint32_t duty;
74 PWM_TIM pwmCh;
75 PWM_TIM pwmTim;
76 } PwmFreqArg;
77
78 static TIM_TypeDef* g_stTimMap[PWM_TIM_MAX] = {
79 TIM1,
80 TIM2,
81 TIM3,
82 TIM4,
83 TIM5,
84 TIM6,
85 TIM7,
86 TIM8,
87 TIM9,
88 TIM10,
89 TIM11,
90 TIM12,
91 TIM13,
92 TIM14,
93 };
94
95 static uint32_t g_stChannelMap[PWM_CH_MAX] = {
96 LL_TIM_CHANNEL_CH1,
97 LL_TIM_CHANNEL_CH2,
98 LL_TIM_CHANNEL_CH3,
99 LL_TIM_CHANNEL_CH4,
100 };
101
102 static uint32_t g_stTimIrqMap[PWM_TIM_MAX] = {
103 TIM1_CC_IRQn,
104 TIM2_IRQn,
105 TIM3_IRQn,
106 TIM4_IRQn,
107 TIM5_IRQn,
108 TIM6_DAC_IRQn,
109 TIM7_IRQn,
110 TIM8_CC_IRQn,
111 TIM1_BRK_TIM9_IRQn,
112 TIM1_UP_TIM10_IRQn,
113 TIM1_TRG_COM_TIM11_IRQn,
114 TIM8_BRK_TIM12_IRQn,
115 TIM8_UP_TIM13_IRQn,
116 TIM8_TRG_COM_TIM14_IRQn,
117 };
118
119 static uint32_t g_stTimFreq[PWM_TIM_MAX] = { // tim2-tim7, tim12-tim14 is 84M,TIM1、TIM8~TIM11 is 168M
120 168000000,
121 84000000,
122 84000000,
123 84000000,
124 84000000,
125 84000000,
126 84000000,
127 168000000,
128 168000000,
129 168000000,
130 168000000,
131 84000000,
132 84000000,
133 };
134
135 #define PER_SEC_NSEC 1000000000
136
137 static int32_t PwmDevSetConfig(struct PwmDev *pwm, struct PwmConfig *config);
138 static int32_t PwmDevOpen(struct PwmDev *pwm);
139 static int32_t PwmDevClose(struct PwmDev *pwm);
140
141 struct PwmMethod g_pwmmethod = {
142 .setConfig = PwmDevSetConfig,
143 .open = PwmDevOpen,
144 .close = PwmDevClose,
145 };
146
InitPwmClock(PWM_TIM tim)147 static void InitPwmClock(PWM_TIM tim)
148 {
149 switch (tim) {
150 case PWM_TIM1:
151 LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1);
152 break;
153 case PWM_TIM2:
154 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
155 break;
156 case PWM_TIM3:
157 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);
158 break;
159 case PWM_TIM4:
160 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM4);
161 break;
162 case PWM_TIM5:
163 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM5);
164 break;
165 case PWM_TIM6:
166 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM6);
167 break;
168 case PWM_TIM7:
169 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM7);
170 break;
171 case PWM_TIM8:
172 LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM8);
173 break;
174 case PWM_TIM9:
175 LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM9);
176 break;
177 case PWM_TIM10:
178 LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM10);
179 break;
180 case PWM_TIM11:
181 LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM11);
182 break;
183 case PWM_TIM12:
184 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM12);
185 break;
186 case PWM_TIM13:
187 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM13);
188 break;
189 case PWM_TIM14:
190 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM14);
191 break;
192 default:
193 break;
194 }
195 }
196
197 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
198 #define PWM_FIND_CONFIG(node, name, resource) \
199 do { \
200 if (strcmp(HCS_PROP(node, match_attr), name) == 0) { \
201 uint8_t tim = HCS_PROP(node, pwmTim); \
202 uint8_t ch = HCS_PROP(node, pwmCh); \
203 uint8_t prescaler = HCS_PROP(node, prescaler); \
204 resource->pwmCh = ch; \
205 resource->pwmTim = tim; \
206 resource->prescaler = prescaler; \
207 result = HDF_SUCCESS; \
208 } \
209 } while (0)
210 #define PLATFORM_CONFIG HCS_NODE(HCS_ROOT, platform)
211 #define PLATFORM_PWM_CONFIG HCS_NODE(HCS_NODE(HCS_ROOT, platform), pwm_config)
GetPwmDeviceResource(PwmDevice * device,const char * deviceMatchAttr)212 static uint32_t GetPwmDeviceResource(PwmDevice *device, const char *deviceMatchAttr)
213 {
214 int32_t result = HDF_FAILURE;
215 PwmResource *resource = NULL;
216 if (device == NULL || deviceMatchAttr == NULL) {
217 HDF_LOGE("%s: device or deviceMatchAttr is NULL", __func__);
218 return HDF_ERR_INVALID_PARAM;
219 }
220 resource = &device->resource;
221 #if HCS_NODE_HAS_PROP(PLATFORM_CONFIG, pwm_config)
222 HCS_FOREACH_CHILD_VARGS(PLATFORM_PWM_CONFIG, PWM_FIND_CONFIG, deviceMatchAttr, resource);
223 #endif
224 if (result != HDF_SUCCESS) {
225 HDF_LOGE("resourceNode %s is NULL\r\n", deviceMatchAttr);
226 }
227
228 return result;
229 }
230 #else
GetPwmDeviceResource(PwmDevice * device,const struct DeviceResourceNode * resourceNode)231 static int32_t GetPwmDeviceResource(PwmDevice *device, const struct DeviceResourceNode *resourceNode)
232 {
233 struct DeviceResourceIface *dri = NULL;
234 PwmResource *resource = NULL;
235
236 if (device == NULL || resourceNode == NULL) {
237 HDF_LOGE("resource or device is NULL\r\n");
238 return HDF_ERR_INVALID_PARAM;
239 }
240
241 resource = &device->resource;
242 if (resource == NULL) {
243 HDF_LOGE("resource is NULL\r\n");
244 return HDF_ERR_INVALID_OBJECT;
245 }
246
247 dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
248 if (dri == NULL || dri->GetUint8 == NULL || dri->GetUint32 == NULL) {
249 HDF_LOGE("DeviceResourceIface is invalid\r\n");
250 return HDF_ERR_INVALID_PARAM;
251 }
252
253 if (dri->GetUint8(resourceNode, "pwmTim", &resource->pwmTim, 0) != HDF_SUCCESS) {
254 HDF_LOGE("read pwmPin fail\r\n");
255 return HDF_ERR_INVALID_PARAM;
256 }
257
258 if (resource->pwmTim == PWM_TIM6 || resource->pwmTim == PWM_TIM7) {
259 HDF_LOGE("unsupport tim\r\n");
260 return HDF_ERR_INVALID_PARAM;
261 }
262
263 if (dri->GetUint8(resourceNode, "pwmCh", &resource->pwmCh, 0) != HDF_SUCCESS) {
264 HDF_LOGE("read pwmCh fail\r\n");
265 return HDF_FAILURE;
266 }
267
268 if (dri->GetUint32(resourceNode, "prescaler", &resource->prescaler, 0) != HDF_SUCCESS) {
269 HDF_LOGE("read prescaler fail\r\n");
270 return HDF_FAILURE;
271 }
272
273 return HDF_SUCCESS;
274 }
275 #endif
276
AttachPwmDevice(struct PwmDev * host,const struct HdfDeviceObject * device)277 static int32_t AttachPwmDevice(struct PwmDev *host, const struct HdfDeviceObject *device)
278 {
279 int32_t ret;
280 PwmDevice *pwmDevice = NULL;
281 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
282 if (device == NULL || host == NULL) {
283 #else
284 if (device == NULL || device->property == NULL || host == NULL) {
285 #endif
286 HDF_LOGE("%s: param is NULL\r\n", __func__);
287 return HDF_ERR_INVALID_PARAM;
288 }
289 pwmDevice = (PwmDevice *)OsalMemAlloc(sizeof(PwmDevice));
290 if (pwmDevice == NULL) {
291 HDF_LOGE("%s: OsalMemAlloc pwmDevice error\r\n", __func__);
292 return HDF_ERR_MALLOC_FAIL;
293 }
294 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
295 ret = GetPwmDeviceResource(pwmDevice, device->deviceMatchAttr);
296 #else
297 ret = GetPwmDeviceResource(pwmDevice, device->property);
298 #endif
299 if (ret != HDF_SUCCESS) {
300 (void)OsalMemFree(pwmDevice);
301 return HDF_FAILURE;
302 }
303 host->priv = pwmDevice;
304 host->num = pwmDevice->resource.pwmTim;
305
306 return HDF_SUCCESS;
307 }
308
309 static int32_t PwmDriverBind(struct HdfDeviceObject *device);
310 static int32_t PwmDriverInit(struct HdfDeviceObject *device);
311 static void PwmDriverRelease(struct HdfDeviceObject *device);
312
313 struct HdfDriverEntry g_pwmDriverEntry = {
314 .moduleVersion = 1,
315 .moduleName = "ST_HDF_PLATFORM_PWM",
316 .Bind = PwmDriverBind,
317 .Init = PwmDriverInit,
318 .Release = PwmDriverRelease,
319 };
320 HDF_INIT(g_pwmDriverEntry);
321
322 static int32_t PwmDriverBind(struct HdfDeviceObject *device)
323 {
324 struct PwmDev *devService = NULL;
325 if (device == NULL) {
326 HDF_LOGE("hdfDevice object is null!\r\n");
327 return HDF_FAILURE;
328 }
329
330 devService = (struct PwmDev *)OsalMemCalloc(sizeof(struct PwmDev));
331 if (devService == NULL) {
332 HDF_LOGE("malloc pwmDev failed\n");
333 return HDF_ERR_MALLOC_FAIL;
334 }
335 device->service = &devService->service;
336 devService->device = device;
337
338 return HDF_SUCCESS;
339 }
340
341 static int32_t PwmDriverInit(struct HdfDeviceObject *device)
342 {
343 int32_t ret;
344 struct PwmDev *host = NULL;
345
346 if (device == NULL) {
347 HDF_LOGE("%s: device is NULL\r\n", __func__);
348 return HDF_ERR_INVALID_OBJECT;
349 }
350
351 host = (struct PwmDev *)device->service;
352 if (host == NULL) {
353 HDF_LOGE("%s: host is NULL\r\n", __func__);
354 return HDF_ERR_MALLOC_FAIL;
355 }
356
357 ret = AttachPwmDevice(host, device);
358 if (ret != HDF_SUCCESS) {
359 HDF_LOGE("%s:attach error\r\n", __func__);
360 return HDF_DEV_ERR_ATTACHDEV_FAIL;
361 }
362
363 host->method = &g_pwmmethod;
364 ret = PwmDeviceAdd(device, host);
365 if (ret != HDF_SUCCESS) {
366 PwmDeviceRemove(device, host);
367 OsalMemFree(host->device);
368 OsalMemFree(host);
369 return HDF_DEV_ERR_NO_DEVICE;
370 }
371
372 return HDF_SUCCESS;
373 }
374
375 static void PwmDriverRelease(struct HdfDeviceObject *device)
376 {
377 struct PwmDev *host = NULL;
378
379 if (device == NULL || device->service == NULL) {
380 HDF_LOGE("device is null\r\n");
381 return;
382 }
383
384 host = (struct PwmDev *)device->service;
385 if (host->device != NULL) {
386 host->method = NULL;
387 OsalMemFree(host->device);
388 OsalMemFree(host);
389 host->device = NULL;
390 host = NULL;
391 }
392
393 device->service = NULL;
394 host = NULL;
395
396 return;
397 }
398
399 static int32_t InitPwmFreqAndPeriod(const struct PwmConfig *config, PwmFreqArg* arg, const PwmResource *resource)
400 {
401 if (arg == NULL) {
402 HDF_LOGE("null ptr\r\n");
403 return HDF_FAILURE;
404 }
405
406 uint32_t freq = 0;
407 uint32_t period = 0;
408 uint32_t duty = 0;
409 uint32_t realHz = 0;
410
411 if (config->period != 0) {
412 freq = (uint32_t)(PER_SEC_NSEC / config->period);
413 } else {
414 HDF_LOGE("invalid div\r\n");
415 return HDF_FAILURE;
416 }
417
418 realHz = (uint32_t)(((double)g_stTimFreq[arg->pwmTim]) / ((double)(resource->prescaler + 1)));
419
420 if (freq != 0) {
421 period = (uint32_t)(realHz / freq);
422 } else {
423 HDF_LOGE("invalid div\r\n");
424 return HDF_FAILURE;
425 }
426
427 if (period != 0) {
428 duty = (uint32_t)(((double)config->duty / (double)config->period) * period);
429 } else {
430 HDF_LOGE("invalid div\r\n");
431 return HDF_FAILURE;
432 }
433
434 arg->period = period;
435 arg->duty = duty;
436
437 return HDF_SUCCESS;
438 }
439
440 static void InitTimPwm(const PwmFreqArg* arg, const struct PwmConfig *config,
441 PwmConfig *pwmCfg, const PwmResource *resource)
442 {
443 if (arg == NULL) {
444 HDF_LOGE("null ptr\r\n");
445 return;
446 }
447
448 pwmCfg->timInitStruct.Autoreload = arg->period - 1; // if period is 1000 20KHz/1000=20Hz,period is 50ms
449 pwmCfg->timInitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
450 pwmCfg->timInitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
451 pwmCfg->timInitStruct.Prescaler = resource->prescaler;
452 LL_TIM_Init(g_stTimMap[arg->pwmTim], &pwmCfg->timInitStruct);
453 LL_TIM_EnableARRPreload(g_stTimMap[arg->pwmTim]);
454 LL_TIM_SetClockSource(g_stTimMap[arg->pwmTim], LL_TIM_CLOCKSOURCE_INTERNAL);
455 LL_TIM_SetTriggerOutput(g_stTimMap[arg->pwmTim], LL_TIM_TRGO_RESET);
456 LL_TIM_DisableMasterSlaveMode(g_stTimMap[arg->pwmTim]);
457
458 pwmCfg->timOcInitStruct.OCMode = LL_TIM_OCMODE_PWM1; // PWM1 mode
459 pwmCfg->timOcInitStruct.OCState = LL_TIM_OCSTATE_DISABLE;
460 pwmCfg->timOcInitStruct.CompareValue = arg->duty;
461 if (config->polarity == PWM_NORMAL_POLARITY) {
462 pwmCfg->timOcInitStruct.OCPolarity = LL_TIM_OCPOLARITY_HIGH;
463 } else {
464 pwmCfg->timOcInitStruct.OCPolarity = LL_TIM_OCPOLARITY_LOW;
465 }
466 pwmCfg->timOcInitStruct.OCIdleState = LL_TIM_OCPOLARITY_LOW;
467
468 LL_TIM_OC_Init(g_stTimMap[arg->pwmTim], g_stChannelMap[arg->pwmCh], &pwmCfg->timOcInitStruct);
469 LL_TIM_OC_DisableFast(g_stTimMap[arg->pwmTim], g_stChannelMap[arg->pwmCh]);
470
471 if (arg->pwmTim == PWM_TIM1 || arg->pwmTim == PWM_TIM8) {
472 LL_TIM_BDTR_InitTypeDef bdtrInitStruct = {0};
473 bdtrInitStruct.OSSRState = LL_TIM_OSSR_DISABLE;
474 bdtrInitStruct.OSSIState = LL_TIM_OSSI_DISABLE;
475 bdtrInitStruct.LockLevel = LL_TIM_LOCKLEVEL_OFF;
476 bdtrInitStruct.DeadTime = 0; // dead area time 200ns 0x28
477 bdtrInitStruct.BreakState = LL_TIM_BREAK_ENABLE;
478 bdtrInitStruct.BreakPolarity = LL_TIM_BREAK_POLARITY_HIGH;
479 bdtrInitStruct.AutomaticOutput = LL_TIM_AUTOMATICOUTPUT_ENABLE;
480 LL_TIM_BDTR_Init(g_stTimMap[arg->pwmTim], &bdtrInitStruct);
481 }
482
483 NVIC_SetPriority(g_stTimIrqMap[arg->pwmTim], NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 1, 1));
484 NVIC_EnableIRQ(g_stTimIrqMap[arg->pwmTim]);
485
486 if (arg->pwmTim == PWM_TIM1 || arg->pwmTim == PWM_TIM8) {
487 LL_TIM_EnableAutomaticOutput(g_stTimMap[arg->pwmTim]);
488 LL_TIM_GenerateEvent_UPDATE(g_stTimMap[arg->pwmTim]);
489 }
490 LL_TIM_EnableCounter(g_stTimMap[arg->pwmTim]);
491 LL_TIM_CC_EnableChannel(g_stTimMap[arg->pwmTim], g_stChannelMap[arg->pwmCh]);
492 LL_TIM_OC_EnablePreload(g_stTimMap[arg->pwmTim], g_stChannelMap[arg->pwmCh]);
493
494 return;
495 }
496
497 static void DeInitTimPwm(PWM_TIM pwmId, PWM_CH pwmCh)
498 {
499 LL_TIM_DeInit(g_stTimMap[pwmId]);
500 LL_TIM_OC_DisableClear(g_stTimMap[pwmId], g_stChannelMap[pwmCh]);
501 NVIC_DisableIRQ(g_stTimIrqMap[pwmId]);
502
503 LL_TIM_DisableCounter(g_stTimMap[pwmId]);
504 LL_TIM_CC_DisableChannel(g_stTimMap[pwmId], g_stChannelMap[pwmCh]);
505 LL_TIM_OC_DisablePreload(g_stTimMap[pwmId], g_stChannelMap[pwmCh]);
506
507 if (pwmId == PWM_TIM1 || pwmId == PWM_TIM8) {
508 LL_TIM_DisableAutomaticOutput(g_stTimMap[pwmId]);
509 }
510
511 return;
512 }
513
514 static int32_t PwmDevSetConfig(struct PwmDev *pwm, struct PwmConfig *config)
515 {
516 PwmDevice *prvPwm = NULL;
517 PwmConfig *pwmCfg = NULL;
518 PWM_TIM pwmId;
519 PWM_CH pwmCh;
520 PwmResource *resource = NULL;
521
522 if (pwm == NULL || config == NULL || (config->period > PER_SEC_NSEC)) {
523 HDF_LOGE("%s\r\n", __FUNCTION__);
524 return HDF_FAILURE;
525 }
526
527 prvPwm = (struct PwmDevice *)PwmGetPriv(pwm);
528 if (prvPwm == NULL) {
529 return HDF_FAILURE;
530 }
531 resource = &prvPwm->resource;
532 if (resource == NULL) {
533 return HDF_FAILURE;
534 }
535 pwmCfg = &prvPwm->stPwmCfg;
536 if (pwmCfg == NULL) {
537 return HDF_FAILURE;
538 }
539 pwmId = prvPwm->resource.pwmTim;
540 pwmCh = prvPwm->resource.pwmCh;
541
542 if (config->status == PWM_ENABLE_STATUS) {
543 PwmFreqArg arg = {0};
544 arg.pwmCh = pwmCh;
545 arg.pwmTim = pwmId;
546 if (InitPwmFreqAndPeriod(config, &arg, resource) != HDF_SUCCESS) {
547 HDF_LOGE("calculate freq and period failed!\r\n");
548 return HDF_FAILURE;
549 }
550
551 InitPwmClock(pwmId);
552 InitTimPwm(&arg, config, pwmCfg, resource);
553 } else {
554 DeInitTimPwm(pwmId, pwmCh);
555 }
556
557 return HDF_SUCCESS;
558 }
559
560 static int32_t PwmDevOpen(struct PwmDev *pwm)
561 {
562 if (pwm == NULL) {
563 HDF_LOGE("%s\r\n", __FUNCTION__);
564 return HDF_ERR_INVALID_PARAM;
565 }
566
567 return HDF_SUCCESS;
568 }
569
570 static int32_t PwmDevClose(struct PwmDev *pwm)
571 {
572 PwmDevice *prvPwm = NULL;
573 PWM_TIM pwmId;
574 PWM_CH pwmCh;
575 if (pwm == NULL) {
576 HDF_LOGE("%s\r\n", __FUNCTION__);
577 return HDF_ERR_INVALID_PARAM;
578 }
579 prvPwm = (PwmDevice *)PwmGetPriv(pwm);
580 if (prvPwm == NULL) {
581 HDF_LOGE("%s\r\n", __FUNCTION__);
582 return HDF_DEV_ERR_NO_DEVICE;
583 }
584
585 pwmId = prvPwm->resource.pwmTim;
586 pwmCh = prvPwm->resource.pwmCh;
587 LL_TIM_DeInit(g_stTimMap[pwmId]);
588 LL_TIM_OC_DisableClear(g_stTimMap[pwmId], g_stChannelMap[pwmCh]);
589 NVIC_DisableIRQ(g_stTimIrqMap[pwmId]);
590
591 return HDF_SUCCESS;
592 }