1 /*
2 * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3 */
4
5 #include <poll.h>
6
7 #include <aos/driver/i2c.h>
8 #include <vfsdev/i2c_dev.h>
9 #include <devicevfs/devicevfs.h>
10
11 #ifdef CONFIG_I2C_NUM
12 #define PLATFORM_I2C_NUM CONFIG_I2C_NUM
13 #else
14 #define PLATFORM_I2C_NUM 4
15 #endif
16
17 #if (PLATFORM_I2C_NUM > 0)
18 // I2C device node will be named with "/dev/i2c<x>", where <x> is i2c port id
19 #define I2C_DEV_NAME_FORMAT "i2c%d"
20
21 typedef struct vfs_i2c {
22 unsigned port;
23 } vfs_i2c_t;
24
25 /**
26 * allocate memory for copy i2c_config_t
27 * @param dst pointer to destinatin struct
28 * @param src pointer to source struct
29 * @return 0 for success; negative for failure
30 */
_copy_i2c_control_arg(io_i2c_control_u * dst,io_i2c_control_u * src)31 static int _copy_i2c_control_arg (io_i2c_control_u *dst, io_i2c_control_u *src) {
32 if (!dst || !src) {
33 return -EINVAL;
34 }
35 aos_ipc_copy(dst, src, sizeof(io_i2c_control_u));
36
37 return 0;
38 }
39
40 /**
41 * allocate memory for copy io_i2c_data_t, data field in io_i2c_data_t is also included
42 * @param dst pointer to destinatin struct
43 * @param src pointer to source struct
44 * @return 0 for success; negative for failure
45 */
_alloc_i2c_data_arg(io_i2c_data_t * dst,io_i2c_data_t * src)46 static int _alloc_i2c_data_arg (io_i2c_data_t *dst, io_i2c_data_t *src) {
47 if (!dst || !src) {
48 return -EINVAL;
49 }
50
51 aos_ipc_copy(dst, src, sizeof(io_i2c_data_t));
52 if (!dst->data || !dst->length) {
53 return -EINVAL;
54 }
55
56 dst->data = malloc(dst->length);
57 if (!dst->data)
58 return -ENOMEM;
59
60 return 0;
61 }
62
63 /**
64 * copy io_i2c_data_t's data field
65 * @param dst pointer to destinatin struct
66 * @param src pointer to source struct
67 * @return 0 for success; negative for failure
68 */
_copy_i2c_data_field(io_i2c_data_t * dst,io_i2c_data_t * src)69 static int _copy_i2c_data_field (io_i2c_data_t *dst, io_i2c_data_t *src) {
70 io_i2c_data_t tmp;
71 unsigned char *data = NULL;
72
73 if (!dst || !src) {
74 return -EINVAL;
75 }
76 tmp.data = NULL;
77
78 aos_ipc_copy(&tmp, dst, sizeof(io_i2c_data_t));
79
80 data = tmp.data;
81 if (!data || !tmp.length || !src->data || !src->length || (tmp.length != src->length)) {
82 ddkc_err("invalid arg, dst[data:%p, length:%d], src[data:%p, length:%d]",
83 data, tmp.length, src->data, src->length);
84 return -EINVAL;
85 }
86
87 aos_ipc_copy(data, src->data, src->length);
88
89 return 0;
90 }
91
92 /**
93 * copy io_i2c_data_t's content, data included
94 * @param dst pointer to destinatin struct
95 * @param src pointer to source struct
96 * @return 0 for success; negative for failure
97 */
_copy_i2c_data_arg(io_i2c_data_t * dst,io_i2c_data_t * src)98 static int _copy_i2c_data_arg (io_i2c_data_t *dst, io_i2c_data_t *src) {
99 unsigned char *data = NULL;
100
101 if (!dst || !src) {
102 return -1;
103 }
104
105 aos_ipc_copy(dst, src, sizeof(io_i2c_data_t));
106
107 data = dst->data;
108 if (!data || !dst->length)
109 return 0;
110
111 dst->data = malloc(dst->length);
112 if (!dst->data)
113 return -ENOMEM;
114
115 aos_ipc_copy(dst->data, data, dst->length);
116
117 return 0;
118 }
119
_free_i2c_data_arg(io_i2c_data_t * dst)120 static int _free_i2c_data_arg (io_i2c_data_t *dst) {
121 if (!dst || !dst->data)
122 return -EINVAL;
123
124 free(dst->data);
125
126 return 0;
127 }
128
i2c_device_ioctl(file_t * f,int cmd,unsigned long arg)129 int i2c_device_ioctl (file_t *f, int cmd, unsigned long arg) {
130 int ret = 0;
131 io_i2c_data_t *d = NULL;
132 io_i2c_control_u *c = NULL;
133 vfs_i2c_t *vd = (vfs_i2c_t *)f->node->i_arg;
134 i2c_dev_handle_t slave = (i2c_dev_handle_t)f->f_arg;
135
136 // VFS make sure ioctl on the same fd is sequenced, so big-lock is not necessary
137 ddkc_dbg("cmd:0x%x, arg:0x%lx\r\n", cmd, arg);
138
139 switch (cmd) {
140 case IOC_I2C_SET_FREQ:
141 ddkc_dbg("IOC_I2C_SET_FREQ\r\n");
142 c = (io_i2c_control_u *)arg;
143 ret = aos_i2c_clk_set(slave, c->freq);
144 if (ret) {
145 ddkc_err("set clock to i2c%d failed, ret:%d\r\n", c->freq, ret);
146 }
147 break;
148
149 case IOC_I2C_SET_CONFIG:
150 ddkc_dbg("IOC_I2C_SET_CONFIG\r\n");
151
152 c = (io_i2c_control_u *)arg;
153 if (!c->c.role) {
154 ret = -EINVAL;
155 ddkc_err("i2c%d only support master mode\r\n", c->freq);
156 }
157
158 ret = aos_i2c_slave_addr_set(slave, c->c.addr);
159 if (ret) {
160 ddkc_err("set slave address:0x%x to i2c%d failed, ret:%d\r\n", c->c.addr, ret);
161 }
162
163 ret += aos_i2c_addr_width_set(slave, c->c.addr_width ? I2C_SLAVE_ADDR_WIDTH_10BIT : I2C_SLAVE_ADDR_WIDTH_7BIT);
164 if (ret) {
165 ddkc_err("set slave address:0x%x to i2c%d failed, ret:%d\r\n", c->c.addr, ret);
166 }
167 break;
168
169 case IOC_I2C_MASTER_RX:
170 ddkc_dbg("IOC_I2C_MASTER_RX\r\n");
171
172 d = (io_i2c_data_t *)arg;
173
174 ret = aos_i2c_slave_addr_set(slave, d->addr);
175 if (ret) {
176 ddkc_err("set slave address:0x%x to i2c%d failed, ret:%d\r\n", c->c.addr, ret);
177 return ret;
178 }
179
180 ret = aos_i2c_master_recv(slave, d->data, d->length, d->timeout);
181 if (ret != d->length) {
182 ddkc_err("i2c%d rx failed, tx_buffer:%p, d->length:%d, d->timeout:%d, ret:%d\n",
183 vd->port, d->data, d->length, d->timeout, ret);
184 ret = -EIO;
185 } else {
186 ddkc_dbg("i2c%d rx succeed, tx_buffer:%p, d->length:%d, d->timeout:%d\n",
187 vd->port, d->data, d->length, d->timeout);
188 ret = 0;
189 }
190 break;
191 case IOC_I2C_MASTER_TX:
192 ddkc_dbg("IOC_I2C_MASTER_TX\r\n");
193
194 d = (io_i2c_data_t *)arg;
195
196 ret = aos_i2c_slave_addr_set(slave, d->addr);
197 if (ret) {
198 ddkc_err("set slave address:0x%x to i2c%d failed, ret:%d\r\n", c->c.addr, ret);
199 return ret;
200 }
201
202 ret = aos_i2c_master_send(slave, d->data, d->length, d->timeout);
203 if (ret != d->length) {
204 ddkc_err("i2c%d tx failed, tx_buffer:%p, d->length:%d, d->timeout:%d, ret:%d\n",
205 vd->port, d->data, d->length, d->timeout, ret);
206 ret = -EIO;
207 } else {
208 ddkc_dbg("i2c%d tx succeed, tx_buffer:%p, d->length:%d, d->timeout:%d\n",
209 vd->port, d->data, d->length, d->timeout);
210 ret = 0;
211 }
212 break;
213 case IOC_I2C_SLAVE_RX:
214 ddkc_dbg("IOC_I2C_SLAVE_RX\r\n");
215 ddkc_err("i2c slave operation is not supported\r\n");
216 ret = -ENOTSUP;
217 break;
218 case IOC_I2C_SLAVE_TX:
219 ddkc_dbg("IOC_I2C_SLAVE_TX\r\n");
220 ddkc_err("i2c slave operation is not supported\r\n");
221 ret = -ENOTSUP;
222 break;
223 case IOC_I2C_MEM_RX:
224 ddkc_dbg("IOC_I2C_MEM_RX\r\n");
225 d = (io_i2c_data_t *)arg;
226
227 ret = aos_i2c_slave_addr_set(slave, d->addr);
228 if (ret) {
229 ddkc_err("set slave address:0x%x to i2c%d failed, ret:%d\r\n", c->c.addr, ret);
230 return ret;
231 }
232
233 ret = aos_i2c_mem_read(slave, d->maddr, d->mlength, d->data, d->length, d->timeout);
234 if (ret != d->length) {
235 ddkc_err("i2c%d memory rx failed, mem_addr:0x%x, addr_len:%d, tx_buffer:%p, d->length:%d, d->timeout:%d, ret:%d\n",
236 vd->port, d->maddr, d->mlength, d->data, d->length, d->timeout, ret);
237 ret = -EIO;
238 } else {
239 ddkc_dbg("i2c%d memory rx succeed, mem_addr:0x%x, addr_len:%d, tx_buffer:%p, d->length:%d, d->timeout:%d\n",
240 vd->port, d->maddr, d->mlength, d->data, d->length, d->timeout);
241 ret = 0;
242 }
243 break;
244 case IOC_I2C_MEM_TX:
245 ddkc_dbg("IOC_I2C_MEM_TX\r\n");
246 d = (io_i2c_data_t *)arg;
247
248 ret = aos_i2c_slave_addr_set(slave, d->addr);
249 if (ret) {
250 ddkc_err("set slave address:0x%x to i2c%d failed, ret:%d\r\n", c->c.addr, ret);
251 return ret;
252 }
253
254 ret = aos_i2c_mem_write(slave, d->maddr, d->mlength, d->data, d->length, d->timeout);
255 if (ret != d->length) {
256 ddkc_err("i2c%d memory tx failed, mem_addr:0x%x, addr_len:%d, tx_buffer:%p, d->length:%d, d->timeout:%d, ret:%d\n",
257 vd->port, d->maddr, d->mlength, d->data, d->length, d->timeout, ret);
258 ret = -EIO;
259 } else {
260 ddkc_dbg("i2c%d memory tx succeed, mem_addr:0x%x, addr_len:%d, tx_buffer:%p, d->length:%d, d->timeout:%d\n",
261 vd->port, d->maddr, d->mlength, d->data, d->length, d->timeout);
262 ret = 0;
263 }
264 break;
265 default:
266 ddkc_err("invalid cmd:%d\r\n", cmd);
267 break;
268 }
269
270 return ret;
271 }
272
i2c_device_open(inode_t * node,file_t * f)273 int i2c_device_open (inode_t *node, file_t *f) {
274 vfs_i2c_t *vd = (vfs_i2c_t *)node->i_arg;
275 i2c_dev_handle_t slave = NULL;
276 i2c_slave_config_t config;
277
278 config.addr = 0x0; // set to 0x0 by default
279 config.addr_width = I2C_SLAVE_ADDR_WIDTH_7BIT; // set to 7-bit address mode by default
280 config.clk = I2C_BUS_CLK_100K; // set to 100k by default
281
282 slave = aos_i2c_open(vd->port, &config);
283 if (!slave) {
284 printf("i2c%d open failed\r\n", vd->port);
285 return -1;
286 }
287
288 f->f_arg = slave;
289
290 ddkc_dbg("device:%s open success\r\n", node->i_name);
291
292 return 0;
293 }
294
i2c_device_close(file_t * f)295 int i2c_device_close (file_t *f) {
296 int ret = -1;
297 vfs_i2c_t *vd = (vfs_i2c_t *)f->node->i_arg;
298 i2c_dev_handle_t slave = (i2c_dev_handle_t)f->f_arg;
299
300 if (slave) {
301 ret = aos_i2c_close(slave);
302 if (ret) {
303 printf("i2c%d close failed, ret:%d\r\n", vd->port, ret);
304 }
305 f->f_arg = NULL;
306 } else {
307 ddkc_warn("invalid f_arg:%x\r\n", slave);
308 };
309
310 ddkc_dbg("device:%s close success\r\n", f->node->i_name);
311
312 return 0;
313 }
314
315
316 /************************** device ****************************/
317
318
319 subsys_file_ops_t i2c_device_fops = {
320 .open = i2c_device_open,
321 .close = i2c_device_close,
322 .read = NULL,
323 .write = NULL,
324 .ioctl = i2c_device_ioctl,
325 .poll = NULL,
326 };
327
i2c_device_init(struct u_platform_device * pdev)328 int i2c_device_init (struct u_platform_device *pdev) {
329 // make sure 0 is returned if init operation success
330 // or aos_dev_reg procedure will break and no device node will be registered
331 ddkc_dbg("%s\r\n", __func__);
332 return 0;
333 }
334
i2c_device_deinit(struct u_platform_device * pdev)335 int i2c_device_deinit (struct u_platform_device *pdev) {
336 ddkc_dbg("%s\r\n", __func__);
337 return 0;
338 }
339
i2c_device_pm(struct u_platform_device * pdev,u_pm_ops_t state)340 int i2c_device_pm (struct u_platform_device *pdev, u_pm_ops_t state) {
341 ddkc_dbg("%s\r\n", __func__);
342 return 0;
343 }
344
345 struct subsys_drv i2c_device_drv = {
346 .drv_name = "i2c",
347 .init = i2c_device_init,
348 .deinit = i2c_device_deinit,
349 .pm = i2c_device_pm,
350 };
351
352 struct subsys_dev *g_i2c_device_array[PLATFORM_I2C_NUM];
353
354
vfs_i2c_drv_init(void)355 int vfs_i2c_drv_init (void) {
356 int i = 0;
357 int j = 0;
358 int ret = 0;
359 int node_name_len = 0;
360 struct subsys_dev **ppsdev = NULL;
361
362 ddkc_dbg("i2c vfs driver init starts\r\n");
363
364 node_name_len = strlen(I2C_DEV_NAME_FORMAT) + 1;
365 ddkc_dbg("node_name_len:%d\r\n", node_name_len);
366
367 memset(g_i2c_device_array, 0, sizeof(g_i2c_device_array));
368 ppsdev = g_i2c_device_array;
369
370 for (i = 0; i < PLATFORM_I2C_NUM; i++) {
371 vfs_i2c_t *vd = malloc(sizeof(vfs_i2c_t));
372
373 *ppsdev = malloc(sizeof(struct subsys_dev) + node_name_len);
374 if (!(*ppsdev) || !vd) {
375 ddkc_info("malloc failed, *ppsdev:%p, vd:%p\r\n", *ppsdev, vd);
376
377 if (*ppsdev) {
378 free(*ppsdev);
379 *ppsdev = NULL;
380 }
381
382 if (vd)
383 free(vd);
384
385 goto err;
386 }
387
388 memset(*ppsdev, 0, sizeof(struct subsys_dev) + node_name_len);
389 memset(vd, 0, sizeof(*vd));
390 // vfs_i2c_t's port should be remained during the whole driver life
391 vd->port = i;
392
393 (*ppsdev)->node_name = (char *)((*ppsdev) + 1);
394 snprintf((*ppsdev)->node_name, node_name_len, I2C_DEV_NAME_FORMAT, i);
395 ddkc_dbg("*ppsdev:%p, node_name:%s, (*ppsdev) + 1:%p, sizeof(struct subsys_dev):%d\r\n",
396 *ppsdev, (*ppsdev)->node_name, (*ppsdev) + 1, sizeof(struct subsys_dev));
397 (*ppsdev)->permission = 0;
398 // please refer to definitions in enum SUBSYS_BUS_TYPE
399 (*ppsdev)->type = BUS_TYPE_PLATFORM;
400 // user_data will be passed to open operation via node->i_arg
401 (*ppsdev)->user_data = vd;
402
403 ret = aos_dev_reg(*ppsdev, &i2c_device_fops, &i2c_device_drv);
404 if (ret) {
405 ddkc_err("aos_dev_reg for i2c%d failed, ret:%d\r\n", i, ret);
406
407 free(vd);
408 free(*ppsdev);
409 *ppsdev = NULL;
410
411 goto err;
412 }
413
414 ppsdev++;
415 }
416
417 ddkc_dbg("i2c vfs driver init finish, ret:%d\r\n", ret);
418 return 0;
419
420 err:
421 ppsdev = g_i2c_device_array;
422 for (j = 0; j < i; j++) {
423 // shall uninstall i2c devices who are already registered
424
425 if (*ppsdev) {
426 aos_dev_unreg(*ppsdev);
427
428 ddkc_info("free memory for i2c%d\r\n", i);
429
430 if ((*ppsdev)->user_data)
431 free((*ppsdev)->user_data);
432
433 free(*ppsdev);
434 *ppsdev = NULL;
435 }
436 ppsdev++;
437 }
438 ddkc_err("i2c vfs driver init failed, ret:%d\r\n", ret);
439
440 return ret;
441 }
442
443 VFS_DRIVER_ENTRY(vfs_i2c_drv_init)
444
445
446 #endif
447