【摘要】本文以PowerPC+Linux 2.6.25 平台为例,详细分析了I2C总线的驱动架构。首先介绍了I2C的总体架构,从用户的角度将其分为三个层面,不同的开发者只需要关注相应的层面即可。然后分析了主要数据结构及其之间的相互关系,接着分析了不同层的具体实现,最后以一款EEPEOM为例讲述了如何在用户空间访问I2C驱动。对于ARM + Linux平台,只有平台依赖层即总线适配器驱动有差异。
【关键字】PowerPC, I2C, i2c-core, adapter , i2c_algorithm, RTC, EEPROM
目录
1 I2C概述 3
2 I2C总体架构 3
2.1 硬件抽象层 3
2.2 平台依赖层 3
2.3 用户接口层 3
3 主要的数据结构 4
3.1 Adapter 4
3.2 I2c_algorithm 5
3.3 i2c_driver 5
3.4 Client 6
4 平台依赖层-总线适配器驱动 7
4.1 platform device 7
4.2 platform driver 9
4.3 Adapter及algorithm 12
5 硬件抽象层-I2C core 13
5.1 总线初始化 13
5.2 Adapter注册 15
5.3 驱动注册 16
5.4 数据传输 17
6 用户接口层-I2C设备驱动 18
6.1 统一的设备模型 18
6.1.1 关键数据结构 18
6.1.2 初始化 19
6.1.3 Open及release 21
6.1.4 数据收发 22
6.2 特定的设备驱动 26
6.2.1 关键数据结构 26
6.2.2 初始化 27
6.2.3 数据收发 29
7 驱动访问示例 29
7.1.1 写操作 29
7.1.2 读操作 31
8 参考鸣谢 33
1 I2C概述
I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL。I2C是一种多主机控制总线,同一总线上可允许多个master,即总线上的设备都有主动发起数据传输的可能,依靠线与逻辑来实现无损仲裁。但通常情况是总线上有个带CPU的master,其他设备被master访问。
2 I2C总体架构
在2.6的Linux内核中,I2C的驱动架构分为如下三个层次:硬件抽象层、平台依赖层和用户接口层。
2.1 硬件抽象层
i2c-core.h和i2c-core.c为其主体框架代码,提供了核心数据结构的定义、i2c适配器驱动和设备驱动的注册、注销管理等API。其为硬件平台无关层,向下屏蔽了物理总线适配器的差异,定义了统一的访问策略和接口;其向上提供了统一的接口,以便I2C设备驱动通过总线适配器进行数据收发。
2.2 平台依赖层
i2c总线适配器(adapter)就是一条i2c总线的控制器(所谓控制是相对于本CPU来说的),在物理上连接若干i2c设备。在Linux驱动中,每种处理器平台有自己的适配器驱动,属于平台移植相关层。每一个特定的硬件平台在i2c/busses/目录下都有一个adapter的实现,对于PowerPC平台来说,其是i2c-mpc.c。其按照核心层定义的接口实现了i2c_adapter,提供了具体的访问方式i2c_algorithm。
2.3 用户接口层
设备驱动层为用户接口层,其为用户提供了通过I2C总线访问具体设备的接口。
3 主要的数据结构
3.1 Adapter
Adapter是对某一条I2C总线的抽象,是特定总线的相关属性的集合。
http://lxr.linux.no/#linux+v2.6.25/include/linux/i2c.h#L312
312struct i2c_adapter {
313 struct module *owner;
314 unsigned int id;
315 unsigned int class;
316 const struct i2c_algorithm *algo; /* the algorithm to access the bus */
317 void *algo_data;
318
319 /* --- administration stuff. */
320 int (*client_register)(struct i2c_client *);
321 int (*client_unregister)(struct i2c_client *);
322
323 /* data fields that are valid for all devices */
324 u8 level; /* nesting level for lockdep */
325 struct mutex bus_lock; //
326 struct mutex clist_lock;
327
328 int timeout;
329 int retries;
330 struct device dev; /* the adapter device */
331
332 int nr; /*该成员描述了总线号*/
333 struct list_head clients; /* i2c_client结构链表,该结构包含device,driver和 adapter结构*/
334 char name[48];
335 struct completion dev_released;
336};
Algo是和底层硬件的接口,标识了具体的物理总线传输的实现。
Clients为使用该总线的client链表。
Nr为该适配器也就是某条I2C总线占据的全局编号。
bus_lock总线的互斥锁,防止总线冲突。
3.2 I2c_algorithm
http://lxr.linux.no/#linux+v2.6.25/include/linux/i2c.h#L291
291struct i2c_algorithm {
292 /* If an adapter algorithm can't do I2C-level access, set master_xfer
293 to NULL. If an adapter algorithm can do SMBus access, set
294 smbus_xfer. If set to NULL, the SMBus protocol is simulated
295 using common I2C messages */
296 /* master_xfer should return the number of messages successfully
297 processed, or a negative value on error */
298 int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs,
299 int num);
300 int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
301 unsigned short flags, char read_write,
302 u8 command, int size, union i2c_smbus_data * data);
303
304 /* To determine what the adapter supports */
305 u32 (*functionality) (struct i2c_adapter *);
306};
主要就是master_xfer方法,其和具体的总线控制器相关,不同的CPU在实现上可能有差异。
3.3 i2c_driver
http://lxr.linux.no/#linux+v2.6.25/include/linux/i2c.h#L105
105struct i2c_driver {
106 int id;
107 unsigned int class;
108
109 /* Notifies the driver that a new bus has appeared. This routine
110 * can be used by the driver to test if the bus meets its conditions
111 * & seek for the presence of the chip(s) it supports. If found, it
112 * registers the client(s) that are on the bus to the i2c admin. via
113 * i2c_attach_client. (LEGACY I2C DRIVERS ONLY)
114 */
115 int (*attach_adapter)(struct i2c_adapter *);
116 int (*detach_adapter)(struct i2c_adapter *);
117
118 /* tells the driver that a client is about to be deleted & gives it
119 * the chance to remove its private data. Also, if the client struct
120 * has been dynamically allocated by the driver in the function above,
121 * it must be freed here. (LEGACY I2C DRIVERS ONLY)
122 */
123 int (*detach_client)(struct i2c_client *);
124
125 /* Standard driver model interfaces, for "new style" i2c drivers.
126 * With the driver model, device enumeration is NEVER done by drivers;
127 * it's done by infrastructure. (NEW STYLE DRIVERS ONLY)
128 */
129 int (*probe)(struct i2c_client *);
130 int (*remove)(struct i2c_client *);
131
132 /* driver model interfaces that don't relate to enumeration */
133 void (*shutdown)(struct i2c_client *);
134 int (*suspend)(struct i2c_client *, pm_message_t mesg);
135 int (*resume)(struct i2c_client *);
136
137 /* a ioctl like command that can be used to perform specific functions
138 * with the device.
139 */
140 int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
141
142 struct device_driver driver;
143};
Driver是为device服务的,i2c_driver注册时会扫描i2c bus上的设备,进行驱动和设备的绑定。主要有两种接口attach_adapter和probe,二者分别针对旧的和新式的驱动。
3.4 Client
http://lxr.linux.no/#linux+v2.6.25/include/linux/i2c.h#L168
168struct i2c_client {
169 unsigned short flags; /* div., see below */
170 unsigned short addr; /* chip address - NOTE: 7bit */
171 /* addresses are stored in the */
172 /* _LOWER_ 7 bits */
173 char name[I2C_NAME_SIZE];
174 struct i2c_adapter *adapter; /* the adapter we sit on */
175 struct i2c_driver *driver; /* and our access routines */
176 struct device dev; /* the device structure */
177 int irq; /* irq issued by device (or -1) */
178 char driver_name[KOBJ_NAME_LEN];
179 struct list_head list; /* DEPRECATED */
180 struct completion released;
181};
通常来说i2c_client对应着I2C总线上某个特定的slave或者是user space的某个用户对应,而此时的slave可以动态变化。
4 平台依赖层-总线适配器驱动
总线适配器驱动,本质上就是实现了具体的总线传输算法并向核心层注册了适配器。主要分为三个层面,platform device,platform driver及与I2C core的接口层。
Linux内核的所有适配器驱动程序都在driver/i2c/busses/目录下, MPC8xxx驱动是i2c-mpc.c。
4.1 platform device
2.6内核中硬件资源的注册都采用了platform device的机制。对于PowerPC来说,其硬件资源是通过DTS来描述的。
i2c@3000 {
#address-cells = <1>;
#size-cells = <0>;
cell-index = <0>;
compatible = "fsl-i2c";
reg = <0x3000 0x100>;
interrupts = <14 0x8>;
interrupt-parent = <&ipic>;
dfsrr;
};
i2c@3100 {
#address-cells = <1>;
#size-cells = <0>;
cell-index = <1>;
compatible = "fsl-i2c";
reg = <0x3100 0x100>;
interrupts = <15 0x8>;
interrupt-parent = <&ipic>;
dfsrr;
rtc@51 { //legacy I2C device,静态定义
device_type = "rtc";
compatible = "Philips,8563"; //设备类型
reg = <0x51>; //I2C地址
};
};
中断号及寄存器的基地址等信息会在设备树中描述了,此后只需利用platform_get_resource等标准接口自动获取即可,实现了驱动和资源的分离。cell-index标识了总线编号,也就是adapter的编号。
随后在系统启动阶段会解析DTB文件,将相关资源注册到Platform bus上。
http://lxr.linux.no/#linux+v2.6.25/arch/powerpc/sysdev/fsl_soc.c#L454
458static int __init fsl_i2c_of_init(void)
501 of_register_i2c_devices(np, i++);
429static void __init of_register_i2c_devices(struct device_node *adap_node,
430 int bus_num)
431{
432 struct device_node *node = NULL;
433
434 while ((node = of_get_next_child(adap_node, node))) {
435 struct i2c_board_info info = {};
436 const u32 *addr;
437 int len;
438
439 addr = of_get_property(node, "reg", &len);
440 if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) {
441 printk(KERN_WARNING "fsl_soc.c: invalid i2c device entry/n");
442 continue;
443 }
444
445 info.irq = irq_of_parse_and_map(node, 0);
446 if (info.irq == NO_IRQ)
447 info.irq = -1;
448
449 if (of_find_i2c_driver(node, &info) < 0)
450 continue;
451
452 info.addr = *addr;
453
454 i2c_register_board_info(bus_num, &info, 1);
455 }
456}
397static struct i2c_driver_device i2c_devices[] __initdata = {
398 {"ricoh,rs5c372a", "rtc-rs5c372", "rs5c372a",},
399 {"ricoh,rs5c372b", "rtc-rs5c372", "rs5c372b",},
400 {"ricoh,rv5c386", "rtc-rs5c372", "rv5c386",},
401 {"ricoh,rv5c387a", "rtc-rs5c372", "rv5c387a",},
402 {"dallas,ds1307", "rtc-ds1307", "ds1307",},
403 {"dallas,ds1337", "rtc-ds1307", "ds1337",},
404 {"dallas,ds1338", "rtc-ds1307", "ds1338",},
405 {"dallas,ds1339", "rtc-ds1307", "ds1339",},
406 {"dallas,ds1340", "rtc-ds1307", "ds1340",},
407 {"stm,m41t00", "rtc-ds1307", "m41t00"},
408 {"dallas,ds1374", "rtc-ds1374", "rtc-ds1374",},
409};
410
在i2c_devices列表里描述了那些采用传统的I2C驱动的设备列表。同时DTS文件中也需要描述,二者会利用of_find_i2c_driver进行匹配。
411static int __init of_find_i2c_driver(struct device_node *node,
412 struct i2c_board_info *info)
413{
414 int i;
415
416 for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) {
417 if (!of_device_is_compatible(node, i2c_devices[i].of_device))
418 continue;
419 if (strlcpy(info->driver_name, i2c_devices[i].i2c_driver,
420 KOBJ_NAME_LEN) >= KOBJ_NAME_LEN ||
421 strlcpy(info->type, i2c_devices[i].i2c_type,
422 I2C_NAME_SIZE) >= I2C_NAME_SIZE)
423 return -ENOMEM;
424 return 0;
425 }
426 return -ENODEV;
427}
4.2 platform driver
394
395/* Structure for a device driver */
396static struct platform_driver fsl_i2c_driver = {
397 .probe = fsl_i2c_probe,
398 .remove = fsl_i2c_remove,
399 .driver = {
400 .owner = THIS_MODULE,
401 .name = "fsl-i2c", //匹配因子
402 },
403};
404
405static int __init fsl_i2c_init(void)
406{
407 return platform_driver_register(&fsl_i2c_driver);
408}
409
410static void __exit fsl_i2c_exit(void)
411{
412 platform_driver_unregister(&fsl_i2c_driver);
413}
414
415module_init(fsl_i2c_init);
416module_exit(fsl_i2c_exit);
fsl_i2c_driver注册时会扫描platform bus上的所有设备,匹配因子是fsl-i2c,匹配成功后调用fsl_i2c_probe将设备和驱动绑定起来,具体过程参加《详解Linux2.6内核中基于platform机制的驱动模型》,随后向系统注册一个adapter。
http://blog.csdn.net/sailor_8318/archive/2010/01/29/5267698.aspx
318static int fsl_i2c_probe(struct platform_device *pdev)
319{
320 int result = 0;
321 struct mpc_i2c *i2c;
322 struct fsl_i2c_platform_data *pdata;
323 struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
324
325 pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data;
326
327 i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
328 if (!i2c)
329 return -ENOMEM;
330
331 i2c->irq = platform_get_irq(pdev, 0);
332 if (i2c->irq < 0) {
333 result = -ENXIO;
334 goto fail_get_irq;
335 }
336 i2c->flags = pdata->device_flags;
337 init_waitqueue_head(&i2c->queue);
338
339 i2c->base = ioremap((phys_addr_t)r->start, MPC_I2C_REGION);
340
341 if (!i2c->base) {
342 printk(KERN_ERR "i2c-mpc - failed to map controller/n");
343 result = -ENOMEM;
344 goto fail_map;
345 }
346
347 if (i2c->irq != 0)
348 if ((result = request_irq(i2c->irq, mpc_i2c_isr,
349 IRQF_SHARED, "i2c-mpc", i2c)) < 0) {
350 printk(KERN_ERR
351 "i2c-mpc - failed to attach interrupt/n");
352 goto fail_irq;
353 }
354
355 mpc_i2c_setclock(i2c);
356 platform_set_drvdata(pdev, i2c);
357
358 i2c->adap = mpc_ops;
359 i2c->adap.nr = pdev->id;
360 i2c_set_adapdata(&i2c->adap, i2c);
361 i2c->adap.dev.parent = &pdev->dev;
362 if ((result = i2c_add_numbered_adapter(&i2c->adap)) < 0) {
363 printk(KERN_ERR "i2c-mpc - failed to add adapter/n");
364 goto fail_add;
365 }
366
367 return result;
368
369 fail_add:
370 if (i2c->irq != 0)
371 free_irq(i2c->irq, i2c);
372 fail_irq:
373 iounmap(i2c->base);
374 fail_map:
375 fail_get_irq:
376 kfree(i2c);
377 return result;
378};
379
380static int fsl_i2c_remove(struct platform_device *pdev)
381{
382 struct mpc_i2c *i2c = platform_get_drvdata(pdev);
383
384 i2c_del_adapter(&i2c->adap);
385 platform_set_drvdata(pdev, NULL);
386
387 if (i2c->irq != 0)
388 free_irq(i2c->irq, i2c);
389
390 iounmap(i2c->base);
391 kfree(i2c);
392 return 0;
393};
pdev->id为platform data中的devid,为I2C的总线编号,其在设备树文件中描述。
PowerPC的adapter驱动使用了i2c_add_numbered_adapter()注册,总线号最初保存在 platform_data中。
4.3 Adapter及algorithm
这一层主要是定义了关键的数据结构adapter和algorithm。
http://lxr.linux.no/#linux+v2.6.25/drivers/i2c/busses/i2c-mpc.c#L309
309static struct i2c_adapter mpc_ops = {
310 .owner = THIS_MODULE,
311 .name = "MPC adapter",
312 .id = I2C_HW_MPC107,
313 .algo = &mpc_algo,
314 .class = I2C_CLASS_HWMON,
315 .timeout = 1,
316};
304static const struct i2c_algorithm mpc_algo = {
305 .master_xfer = mpc_xfer,
306 .functionality = mpc_functionality,
307};
308
http://lxr.linux.no/#linux+v2.6.25/drivers/i2c/busses/i2c-mpc.c#L256
256static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
257{
258 struct i2c_msg *pmsg;
259 int i;
260 int ret = 0;
261 unsigned long orig_jiffies = jiffies;
262 struct mpc_i2c *i2c = i2c_get_adapdata(adap);
263
264 mpc_i2c_start(i2c);
265
266 /* Allow bus up to 1s to become not busy */ //一定程度上避免总线冲突,收发数据前先查询总线状态
267 while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
268 if (signal_pending(current)) {
269 pr_debug("I2C: Interrupted/n");
270 writeccr(i2c, 0);
271 return -EINTR;
272 }
273 if (time_after(jiffies, orig_jiffies + HZ)) {
274 pr_debug("I2C: timeout/n");
275 if (readb(i2c->base + MPC_I2C_SR) ==
276 (CSR_MCF | CSR_MBB | CSR_RXAK))
277 mpc_i2c_fixup(i2c);
278 return -EIO;
279 }
280 schedule();
281 }
282
283 for (i = 0; ret >= 0 && i < num; i++) {
284 pmsg = &msgs[i];
285 pr_debug("Doing %s %d bytes to 0x%02x - %d of %d messages/n",
286 pmsg->flags & I2C_M_RD ? "read" : "write",
287 pmsg->len, pmsg->addr, i + 1, num);
288 if (pmsg->flags & I2C_M_RD)
289 ret =
290 mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
291 else
292 ret =
293 mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
294 }
295 mpc_i2c_stop(i2c);
296 return (ret < 0) ? ret : num;
297}
5 硬件抽象层-I2C core
5.1 总线初始化
http://lxr.linux.no/#linux+v2.6.25/drivers/i2c/i2c-core.c#L914
885static int __init i2c_init(void)
886{
887 int retval;
888
889 retval = bus_register(&i2c_bus_type);
890 if (retval)
891 return retval;
892 retval = class_register(&i2c_adapter_class);
893 if (retval)
894 goto bus_err;
895 retval = i2c_add_driver(&dummy_driver);
896 if (retval)
897 goto class_err;
898 return 0;
899
900class_err:
901 class_unregister(&i2c_adapter_class);
902bus_err:
903 bus_unregister(&i2c_bus_type);
904 return retval;
905}
906
907static void __exit i2c_exit(void)
908{
909 i2c_del_driver(&dummy_driver);
910 class_unregister(&i2c_adapter_class);
911 bus_unregister(&i2c_bus_type);
912}
913
914subsys_initcall(i2c_init);
915module_exit(i2c_exit);
关于被subsys_initcall修饰的i2c_init何时初始化,请参考下文《详解Linux2.6内核中基于platform机制的驱动模型》
http://blog.csdn.net/sailor_8318/archive/2010/01/29/5267698.aspx
此时platform bus及platform device已经注册完毕,因此I2C控制器的相关资源已经就绪。
该过程主要完成了sysfs总线结构,最终形成如下结构:
/sys/bus/i2c/
|-- devices
|-- drivers
| |-- dummy
| |-- bind
| |-- uevent
| `-- unbind
|-- drivers_autoprobe
|-- drivers_probe
`-- uevent
和
/sys/class/i2c-adapter/
dummy_driver 仅仅是注册了一个空的设备驱动,注册驱动时会遍历加载/sys/class/i2c-adapter/中的所有设备,该过程在初始化总线过程中完成, /sys/class/i2c-adapter/基本为空,所以我认为这里的驱动注册只是验证i2c总线结构的完整性考虑的。
5.2 Adapter注册
在 kernel中提供了两个adapter注册接口,分别为i2c_add_adapter()和i2c_add_numbered_adapter()。 由于在系统中可能存在多个adapter,因此每一条I2C总线对应一个编号,下文中称为I2C总线号。对于i2c_add_adapter()而言, 它使用的是动态总线号,即由系统给其分配一个总线号,而i2c_add_numbered_adapter()则是自己指定总线号,如果这个总线号非法或者是被占用,就会注册失败。
http://lxr.linux.no/#linux+v2.6.25/drivers/i2c/i2c-core.c#L403
403static int i2c_register_adapter(struct i2c_adapter *adap)
404{
405 int res = 0, dummy;
406
407 mutex_init(&adap->bus_lock);
408 mutex_init(&adap->clist_lock);
409 INIT_LIST_HEAD(&adap->clients);
410
411 mutex_lock(&core_lock);
412
413 /* Add the adapter to the driver core.
414 * If the parent pointer is not set up,
415 * we add this adapter to the host bus.
416 */
417 if (adap->dev.parent == NULL) {
418 adap->dev.parent = &platform_bus;
419 pr_debug("I2C adapter driver [%s] forgot to specify "
420 "physical device/n", adap->name);
421 }
422 sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
423 adap->dev.release = &i2c_adapter_dev_release;
424 adap->dev.class = &i2c_adapter_class;
425 res = device_register(&adap->dev);
426 if (res)
427 goto out_list;
428
429 dev_dbg(&adap->dev, "adapter [%s] registered/n", adap->name);
430
431 /* create pre-declared device nodes for new-style drivers */
432 if (adap->nr < __i2c_first_dynamic_bus_num)
433 i2c_scan_static_board_info(adap); //完成静态定义的I2C设备的扫描,将设备和adapter挂上钩,即将设备挂在总线上
434
435 /* let legacy drivers scan this bus for matching devices */
436 dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
437 i2c_do_add_adapter); /*探测总线上的所有i2c设备驱动,如果匹配则完成client、driver、device、adapter的绑定*/
438
439out_unlock:
440 mutex_unlock(&core_lock);
441 return res;
442
443out_list:
444 idr_remove(&i2c_adapter_idr, adap->nr);
445 goto out_unlock;
446}
5.3 驱动注册
http://lxr.linux.no/#linux+v2.6.25/drivers/i2c/i2c-core.c#L635
635int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
636{
637 int res;
638
639 /* new style driver methods can't mix with legacy ones */
640 if (is_newstyle_driver(driver)) {
641 if (driver->attach_adapter || driver->detach_adapter
642 || driver->detach_client) {
643 printk(KERN_WARNING
644 "i2c-core: driver [%s] is confused/n",
645 driver->driver.name);
646 return -EINVAL;
647 }
648 }
649
650 /* add the driver to the list of i2c drivers in the driver core */
651 driver->driver.owner = owner;
652 driver->driver.bus = &i2c_bus_type;
653
654 /* for new style drivers, when registration returns the driver core
655 * will have called probe() for all matching-but-unbound devices.
656 */
657 res = driver_register(&driver->driver);
658 if (res)
659 return res;
660
661 mutex_lock(&core_lock);
662
663 pr_debug("i2c-core: driver [%s] registered/n", driver->driver.name);
664
665 /* legacy drivers scan i2c busses directly */
666 if (driver->attach_adapter) {
667 struct i2c_adapter *adapter;
668
669 down(&i2c_adapter_class.sem);
670 list_for_each_entry(adapter, &i2c_adapter_class.devices,
671 dev.node) {
672 driver->attach_adapter(adapter);
673 }
674 up(&i2c_adapter_class.sem);
675 }
676
677 mutex_unlock(&core_lock);
678 return 0;
679}
680EXPORT_SYMBOL(i2c_register_driver);
两种注册方式。对于new style驱动,将采用内核通用的驱动模型,其流程和platform driver的注册过程类似,请请参考下文《详解Linux2.6内核中基于platform机制的驱动模型》
http://blog.csdn.net/sailor_8318/archive/2010/01/29/5267698.aspx
而对于legacy driver,是如何匹配注册的呢?TBD
5.4 数据传输
917/* ----------------------------------------------------
918 * the functional interface to the i2c busses.
919 * ----------------------------------------------------
920 */
921
922int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
923{
924 int ret;
925
926 if (adap->algo->master_xfer) {
927#ifdef DEBUG
928 for (ret = 0; ret < num; ret++) {
929 dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
930 "len=%d%s/n", ret, (msgs[ret].flags & I2C_M_RD)
931 ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
932 (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
933 }
934#endif
935
936 if (in_atomic() || irqs_disabled()) { //原子上下文或者中断禁止时不能获取自旋锁,防止休眠死锁,只能试探锁
937 ret = mutex_trylock(&adap->bus_lock);
938 if (!ret)
939 /* I2C activity is ongoing. */
940 return -EAGAIN;
941 } else {
942 mutex_lock_nested(&adap->bus_lock, adap->level);
943 }
944
945 ret = adap->algo->master_xfer(adap,msgs,num);
946 mutex_unlock(&adap->bus_lock);
947
948 return ret;
949 } else {
950 dev_dbg(&adap->dev, "I2C level transfers not supported/n");
951 return -ENOSYS;
952 }
953}
954EXPORT_SYMBOL(i2c_transfer);
核心层提供的通用数据收发接口,屏蔽了底层差异。利用adapter进行数据传输前先获得互斥锁,因此保证只有一个调用者占用总线,这样数据传输才是原子的。多个msgs可以一次传输完毕,因此对于读操作,两次I2C总线的访问(先写后读)需要在一个io ctrl中处理完毕
6 用户接口层-I2C设备驱动
6.1 统一的设备模型
此驱动模型是针对I2C控制器的,因为对I2C slave的寻址是通过报文的内容来实现的,而对于I2C控制器来说,slave的地址仅仅是某个具体的报文而已,对控制器来说是透明的,因此用户空间访问的设备本质上就是I2C控制器。
6.1.1 关键数据结构
550static struct i2c_driver i2cdev_driver = {
551 .driver = {
552 .name = "dev_driver",
553 },
554 .id = I2C_DRIVERID_I2CDEV,
555 .attach_adapter = i2cdev_attach_adapter,
556 .detach_adapter = i2cdev_detach_adapter,
557 .detach_client = i2cdev_detach_client,
558};
定义了一个标准的i2c_driver。
41/*
42 * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a
43 * slave (i2c_client) with which messages will be exchanged. It's coupled
44 * with a character special file which is accessed by user mode drivers.
45 *
46 * The list of i2c_dev structures is parallel to the i2c_adapter lists
47 * maintained by the driver model, and is updated using notifications
48 * delivered to the i2cdev_driver.
49 */
50struct i2c_dev {
51 struct list_head list;
52 struct i2c_adapter *adap;
53 struct device *dev;
54};
55
56#define I2C_MINORS 256
57static LIST_HEAD(i2c_dev_list);
58static DEFINE_SPINLOCK(i2c_dev_list_lock);
定义了一个i2c_dev列表,每个adapter对应一个i2c_dev。
478static const struct file_operations i2cdev_fops = {
479 .owner = THIS_MODULE,
480 .llseek = no_llseek,
481 .read = i2cdev_read,
482 .write = i2cdev_write,
483 .ioctl = i2cdev_ioctl,
484 .open = i2cdev_open,
485 .release = i2cdev_release,
486};
487
任意一个需要和用户空间通信的驱动必备的数据结构,其定义了具体的读写操作方法。
6.1.2 初始化
http://lxr.linux.no/#linux+v2.6.25/drivers/i2c/i2c-dev.c#L607
566static int __init i2c_dev_init(void)
567{
568 int res;
569
570 printk(KERN_INFO "i2c /dev entries driver/n");
571
572 res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
573 if (res)
574 goto out;
575
576 i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
577 if (IS_ERR(i2c_dev_class))
578 goto out_unreg_chrdev;
579
580 res = i2c_add_driver(&i2cdev_driver);
581 if (res)
582 goto out_unreg_class;
583
584 return 0;
585
586out_unreg_class:
587 class_destroy(i2c_dev_class);
588out_unreg_chrdev:
589 unregister_chrdev(I2C_MAJOR, "i2c");
590out:
591 printk(KERN_ERR "%s: Driver Initialisation failed/n", __FILE__);
592 return res;
593}
594
595static void __exit i2c_dev_exit(void)
596{
597 i2c_del_driver(&i2cdev_driver);
598 class_destroy(i2c_dev_class);
599 unregister_chrdev(I2C_MAJOR,"i2c");
600}
首先注册了一个字符型设备驱动,然后注册i2c_driver,将驱动和adapter绑定起来,匹配成功后将调用i2c_driver 的attach_adapter 方法,即i2cdev_attach_adapter, 建立dev设备节点,并维护了一个i2c_dev链表保存设备节点和adapter的关系。
http://lxr.linux.no/#linux+v2.6.25/drivers/i2c/i2c-dev.c#L498
498static int i2cdev_attach_adapter(struct i2c_adapter *adap)
499{
500 struct i2c_dev *i2c_dev;
501 int res;
502
503 i2c_dev = get_free_i2c_dev(adap); //添加一个adapter到i2c_dev列表中
504 if (IS_ERR(i2c_dev))
505 return PTR_ERR(i2c_dev);
506
507 /* register this i2c device with the driver core */
508 i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
509 MKDEV(I2C_MAJOR, adap->nr),
510 "i2c-%d", adap->nr);
511 if (IS_ERR(i2c_dev->dev)) {
512 res = PTR_ERR(i2c_dev->dev);
513 goto error;
514 }
515 res = device_create_file(i2c_dev->dev, &dev_attr_name);
516 if (res)
517 goto error_destroy;
518
519 pr_debug("i2c-dev: adapter [%s] registered as minor %d/n",
520 adap->name, adap->nr);
521 return 0;
522error_destroy:
523 device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
524error:
525 return_i2c_dev(i2c_dev);
526 return res;
527}
以I2C_MAJOR和adap->nr为主从设备号注册设备节点,如果系统有udev或者是hotplug,那么就么在/dev下自动创建相关的设备节点了
6.1.3 Open及release
431static int i2cdev_open(struct inode *inode, struct file *file)
432{
433 unsigned int minor = iminor(inode);
434 struct i2c_client *client;
435 struct i2c_adapter *adap;
436 struct i2c_dev *i2c_dev;
437
438 i2c_dev = i2c_dev_get_by_minor(minor); //由次设备号获得i2c_dev即可获得对应的adapter
439 if (!i2c_dev)
440 return -ENODEV;
441
442 adap = i2c_get_adapter(i2c_dev->adap->nr); //对module引用进行计数
443 if (!adap)
444 return -ENODEV;
445
446 /* This creates an anonymous i2c_client, which may later be
447 * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
448 *
449 * This client is ** NEVER REGISTERED ** with the driver model
450 * or I2C core code!! It just holds private copies of addressing
451 * information and maybe a PEC flag.
452 */
453 client = kzalloc(sizeof(*client), GFP_KERNEL);
454 if (!client) {
455 i2c_put_adapter(adap);
456 return -ENOMEM;
457 }
458 snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
459 client->driver = &i2cdev_driver;
460
461 client->adapter = adap;
462 file->private_data = client;
463
464 return 0;
465}
Open操作是用户空间程序和内核驱动交换的第一步,最终返回给用户空间的就是struct file结构体。对于I2C 驱动来说,用户空间所获得的就是client这个关键信息,在其中可以找到所有有关的信息如client所在的adapter及i2c_driver。此i2c_client并没有遵循设备模型的方式注册进系统,在sys下面没有任何信息。
6.1.4 数据收发
对于I2C驱动来说,数据收发有两种途径,read/write或者ioctl方式。
对于read/write方式来说,必须先通过ioctl的I2C_SLAVE设置从设备的地址。随后再通过read/write对相应的slave直接进行数据收发。
117/*
118 * After opening an instance of this character special file, a file
119 * descriptor starts out associated only with an i2c_adapter (and bus).
120 *
121 * Using the I2C_RDWR ioctl(), you can then *immediately* issue i2c_msg
122 * traffic to any devices on the bus used by that adapter. That's because
123 * the i2c_msg vectors embed all the addressing information they need, and
124 * are submitted directly to an i2c_adapter. However, SMBus-only adapters
125 * don't support that interface.
126 *
127 * To use read()/write() system calls on that file descriptor, or to use
128 * SMBus interfaces (and work with SMBus-only hosts!), you must first issue
129 * an I2C_SLAVE (or I2C_SLAVE_FORCE) ioctl. That configures an anonymous
130 * (never registered) i2c_client so it holds the addressing information
131 * needed by those system calls and by this SMBus interface.
132 */
133
134static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count,
135 loff_t *offset)
136{
read/write与用户空间的接口是buf和count,为收发的相应数据指针和数据长度。
SMBus只能利用read/write方式和用户空间通信??
对于ioctl方式,相关的cmd是I2C_RDWR
203static int i2cdev_ioctl(struct inode *inode, struct file *file,
204 unsigned int cmd, unsigned long arg)
205{
206 struct i2c_client *client = (struct i2c_client *)file->private_data;
207 struct i2c_rdwr_ioctl_data rdwr_arg;
208 struct i2c_smbus_ioctl_data data_arg;
209 union i2c_smbus_data temp;
210 struct i2c_msg *rdwr_pa;
211 u8 __user **data_ptrs;
212 int i,datasize,res;
213 unsigned long funcs;
255 case I2C_RDWR:
256 if (copy_from_user(&rdwr_arg,
257 (struct i2c_rdwr_ioctl_data __user *)arg,
258 sizeof(rdwr_arg)))
259 return -EFAULT;
260
261 /* Put an arbitrary limit on the number of messages that can
262 * be sent at once */
263 if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
264 return -EINVAL;
265
266 rdwr_pa = (struct i2c_msg *)
267 kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
268 GFP_KERNEL);
269
270 if (rdwr_pa == NULL) return -ENOMEM;
271
272 if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
273 rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
274 kfree(rdwr_pa);
275 return -EFAULT;
276 }
277
278 data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
279 if (data_ptrs == NULL) {
280 kfree(rdwr_pa);
281 return -ENOMEM;
282 }
283
284 res = 0;
285 for( i=0; i<rdwr_arg.nmsgs; i++ ) {
286 /* Limit the size of the message to a sane amount;
287 * and don't let length change either. */
288 if ((rdwr_pa[i].len > 8192) ||
289 (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
290 res = -EINVAL;
291 break;
292 }
293 data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
294 rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
295 if(rdwr_pa[i].buf == NULL) {
296 res = -ENOMEM;
297 break;
298 }
299 if(copy_from_user(rdwr_pa[i].buf,
300 data_ptrs[i],
301 rdwr_pa[i].len)) {
302 ++i; /* Needs to be kfreed too */
303 res = -EFAULT;
304 break;
305 }
306 }
307 if (res < 0) {
308 int j;
309 for (j = 0; j < i; ++j)
310 kfree(rdwr_pa[j].buf);
311 kfree(data_ptrs);
312 kfree(rdwr_pa);
313 return res;
314 }
315
//上述所有操作就是将用户空间的数据拷贝到内核空间。组织成以rdwr_pa为首地址的nmsgs个msg
316 res = i2c_transfer(client->adapter,
317 rdwr_pa,
318 rdwr_arg.nmsgs);
319 while(i-- > 0) {
320 if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD)) {
321 if(copy_to_user( //如果是读操作,再将内核空间中缓存的数据拷贝到用户空间
322 data_ptrs[i],
323 rdwr_pa[i].buf,
324 rdwr_pa[i].len)) {
325 res = -EFAULT;
326 }
327 }
328 kfree(rdwr_pa[i].buf);
329 }
330 kfree(data_ptrs);
331 kfree(rdwr_pa);
332 return res;
与用户空间的接口是i2c_rdwr_ioctl_data
/* This is the structure as used in the I2C_RDWR ioctl call */
struct i2c_rdwr_ioctl_data {
struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */
};
所有待收发的数据都已经由用户空间组织好了
/**
* struct i2c_msg - an I2C transaction segment beginning with START
* @addr: Slave address, either seven or ten bits. When this is a ten
* bit address, I2C_M_TEN must be set in @flags and the adapter
* must support I2C_FUNC_10BIT_ADDR.
* @flags: I2C_M_RD is handled by all adapters. No other flags may be
* provided unless the adapter exported the relevant I2C_FUNC_*
* flags through i2c_check_functionality().
* @len: Number of data bytes in @buf being read from or written to the
* I2C slave address. For read transactions where I2C_M_RECV_LEN
* is set, the caller guarantees that this buffer can hold up to
* 32 bytes in addition to the initial length byte sent by the
* slave (plus, if used, the SMBus PEC); and this value will be
* incremented by the number of block data bytes received.
* @buf: The buffer into which data is read, or from which it's written.
*
* An i2c_msg is the low level representation of one segment of an I2C
* transaction. It is visible to drivers in the @i2c_transfer() procedure,
* to userspace from i2c-dev, and to I2C adapter drivers through the
* @i2c_adapter.@master_xfer() method.
*
* Except when I2C "protocol mangling" is used, all I2C adapters implement
* the standard rules for I2C transactions. Each transaction begins with a
* START. That is followed by the slave address, and a bit encoding read
* versus write. Then follow all the data bytes, possibly including a byte
* with SMBus PEC. The transfer terminates with a NAK, or when all those
* bytes have been transferred and ACKed. If this is the last message in a
* group, it is followed by a STOP. Otherwise it is followed by the next
* @i2c_msg transaction segment, beginning with a (repeated) START.
*
* Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then
* passing certain @flags may have changed those standard protocol behaviors.
* Those flags are only for use with broken/nonconforming slaves, and with
* adapters which are known to support the specific mangling options they
* need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR).
*/
struct i2c_msg {
__u16 addr; /* slave address */
__u16 flags;
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RD 0x0001 /* read data, from slave to master */
。。。
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
6.2 特定的设备驱动
原则上所有的I2C从设备的方法都可以通过上述统一的设备模型I2c-dev来访问,但I2c-dev上传输的是透明的数据,而对于某些I2C从设备,其数据传输遵循一定的格式,如果用I2c-dev来访问,则用户需要组织好所有的i2c_msg,对一般用户来说可能比较复杂。为了提供更加user friendly的接口,可以对特定I2C从设备的访问进行再次封装。
如I2C的RTC,其数据的转换较为复杂,为了减少用户空间的转换,提供了专用的RTC驱动供用户程序访问,其向上屏蔽了具体RTC芯片的差异。
下面以drivers/rtc/rtc-pcf8563.c为例来进行讲述。
6.2.1 关键数据结构
struct pcf8563 {
struct i2c_client client;
/*
* The meaning of MO_C bit varies by the chip type.
* From PCF8563 datasheet: this bit is toggled when the years
* register overflows from 99 to 00
* 0 indicates the century is 20xx
* 1 indicates the century is 19xx
* From RTC8564 datasheet: this bit indicates change of
* century. When the year digit data overflows from 99 to 00,
* this bit is set. By presetting it to 0 while still in the
* 20th century, it will be set in year 2000, ...
* There seems no reliable way to know how the system use this
* bit. So let's do it heuristically, assuming we are live in
* 1970...2069.
*/
int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
};
pcf8563关键信息的全局表示。
static struct i2c_driver pcf8563_driver = {
.driver = {
.name = "pcf8563",
},
.id = I2C_DRIVERID_PCF8563,
.attach_adapter = &pcf8563_attach,
.detach_client = &pcf8563_detach,
};
特定的pcf8563_driver,有自己特定的pcf8563_attach方法。
static const struct rtc_class_ops pcf8563_rtc_ops = {
.read_time = pcf8563_rtc_read_time,
.set_time = pcf8563_rtc_set_time,
};
向RTC子系统注册的读写方法。
6.2.2 初始化
static int __init pcf8563_init(void)
{
return i2c_add_driver(&pcf8563_driver);
}
static void __exit pcf8563_exit(void)
{
i2c_del_driver(&pcf8563_driver);
}
调用i2c_add_driver向I2C总线上注册pcf8563_driver的I2C驱动,根据pcf8563这个driver的name进行匹配,匹配成功后将自动调用pcf8563_attach。
static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
{
struct pcf8563 *pcf8563;
struct i2c_client *client;
struct rtc_device *rtc;
int err = 0;
dev_dbg(&adapter->dev, "%s/n", __FUNCTION__);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
goto exit;
}
if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
client = &pcf8563->client;
client->addr = address; //此address即为该slave的I2C设备地址
client->driver = &pcf8563_driver;
client->adapter = adapter;
//上述几步和统一的I2C设备模型的client一样
strlcpy(client->name, pcf8563_driver.driver.name, I2C_NAME_SIZE);
/* Verify the chip is really an PCF8563 */
if (kind < 0) {
if (pcf8563_validate_client(client) < 0) { //探测相关slave是否存在,简单的收发数据进行验证
err = -ENODEV;
goto exit_kfree;
}
}
/* Inform the i2c layer */
if ((err = i2c_attach_client(client))) //将本client挂接到依附的adapter上 goto exit_kfree;
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "/n");
rtc = rtc_device_register(pcf8563_driver.driver.name, &client->dev,
&pcf8563_rtc_ops, THIS_MODULE);
//向RTC子系统注册pcf8563设备
if (IS_ERR(rtc)) {
err = PTR_ERR(rtc);
goto exit_detach;
}
i2c_set_clientdata(client, rtc);
return 0;
exit_detach:
i2c_detach_client(client);
exit_kfree:
kfree(pcf8563);
exit:
return err;
}
6.2.3 数据收发
RTC设备的数据收发是通过drivers/rtc/rtc-dev.c进行的。
static const struct file_operations rtc_dev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = rtc_dev_read,
.poll = rtc_dev_poll,
.ioctl = rtc_dev_ioctl,
.open = rtc_dev_open,
.release = rtc_dev_release,
.fasync = rtc_dev_fasync,
};
该file_operations向用户空间提供了统一接口。
7 驱动访问示例
下面以一款EEPOM AT24C64AN为例来讲述用户空间如何访问I2C设备。
7.1.1 写操作
I2C总线的写操作通常比较简单,分为byte write和page write
但两种方式对于SW来说没有区别,SW只需要指定发送的数据长度即可。
/**********
i2cBus为总线编号,也就是adapter编号,应该是本I2C设备所挂接的I2C总线
devAddr,为待访问的I2C设备地址
bTwoByteAddr,为待访问的从设备内部寄存器偏移量地址的宽度,即8位或16位,对应1或2个字节
offAddr,为待访问的从设备内部寄存器偏移量起始地址
byteLen,待写的数据长度,不包括总线协议上的dev addr及word address
i2cBuff1,待发送到有效数据即DATA
********/
int i2c_write(BYTE i2cBus, BYTE devAddr, BOOL bTwoByteAddr,
WORD offAddr, WORD byteLen, BYTE* i2cBuff1)
{
char fileName[20];
BYTE i2cBuff0[256]; /* buffer to send offset address & data*/
int file, iRealDataStart;
sprintf(fileName, "/dev/i2c-%d", i2cBus); //打开相应的I2C总线设备
file = open(fileName, O_RDWR);
if (file < 0)
{
fprintf(stderr, "Fail: Could not open file `/dev/i2c-%d': %s/n", /
i2cBus, strerror(ENOENT));
return -1;
}
if(!bTwoByteAddr)
{
i2cBuff0[0] = (BYTE)(offAddr & 0x00FF);
iRealDataStart = 1;
}
else
{
i2cBuff0[0] = (BYTE)((offAddr & 0xFF00)>>8);
i2cBuff0[1] = (BYTE)(offAddr & 0x00FF);
iRealDataStart = 2;
}
/* Build write buffer */
memcpy(&i2cBuff0[iRealDataStart], i2cBuff1, byteLen); //构造i2c_msg中的buf
sI2ccMessages[0].addr = devAddr;
sI2ccMessages[0].flags = 0; /* Write flag = 0 */
sI2ccMessages[0].len = byteLen + iRealDataStart; //此长度为DATA和WORD ADDRESS
sI2ccMessages[0].buf = i2cBuff0;
sI2ccIoctData.msgs = sI2ccMessages;
sI2ccIoctData.nmsgs = 1;
if (ioctl(file, I2C_RDWR, &sI2ccIoctData) < 0)
{
fprintf(stderr, "Fail: fails to write to I2C device 0x%x at address 0x%x/n", devAddr, offAddr);
close(file);
return -1;
}
close(file);
return 0;
}
7.1.2 读操作
I2C设备的读操作较复杂,需要先写待读的内部寄存器地址,然后再发起总线的读操作。时序如下:
因此需要在总线上连续进行两次数据传输,即两个i2c_msg。
/**********
i2cBus为总线编号,也就是adapter编号,应该是本I2C设备所挂接的I2C总线
devAddr,为待访问的I2C设备地址
bTwoByteAddr,为待访问的从设备内部寄存器偏移量地址的宽度,即8位或16位,对应1或2个字节
offAddr,为待访问的从设备内部寄存器偏移量起始地址
byteLen,待读的数据长度
i2cBuff1,待读的有效数据即DATA
********/
int i2c_read(BYTE i2cBus, BYTE devAddr, BOOL bTwoByteAddr,
WORD offAddr, WORD byteLen, BYTE* i2cBuff1)
{
char fileName[20];
BYTE i2cBuff0[2]; /* buffer to send offset address */
int file= 0;
sprintf(fileName, "/dev/i2c-%d", i2cBus);
file = open(fileName, O_RDWR);
if (file < 0)
{
fprintf(stderr, "Fail: Could not open file `/dev/i2c-%d': %s/n", /
i2cBus, strerror(ENOENT));
return -1;
}
sI2ccMessages[0].addr = devAddr;
sI2ccMessages[0].flags = 0; /* write flag = 0 */
if(!bTwoByteAddr)
{
i2cBuff0[0] = (BYTE)(offAddr & 0x00FF);
sI2ccMessages[0].len = 1;
}
else
{
i2cBuff0[0] = (BYTE)((offAddr& 0xFF00)>>8);
i2cBuff0[1] = (BYTE)(offAddr& 0x00FF);
sI2ccMessages[0].len = 2;
}
sI2ccMessages[0].buf = i2cBuff0; //第一个msg只是一个默认的写操作
sI2ccMessages[1].addr = devAddr;
sI2ccMessages[1].flags = I2C_M_RD; /* read flag */
sI2ccMessages[1].len = byteLen;
sI2ccMessages[1].buf = i2cBuff1; //此仅仅为DATA域
sI2ccIoctData.msgs = sI2ccMessages;
sI2ccIoctData.nmsgs = 2;
if (ioctl(file, I2C_RDWR, &sI2ccIoctData) < 0) //一个ioctl必须连续发送两个msg
{
fprintf(stderr, "Fail: fails to read from I2C device 0x%x at address 0x%x/n", /
devAddr, offAddr);
close(file);
return -1;
}
close(file);
return 0;
}