1 /*
2 * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3 */
4
5 #include <poll.h>
6
7 #include <aos/hal/pwm.h>
8 #include <vfsdev/pwm_dev.h>
9 #include <devicevfs/devicevfs.h>
10
11 #ifdef CONFIG_PWM_NUM
12 #define PLATFORM_PWM_NUM CONFIG_PWM_NUM
13 #else
14 #define PLATFORM_PWM_NUM 4
15 #endif
16
17 #if (PLATFORM_PWM_NUM > 0)
18
19 // PWM device node will be named with "/dev/pwm<x>", where <x> is pwm port id
20 #define PWM_DEV_NAME_FORMAT "pwm%d"
21
22 typedef struct vfs_pwm {
23 bool on;
24 bool start;
25 pwm_dev_t dev;
26 } vfs_pwm_t;
27
pwm_device_ioctl(file_t * f,int cmd,unsigned long arg)28 int pwm_device_ioctl (file_t *f, int cmd, unsigned long arg) {
29 int ret = 0;
30 pwm_config_t *config = NULL;
31 vfs_pwm_t *vp = (vfs_pwm_t *)f->node->i_arg;
32 pwm_dev_t *pwm_dev = &vp->dev;
33 ddkc_info("cmd:0x%x, arg:0x%lx\r\n", cmd, arg);
34
35 switch (cmd) {
36 case IOC_PWM_ON:
37 ddkc_info("IOC_PWM_ON, arg:%ld\r\n", arg);
38 if (!vp->on) {
39 ddkc_info("before hal_pwm_init\r\n");
40 ret = hal_pwm_init(pwm_dev);
41 }
42 vp->on = ret ? false : true;
43 if (vp->on && !vp->start) {
44 ret = hal_pwm_start(pwm_dev);
45 vp->start = ret ? false : true;
46 } else
47 ddkc_warn("pwm%d is already ON\r\n", pwm_dev->port);
48
49 if (!vp->start) {
50 ddkc_err("pwm%d on failed, ret:%d\r\n", pwm_dev->port, ret);
51 }
52 break;
53 case IOC_PWM_OFF:
54 if (vp->start)
55 hal_pwm_stop(pwm_dev);
56 else
57 ddkc_warn("pwm%d is off now, ignore OFF request\r\n", pwm_dev->port);
58 // anyway, set on flag to false
59 vp->start = false;
60 ddkc_info("IOC_PWM_OFF, arg:%ld\r\n", arg);
61 break;
62 case IOC_PWM_FREQ:
63 ddkc_info("IOC_PWM_FREQ, freq:%ld\r\n", arg);
64 config = &pwm_dev->config;
65 config->freq = (unsigned int)arg;
66
67 if (vp->start) {
68 ret = hal_pwm_para_chg(pwm_dev, *config);
69 if (ret)
70 ddkc_err("change freq to %d failed, ret:%d\r\n", config->freq, ret);
71 }
72 break;
73 case IOC_PWM_DUTY_CYCLE:
74 ddkc_info("IOC_PWM_DUTY_CYCLE, duty_cycle:%ld\r\n", arg);
75 config = &pwm_dev->config;
76 aos_ipc_copy(&config->duty_cycle, (void *)arg, sizeof(float));
77
78 if (vp->start) {
79 ret = hal_pwm_para_chg(pwm_dev, *config);
80 if (ret)
81 ddkc_err("change duty cycle to %f failed, ret:%d\r\n", config->duty_cycle, ret);
82 }
83 break;
84 default:
85 ddkc_err("invalid cmd:%d\r\n", cmd);
86 break;
87 }
88
89 return ret;
90 }
91
pwm_device_open(inode_t * node,file_t * f)92 int pwm_device_open (inode_t *node, file_t *f) {
93 vfs_pwm_t *vp = (vfs_pwm_t *)f->node->i_arg;
94 pwm_dev_t *pwm_dev = &vp->dev;
95
96 ddkc_info("%s opened, port:%d\r\n", node->i_name, pwm_dev->port);
97
98 return 0;
99 }
100
pwm_device_close(file_t * f)101 int pwm_device_close (file_t *f) {
102 int ret = 0;
103 vfs_pwm_t *vp = (vfs_pwm_t *)f->node->i_arg;
104 pwm_dev_t *pwm_dev = &vp->dev;
105
106 ddkc_info("%s closed, port:%d\r\n", f->node->i_name, pwm_dev->port);
107
108 if (vp->start) {
109 ret = hal_pwm_stop(pwm_dev);
110 if (ret) {
111 ddkc_err("hal_pwm_stop on pwm%d failed, ret=%d\r\n", pwm_dev->port, ret);
112 }
113 vp->start = false;
114 }
115 if (vp->on) {
116 ret = hal_pwm_finalize(pwm_dev);
117 if (ret) {
118 ddkc_err("hal_pwm_finalize on pwm%d failed, ret=%d\r\n", pwm_dev->port, ret);
119 }
120 vp->on = false;
121 }
122
123 memset(&pwm_dev->config, 0, sizeof(pwm_dev->config));
124
125 return 0;
126 }
127
128
129 /************************** device ****************************/
130
131 subsys_file_ops_t pwm_device_fops = {
132 .open = pwm_device_open,
133 .close = pwm_device_close,
134 .read = NULL,
135 .write = NULL,
136 .ioctl = pwm_device_ioctl,
137 .poll = NULL,
138 };
139
pwm_device_init(struct u_platform_device * pdev)140 int pwm_device_init (struct u_platform_device *pdev) {
141 // make sure 0 is returned if init operation success
142 // or aos_dev_reg procedure will break and no device node will be registered
143 ddkc_dbg("%s\r\n", __func__);
144 return 0;
145 }
146
pwm_device_deinit(struct u_platform_device * pdev)147 int pwm_device_deinit (struct u_platform_device *pdev) {
148 ddkc_dbg("%s\r\n", __func__);
149 return 0;
150 }
151
pwm_device_pm(struct u_platform_device * pdev,u_pm_ops_t state)152 int pwm_device_pm (struct u_platform_device *pdev, u_pm_ops_t state) {
153 ddkc_info("%s\r\n", __func__);
154 return 0;
155 }
156
157 struct subsys_drv pwm_device_drv = {
158 .drv_name = "pwm",
159 .init = pwm_device_init,
160 .deinit = pwm_device_deinit,
161 .pm = pwm_device_pm,
162 };
163
164 struct subsys_dev *g_pwm_device_array[PLATFORM_PWM_NUM];
165
166
vfs_pwm_drv_init(void)167 int vfs_pwm_drv_init (void) {
168 int i = 0;
169 int j = 0;
170 int ret = 0;
171 int node_name_len = 0;
172 struct subsys_dev **ppsdev = NULL;
173
174 ddkc_dbg("pwm vfs driver init starts\r\n");
175
176 node_name_len = strlen(PWM_DEV_NAME_FORMAT) + 1;
177 ddkc_dbg("node_name_len:%d\r\n", node_name_len);
178
179 memset(g_pwm_device_array, 0, sizeof(g_pwm_device_array));
180 ppsdev = g_pwm_device_array;
181
182 for (i = 0; i < PLATFORM_PWM_NUM; i++) {
183 vfs_pwm_t *vp = malloc(sizeof(vfs_pwm_t));
184
185 *ppsdev = malloc(sizeof(struct subsys_dev) + node_name_len);
186 if (!(*ppsdev) || !vp) {
187 ddkc_err("malloc failed, *ppsdev:%p, vp:%p\r\n", *ppsdev, vp);
188
189 if (*ppsdev) {
190 free(*ppsdev);
191 *ppsdev = NULL;
192 }
193
194 if (vp)
195 free(vp);
196
197 goto err;
198 }
199
200 memset(*ppsdev, 0, sizeof(struct subsys_dev) + node_name_len);
201 memset(vp, 0, sizeof(*vp));
202 // vfs_pwm_t's port should be remained during the whole driver life
203 vp->dev.port = i;
204
205 (*ppsdev)->node_name = (char *)((*ppsdev) + 1);
206 snprintf((*ppsdev)->node_name, node_name_len, PWM_DEV_NAME_FORMAT, i);
207 ddkc_dbg("*ppsdev:%p, (char *)((*ppsdev) + 1):%p, node_name:%s, sizeof(struct subsys_dev):%d\r\n",
208 *ppsdev, (*ppsdev)->node_name, (char *)((*ppsdev) + 1), sizeof(struct subsys_dev));
209 (*ppsdev)->permission = 0;
210 // please refer to definitions in enum SUBSYS_BUS_TYPE
211 (*ppsdev)->type = BUS_TYPE_PLATFORM;
212 // user_data will be passed to open operation via node->i_arg
213 (*ppsdev)->user_data = vp;
214
215 ret = aos_dev_reg(*ppsdev, &pwm_device_fops, &pwm_device_drv);
216 if (ret) {
217 ddkc_err("aos_dev_reg for pwm%d failed, ret:%d\r\n", i, ret);
218
219 free(vp);
220 free(*ppsdev);
221 *ppsdev = NULL;
222
223 goto err;
224 }
225
226 ppsdev++;
227 }
228
229 ddkc_dbg("pwm vfs driver init finish, ret:%d\r\n", ret);
230 return 0;
231
232 err:
233 ddkc_info("handle pwm%d reg fail\r\n", j);
234 // shall uninstall pwm devices who are already registered
235
236 ppsdev = g_pwm_device_array;
237 for (j = 0; j < i; j++) {
238 if (*ppsdev) {
239 aos_dev_unreg(*ppsdev);
240
241 ddkc_info("free memory for pwm%d\r\n", i);
242
243 if ((*ppsdev)->user_data)
244 free((*ppsdev)->user_data);
245
246 free(*ppsdev);
247 *ppsdev = NULL;
248 }
249 ppsdev++;
250 }
251 ddkc_err("pwm vfs driver init failed, ret:%d\r\n", ret);
252
253 return ret;
254 }
255
VFS_DRIVER_ENTRY(vfs_pwm_drv_init)256 VFS_DRIVER_ENTRY(vfs_pwm_drv_init)
257
258 __weak int32_t hal_pwm_init(pwm_dev_t *tim) {
259 ddkc_info("%s\r\n", __func__);
260 return 0;
261 }
262
hal_pwm_start(pwm_dev_t * tim)263 __weak int32_t hal_pwm_start(pwm_dev_t *tim) {
264 ddkc_info("__weak %s\r\n", __func__);
265 return 0;
266 }
267
hal_pwm_stop(pwm_dev_t * tim)268 __weak int32_t hal_pwm_stop(pwm_dev_t *tim) {
269 ddkc_info("__weak %s\r\n", __func__);
270 return 0;
271 }
272
hal_pwm_para_chg(pwm_dev_t * tim,pwm_config_t para)273 __weak int32_t hal_pwm_para_chg(pwm_dev_t *tim, pwm_config_t para) {
274 ddkc_info("__weak %s\r\n", __func__);
275 return 0;
276 }
277
hal_pwm_finalize(pwm_dev_t * tim)278 __weak int32_t hal_pwm_finalize(pwm_dev_t *tim) {
279 ddkc_info("__weak %s\r\n", __func__);
280 return 0;
281 }
282
283 #endif
284