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