1 /*
2  * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3  */
4 
5 #include <poll.h>
6 
7 #include <aos/hal/adc.h>
8 #include <vfsdev/adc_dev.h>
9 #include <devicevfs/devicevfs.h>
10 
11 #ifdef CONFIG_ADC_NUM
12 #define PLATFORM_ADC_NUM CONFIG_ADC_NUM
13 #else
14 #define PLATFORM_ADC_NUM  4
15 #endif
16 
17 #if (PLATFORM_ADC_NUM > 0)
18 
19 // ADC device node will be named with "/dev/adc<x>", where <x> is adc port id
20 #define ADC_DEV_NAME_FORMAT "adc%d"
21 
22 typedef struct vfs_adc {
23     int ref_cnt;
24     adc_dev_t dev;
25 } vfs_adc_t;
26 
adc_device_ioctl(file_t * f,int cmd,unsigned long arg)27 int adc_device_ioctl (file_t *f, int cmd, unsigned long arg) {
28     int ret = 0;
29     io_adc_arg_t adc_arg;
30     io_adc_arg_t *p_adc_arg = NULL;
31     char *fname = f->node->i_name;
32     vfs_adc_t *vd = (vfs_adc_t *)f->node->i_arg;
33     adc_dev_t *adc_dev = &vd->dev;
34 
35     // arg is channel info
36     ddkc_dbg("cmd:0x%x, arg:0x%lx\r\n", cmd, arg);
37 
38     switch (cmd) {
39         case IOC_ADC_GET_VALUE:
40             p_adc_arg = (io_adc_arg_t *)arg;
41             BUG_ON_MSG(!p_adc_arg, "IOC_ADC_GET_VALUE - arg should not be NULL\r\n");
42             /* copy timeout config from user */
43             aos_ipc_copy(&adc_arg, p_adc_arg, sizeof(io_adc_arg_t));
44 
45             ret = hal_adc_value_get(adc_dev, &adc_arg.value, adc_arg.timeout);
46 
47             /* copy value back to user */
48             aos_ipc_copy(p_adc_arg, &adc_arg, sizeof(io_adc_arg_t));
49             ddkc_info("IOC_ADC_GET_VALUE, adc_arg.value:%d, ret:%d\r\n", adc_arg.value, ret);
50 
51             break;
52 
53         case IOC_ADC_START:
54             ddkc_dbg("IOC_ADC_START, arg:%ld\r\n", arg);
55             adc_dev->config.sampling_cycle = arg;
56             ret = vd->ref_cnt ? 0 : hal_adc_init(adc_dev);
57             if (ret) {
58                 ddkc_err("%s starts failed, port:%d, ref_cnt:%d\r\n", fname, adc_dev->port, vd->ref_cnt);
59             } else {
60                 vd->ref_cnt++;
61                 ddkc_dbg("%s starts success, port:%d, ref_cnt:%d\r\n", fname, adc_dev->port, vd->ref_cnt);
62             }
63             break;
64 
65         case IOC_ADC_STOP:
66             vd->ref_cnt--;
67             ret = vd->ref_cnt ? 0 : hal_adc_finalize(adc_dev);
68 
69             if (ret) {
70                 ddkc_err("%s stop failed, port:%d\r\n", fname, adc_dev->port);
71             } else {
72                 ddkc_dbg("%s stop success, port:%d\r\n", fname, adc_dev->port);
73             }
74 
75             break;
76 
77         default:
78             ddkc_err("invalid cmd:%d\r\n", cmd);
79             break;
80     }
81 
82     return ret;
83 }
84 
adc_device_open(inode_t * node,file_t * f)85 int adc_device_open (inode_t *node, file_t *f) {
86 
87     ddkc_info("device:%s open succeed\r\n", node->i_name);
88 
89     return 0;
90 }
91 
adc_device_close(file_t * f)92 int adc_device_close (file_t *f) {
93 
94     ddkc_info("device:%s close succeed\r\n", f->node->i_name);
95 
96     return 0;
97 }
98 
99 /************************** device ****************************/
100 
101 
102 subsys_file_ops_t adc_device_fops = {
103     .open = adc_device_open,
104     .close = adc_device_close,
105     .read = NULL,
106     .write = NULL,
107     .ioctl = adc_device_ioctl,
108     .poll = NULL,
109 };
110 
adc_device_init(struct u_platform_device * pdev)111 int adc_device_init (struct u_platform_device *pdev) {
112     // make sure 0 is returned if init operation success
113     // or aos_dev_reg procedure will break and no device node will be registered
114     ddkc_dbg("%s\r\n", __func__);
115     return 0;
116 }
117 
adc_device_deinit(struct u_platform_device * pdev)118 int adc_device_deinit (struct u_platform_device *pdev) {
119     ddkc_dbg("%s\r\n", __func__);
120     return 0;
121 }
122 
adc_device_pm(struct u_platform_device * pdev,u_pm_ops_t state)123 int adc_device_pm (struct u_platform_device *pdev, u_pm_ops_t state) {
124     ddkc_dbg("%s\r\n", __func__);
125     return 0;
126 }
127 
128 struct subsys_drv adc_device_drv = {
129     .drv_name = "adc",
130     .init = adc_device_init,
131     .deinit = adc_device_deinit,
132     .pm = adc_device_pm,
133 };
134 
135 struct subsys_dev *g_adc_device_array[PLATFORM_ADC_NUM];
136 
137 
vfs_adc_drv_init(void)138 int vfs_adc_drv_init (void) {
139     int i = 0;
140     int j = 0;
141     int ret = 0;
142     int node_name_len = 0;
143     struct subsys_dev **ppsdev = NULL;
144 
145     ddkc_dbg("adc vfs driver init starts\r\n");
146 
147     node_name_len = strlen(ADC_DEV_NAME_FORMAT) + 1;
148 
149     memset(g_adc_device_array, 0, sizeof(g_adc_device_array));
150     ppsdev = g_adc_device_array;
151 
152     for (i = 0; i < PLATFORM_ADC_NUM; i++) {
153         vfs_adc_t *vd = malloc(sizeof(vfs_adc_t));
154 
155         *ppsdev = malloc(sizeof(struct subsys_dev) + node_name_len);
156         if (!(*ppsdev) || !vd) {
157             ddkc_err("malloc failed, *ppsdev:%p, vd:%p\r\n", *ppsdev, vd);
158 
159             if (*ppsdev) {
160                 free(*ppsdev);
161                 *ppsdev = NULL;
162             }
163 
164             if (vd)
165                 free(vd);
166 
167             goto err;
168         }
169 
170         memset(*ppsdev, 0, sizeof(struct subsys_dev) + node_name_len);
171         memset(vd, 0, sizeof(*vd));
172         // vfs_adc_t's port should be remained during the whole driver life
173         vd->dev.port = i;
174 
175         (*ppsdev)->node_name = (char *)((*ppsdev) + 1);
176         snprintf((*ppsdev)->node_name, node_name_len, ADC_DEV_NAME_FORMAT, i);
177         ddkc_dbg("*ppsdev:%p, node_name:%s, (*ppsdev) + 1:%p, sizeof(struct subsys_dev):%d\r\n",
178                 *ppsdev, (*ppsdev)->node_name, (*ppsdev) + 1, sizeof(struct subsys_dev));
179         (*ppsdev)->permission = 0;
180         // please refer to definitions in enum SUBSYS_BUS_TYPE
181         (*ppsdev)->type = BUS_TYPE_PLATFORM;
182         // user_data will be passed to open operation via node->i_arg
183         (*ppsdev)->user_data = vd;
184 
185         ret = aos_dev_reg(*ppsdev, &adc_device_fops, &adc_device_drv);
186         if (ret) {
187             ddkc_err("aos_dev_reg for adc%d failed, ret:%d\r\n", i, ret);
188 
189             free(vd);
190             free(*ppsdev);
191             *ppsdev = NULL;
192             goto err;
193         }
194 
195         ppsdev++;
196     }
197 
198     ddkc_dbg("adc vfs driver init finish, ret:%d\r\n", ret);
199     return 0;
200 
201 err:
202     ppsdev = g_adc_device_array;
203     for (j = 0; j < i; j++) {
204         // shall uninstall adc devices who are already registered
205         if (*ppsdev) {
206             aos_dev_unreg(*ppsdev);
207 
208             ddkc_info("free memory for adc%d\r\n", j);
209 
210             if ((*ppsdev)->user_data)
211                 free((*ppsdev)->user_data);
212 
213             free(*ppsdev);
214             *ppsdev = NULL;
215         }
216         ppsdev++;
217     }
218     ddkc_err("adc vfs driver init failed, ret:%d\r\n", ret);
219 
220     return ret;
221 }
222 
223 VFS_DRIVER_ENTRY(vfs_adc_drv_init)
224 
225 #endif
226