1 /*
2 * Copyright (c) 2022 Hunan OpenValley Digital Industry Development Co., Ltd.
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
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include "hcs_macro.h"
19 #include "hdf_config_macro.h"
20 #include "hdf_device_desc.h"
21 #include "pwm_if.h"
22 #include "pwm_core.h"
23 #include "hdf_log.h"
24 #include "driver/mcpwm.h"
25 #include "driver/ledc.h"
26
27 #define PERIOD_NUM 1000000000
28 #define PERIOD2FREQUENCY(period) (PERIOD_NUM / (period))
29 #define MCPWM_GENERATOR(cmpr) ((cmpr) % 2)
30 #define NUM_8192 8192
31 #define GET_ESP_DUTY_CYCLE_PERCENT(duty, period) (int)(NUM_8192 * (1.0 * (duty) / (period)))
32
33 #define UNIT_MAX_OUTPUT 6 // 每个PWM单元最大输出的个数
34 #define CONFIG_2_PWM_NUM(unit, signal_port) (((unit)*UNIT_MAX_OUTPUT) + (signal_port))
35 #define PWM_NUM_2_CONFIG(pwm_num, unit, signal_port) \
36 do { \
37 (unit) = (pwm_num) / UNIT_MAX_OUTPUT; \
38 (signal_port) = (pwm_num) % UNIT_MAX_OUTPUT; \
39 } while (0)
40
41 typedef struct _PwmDeviceConfig {
42 int channel;
43 int pwm_timer;
44 int freq_hz;
45 int gpio_pin;
46 ledc_timer_config_t ledc_timer_config;
47 ledc_channel_config_t ledc_channel_config;
48 } PwmDeviceConfig;
49
50 static int32_t PwmDevSetConfig(struct PwmDev *pwm, struct PwmConfig *config);
51 static int32_t PwmDevOpen(struct PwmDev *pwm);
52 static int32_t PwmDevClose(struct PwmDev *pwm);
53
54 struct PwmMethod g_pwmmethod = {
55 .setConfig = PwmDevSetConfig,
56 .open = PwmDevOpen,
57 .close = PwmDevClose,
58 };
59
60 #define PLATFORM_CONFIG HCS_NODE(HCS_ROOT, platform)
61 #define PLATFORM_PWM_CONFIG HCS_NODE(HCS_NODE(HCS_ROOT, platform), pwm_config)
62
63 #define PWM_FIND_CONFIG(node, name, resource) \
64 do { \
65 if (strcmp(HCS_PROP(node, match_attr), name) == 0) { \
66 (resource)->channel = GetChannelFromStr(HCS_PROP(node, channel)); \
67 (resource)->pwm_timer = GetTimerFromStr(HCS_PROP(node, timer)); \
68 (resource)->freq_hz = HCS_PROP(node, freq_hz); \
69 (resource)->gpio_pin = GetPinIndexFromStr(HCS_PROP(node, gpio_pin)); \
70 (resource)->ledc_timer_config.duty_resolution = LEDC_TIMER_13_BIT; \
71 (resource)->ledc_timer_config.clk_cfg = LEDC_AUTO_CLK; \
72 (resource)->ledc_timer_config.timer_num = (resource)->pwm_timer; \
73 (resource)->ledc_timer_config.speed_mode = LEDC_LOW_SPEED_MODE; \
74 (resource)->ledc_channel_config.channel = (resource)->channel; \
75 (resource)->ledc_channel_config.gpio_num = (resource)->gpio_pin; \
76 (resource)->ledc_channel_config.speed_mode = LEDC_LOW_SPEED_MODE; \
77 (resource)->ledc_channel_config.hpoint = 0; \
78 (resource)->ledc_channel_config.timer_sel = (resource)->pwm_timer; \
79 HDF_LOGD("<---------- %s ------------>", name); \
80 HDF_LOGD("channel = %s [%d]", HCS_PROP(node, channel), (resource)->channel); \
81 HDF_LOGD("pwm_timer = %s [%d]", HCS_PROP(node, timer), (resource)->pwm_timer); \
82 HDF_LOGD("freq_hz = %dHz", (resource)->freq_hz); \
83 HDF_LOGD("gpio_pin = %s [%d]", HCS_PROP(node, gpio_pin), (resource)->gpio_pin); \
84 result = HDF_SUCCESS; \
85 } \
86 } while (0)
87
88 #define NUM_10 10
89
GetPinIndexFromStr(const char * str)90 static int GetPinIndexFromStr(const char *str)
91 {
92 if (str == NULL || strlen(str) < 10) {
93 HDF_LOGE("pin index config is illegal!");
94 return GPIO_NUM_NC;
95 }
96
97 char *ptr_nun = &str[9];
98 int level = strlen(ptr_nun); // 获取下标位数
99 int pin_index = 0; // GPIO号
100 for (int i = 0; i < level; i++) {
101 if (i != 0) {
102 pin_index = NUM_10 * pin_index;
103 }
104 int num = ptr_nun[i] - '0';
105 if (num >= NUM_10) { // 字符非法
106 HDF_LOGE("pin index config is illegal!");
107 return GPIO_NUM_NC;
108 }
109 pin_index += num;
110 }
111 return pin_index;
112 }
113
GetTimerFromStr(const char * str)114 static int GetTimerFromStr(const char *str)
115 {
116 if (!strcmp(str, "LEDC_TIMER_0")) {
117 return LEDC_TIMER_0;
118 } else if (!strcmp(str, "LEDC_TIMER_1")) {
119 return LEDC_TIMER_1;
120 } else if (!strcmp(str, "LEDC_TIMER_2")) {
121 return LEDC_TIMER_2;
122 } else if (!strcmp(str, "LEDC_TIMER_3")) {
123 return LEDC_TIMER_3;
124 }
125 HDF_LOGE("pwm_timer is illegal! must be LEDC_TIMER_0-LEDC_TIMER_03.");
126 return LEDC_TIMER_MAX;
127 }
128
GetChannelFromStr(const char * str)129 static int GetChannelFromStr(const char *str)
130 {
131 if (!strcmp(str, "LEDC_CHANNEL_0")) {
132 return LEDC_CHANNEL_0;
133 } else if (!strcmp(str, "LEDC_CHANNEL_1")) {
134 return LEDC_CHANNEL_1;
135 } else if (!strcmp(str, "LEDC_CHANNEL_2")) {
136 return LEDC_CHANNEL_2;
137 } else if (!strcmp(str, "LEDC_CHANNEL_3")) {
138 return LEDC_CHANNEL_3;
139 } else if (!strcmp(str, "LEDC_CHANNEL_4")) {
140 return LEDC_CHANNEL_4;
141 } else if (!strcmp(str, "LEDC_CHANNEL_5")) {
142 return LEDC_CHANNEL_5;
143 } else if (!strcmp(str, "LEDC_CHANNEL_6")) {
144 return LEDC_CHANNEL_6;
145 } else if (!strcmp(str, "LEDC_CHANNEL_7")) {
146 return LEDC_CHANNEL_7;
147 }
148 HDF_LOGE("channel is illegal! must be LEDC_CHANNEL 0-7.");
149 return LEDC_CHANNEL_MAX;
150 }
151
GetPwmDeviceResource(PwmDeviceConfig * device,const char * deviceMatchAttr)152 static uint32_t GetPwmDeviceResource(PwmDeviceConfig *device, const char *deviceMatchAttr)
153 {
154 int32_t result = HDF_FAILURE;
155 if (device == NULL || deviceMatchAttr == NULL) {
156 HDF_LOGE("%s: device or deviceMatchAttr is NULL", __func__);
157 return HDF_ERR_INVALID_PARAM;
158 }
159
160 HCS_FOREACH_CHILD_VARGS(PLATFORM_PWM_CONFIG, PWM_FIND_CONFIG, deviceMatchAttr, device);
161
162 if (result != HDF_SUCCESS) {
163 HDF_LOGE("resourceNode %s is NULL\r\n", deviceMatchAttr);
164 }
165
166 return result;
167 }
168
AttachPwmDevice(struct PwmDev * host,struct HdfDeviceObject * device)169 static int32_t AttachPwmDevice(struct PwmDev *host, struct HdfDeviceObject *device)
170 {
171 int32_t ret;
172 PwmDeviceConfig *pwmDevice = NULL;
173 if (device == NULL || host == NULL) {
174 HDF_LOGE("%s: param is NULL\r\n", __func__);
175 return HDF_ERR_INVALID_PARAM;
176 }
177 pwmDevice = (PwmDeviceConfig *)OsalMemAlloc(sizeof(PwmDeviceConfig));
178 if (pwmDevice == NULL) {
179 HDF_LOGE("%s: OsalMemAlloc pwmDevice error\r\n", __func__);
180 return HDF_ERR_MALLOC_FAIL;
181 }
182 ret = GetPwmDeviceResource(pwmDevice, device->deviceMatchAttr);
183 if (ret != HDF_SUCCESS) {
184 (void)OsalMemFree(pwmDevice);
185 return HDF_FAILURE;
186 }
187
188 PwmSetPriv(host, pwmDevice);
189 host->num = pwmDevice->channel;
190
191 return HDF_SUCCESS;
192 }
193
194 static int32_t PwmDriverBind(struct HdfDeviceObject *device);
195 static int32_t PwmDriverInit(struct HdfDeviceObject *device);
196 static void PwmDriverRelease(struct HdfDeviceObject *device);
197
198 struct HdfDriverEntry g_pwmDriverEntry = {
199 .moduleVersion = 1,
200 .moduleName = "ESP32U4_HDF_PLATFORM_PWM",
201 .Bind = PwmDriverBind,
202 .Init = PwmDriverInit,
203 .Release = PwmDriverRelease,
204 };
205 HDF_INIT(g_pwmDriverEntry);
206
PwmDriverBind(struct HdfDeviceObject * device)207 static int32_t PwmDriverBind(struct HdfDeviceObject *device)
208 {
209 struct PwmDev *devService = NULL;
210 if (device == NULL) {
211 HDF_LOGE("hdfDevice object is null!\r\n");
212 return HDF_FAILURE;
213 }
214
215 devService = (struct PwmDev *)OsalMemCalloc(sizeof(struct PwmDev));
216 if (devService == NULL) {
217 HDF_LOGE("malloc pwmDev failed\n");
218 }
219 device->service = &devService->service;
220 devService->device = device;
221
222 return HDF_SUCCESS;
223 }
224
PwmDriverInit(struct HdfDeviceObject * device)225 static int32_t PwmDriverInit(struct HdfDeviceObject *device)
226 {
227 int32_t ret;
228 struct PwmDev *host = NULL;
229
230 if (device == NULL) {
231 HDF_LOGE("%s: device is NULL\r\n", __func__);
232 return HDF_ERR_INVALID_OBJECT;
233 }
234
235 host = (struct PwmDev *)device->service;
236 if (host == NULL) {
237 HDF_LOGE("%s: host is NULL\r\n", __func__);
238 return HDF_ERR_MALLOC_FAIL;
239 }
240
241 ret = AttachPwmDevice(host, device);
242 if (ret != HDF_SUCCESS) {
243 HDF_LOGE("%s:attach error\r\n", __func__);
244 return HDF_DEV_ERR_ATTACHDEV_FAIL;
245 }
246
247 host->method = &g_pwmmethod;
248 ret = PwmDeviceAdd(device, host);
249 if (ret != HDF_SUCCESS) {
250 PwmDeviceRemove(device, host);
251 OsalMemFree(host->device);
252 OsalMemFree(host);
253 return HDF_DEV_ERR_NO_DEVICE;
254 }
255
256 return HDF_SUCCESS;
257 }
258
PwmDriverRelease(struct HdfDeviceObject * device)259 static void PwmDriverRelease(struct HdfDeviceObject *device)
260 {
261 struct PwmDev *host = NULL;
262 if (device == NULL || device->service == NULL) {
263 HDF_LOGE("device is null\r\n");
264 return;
265 }
266 host = (struct PwmDev *)device->service;
267 if (host != NULL && host->device != NULL) {
268 host->method = NULL;
269 OsalMemFree(host->device);
270 OsalMemFree(host);
271 host->device = NULL;
272 host = NULL;
273 }
274 device->service = NULL;
275 host = NULL;
276 return;
277 }
278
PwmDevSetConfig(struct PwmDev * pwm,struct PwmConfig * config)279 static int32_t PwmDevSetConfig(struct PwmDev *pwm, struct PwmConfig *config)
280 {
281 int ret;
282 if (pwm == NULL || config == NULL) {
283 HDF_LOGE("%s: PwmDev* pwm or struct PwmConfig *config is NULL!", __FUNCTION__);
284 return HDF_ERR_INVALID_PARAM;
285 }
286 PwmDeviceConfig *pwmDevice = (PwmDeviceConfig *)PwmGetPriv(pwm);
287 if (pwmDevice == NULL) {
288 HDF_LOGE("%s: PwmDeviceConfig* pwmDevice is NULL", __FUNCTION__);
289 return HDF_ERR_INVALID_PARAM;
290 }
291 if (config->status == PWM_ENABLE_STATUS) { // 使能PWM
292 if (pwmDevice->ledc_timer_config.freq_hz != PERIOD2FREQUENCY(config->period)) { // 周期有频率变化
293 pwmDevice->ledc_timer_config.freq_hz = PERIOD2FREQUENCY(config->period);
294 ledc_timer_config(&pwmDevice->ledc_timer_config); // 重新配置周期
295 printf("\r\n------->config freq_hz = %d [period = %d]\r\n",
296 pwmDevice->ledc_timer_config.freq_hz, config->period);
297 printf("speed_mode = %d\r\n", pwmDevice->ledc_timer_config.speed_mode);
298 printf("timer_num = %d\r\n", pwmDevice->ledc_timer_config.timer_num);
299 printf("clk_cfg = %d\r\n", pwmDevice->ledc_timer_config.clk_cfg);
300 printf("duty_resolution = %d\r\n", pwmDevice->ledc_timer_config.duty_resolution);
301 }
302 if (pwmDevice->ledc_channel_config.duty != GET_ESP_DUTY_CYCLE_PERCENT(config->duty, config->period)) {
303 pwmDevice->ledc_channel_config.duty = GET_ESP_DUTY_CYCLE_PERCENT(config->duty, config->period);
304 printf("\r\n------->config ledc_duty = %d [duty=%d <--> period=%d]\r\n",
305 pwmDevice->ledc_channel_config.duty, config->duty, config->period);
306 printf("gpio_num = %d\r\n", pwmDevice->ledc_channel_config.gpio_num);
307 printf("speed_mode = %d\r\n", pwmDevice->ledc_channel_config.speed_mode);
308 printf("channel = %d\r\n", pwmDevice->ledc_channel_config.channel);
309 printf("timer_sel = %d\r\n", pwmDevice->ledc_channel_config.timer_sel);
310 printf("hpoint = %d\r\n", pwmDevice->ledc_channel_config.hpoint);
311 }
312 } else if (config->status == PWM_DISABLE_STATUS) { // 失能PWM
313 ledc_stop(pwmDevice->ledc_timer_config.speed_mode, pwmDevice->channel, config->polarity);
314 printf("------->pwm output stop, set level = %d\r\n", config->polarity);
315 }
316 return HDF_SUCCESS;
317 }
318
PwmDevOpen(struct PwmDev * pwm)319 static int32_t PwmDevOpen(struct PwmDev *pwm)
320 {
321 if (pwm == NULL) {
322 HDF_LOGE("%s: PwmDev* pwm is NULL", __FUNCTION__);
323 return HDF_ERR_INVALID_PARAM;
324 }
325
326 PwmDeviceConfig *pwmDevice = (PwmDeviceConfig *)PwmGetPriv(pwm);
327 if (pwmDevice == NULL) {
328 HDF_LOGE("%s: PwmDeviceConfig* pwmDevice is NULL", __FUNCTION__);
329 return HDF_ERR_INVALID_PARAM;
330 }
331 return HDF_SUCCESS;
332 }
333
PwmDevClose(struct PwmDev * pwm)334 static int32_t PwmDevClose(struct PwmDev *pwm)
335 {
336 HDF_LOGI("——> Enter %s", __FUNCTION__);
337 return HDF_SUCCESS;
338 }