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