本文借助mtk平台分析linux的i2c框架,mtk平台mt6765,内核版本kernel-4.9,本文只分析linux的i2c框架,不讨论i2c总线协议相关内容.
一、数据结构
1、i2c_client
具体的i2次设备的软件抽象,它拥有所有i2c次设备的信息:
包括i2c总线(物理总线)的控制器的硬件描述信息,这些信息通过结构 adapter 来进行描述
以及具体设备的addr信息,中断,以及name,这些信息通过结构 i2c_board_info 来进行描述
i2c_client这个结构被注册时候就被注册到 i2c bus 上了,因此我们可以利用 i2c bus 获取到这个结构
说明:i2c有两个总线的概念,一个是设备模型中虚拟的i2c总线,另一个则是实际的物理上的i2c总线,在不说明的情况下默认设备模型中的虚拟总线。
1 2 3 4 5 6 7 8 9 10 11 12 13 struct i2c_client { unsigned short flags; unsigned short addr; char name[I2C_NAME_SIZE]; struct i2c_adapter *adapter ; struct device dev ; int irq; struct list_head detected ; #if IS_ENABLED(CONFIG_I2C_SLAVE) i2c_slave_cb_t slave_cb; #endif };
2、i2c_adapter
i2c适配器,adapter翻译过来就是适配器的意思,这个结构描述了硬件上的i2c总线的控制器信息,注意不是我们理解的设备模型上虚拟的i2c总线,而是实实在在的接在cpu上面的硬件i2c总线的控制器信息
其中 algo 链接着该总线的i2c通信相关结构 i2c_algorithm 。 按理来讲通信方式也是总线控制器的一部分为什么要将其分离出来,这样做是为了代码的复用性,如果系统有6个i2c总线则需要写6个通信接口,而区别往往只是一些和控制器某些寄存器的值不同而已,为了提高代码的效率,于是将 i2c_algorithm 独立出来作为一个共有的模块。
很明显作为总线控制器的描述,i2c_adapter 不会描述具体的设备信息,具体的设备信息由中间结构 i2c_board_info 描述,并将其存入 i2c_client 结构。
从上面的描述可以知道 i2c 适配器的数量其实是固定的,硬件有多少个 i2c 总线,就会有多少个 i2c 适配器,例如 mt6765 有6个物理的i2c总线i2c0-i2c6,因此mt6765就有6个i2c适配器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 struct i2c_adapter { struct module *owner ; unsigned int class ; const struct i2c_algorithm *algo ; void *algo_data; const struct i2c_lock_operations *lock_ops ; struct rt_mutex bus_lock ; struct rt_mutex mux_lock ; int timeout; int retries; struct device dev ; int nr; char name[48 ]; struct completion dev_released ; struct mutex userspace_clients_lock ; struct list_head userspace_clients ; struct i2c_bus_recovery_info *bus_recovery_info ; const struct i2c_adapter_quirks *quirks ; }; struct i2c_algorithm { int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data); u32 (*functionality) (struct i2c_adapter *); #if IS_ENABLED(CONFIG_I2C_SLAVE) int (*reg_slave)(struct i2c_client *client); int (*unreg_slave)(struct i2c_client *client); #endif };
3、i2c_board_info
这个结构用于描述具体的i2c设备的硬件信息,设备地址,通信方式,中断号等。
当使用dts创建 i2c_client 时,它作为中间结构,当他把硬件信息传递给真正的设备结构 i2c_client,它的使命也就完成了,dts中的设备信息先在内核中转换为 i2c_board_info 这个结构,然后通过这个结构传给 i2c_client 。
当使用老式的使用总线号创建 i2c_client时,所有的由 i2c_register_board_info 动态创建的 i2c_board_info 描述的设备信息将被链接到 __i2c_board_list 链表进行维护,在加载内核时查询 __i2c_board_list 将 i2c_board_info 描述的信息传给 i2c_client
1 2 3 4 5 6 7 8 9 10 struct i2c_board_info { char type[I2C_NAME_SIZE]; unsigned short flags; unsigned short addr; void *platform_data; struct dev_archdata *archdata ; struct device_node *of_node ; struct fwnode_handle *fwnode ; int irq; };
4、i2c_driver
该结构用来描述虚拟 i2c bus 总线上的 driver ,通过向 i2c bus 注册该结构进行匹配,获取对应的 i2c_client
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 struct i2c_driver { unsigned int class ; int (*attach_adapter)(struct i2c_adapter *) __deprecated; int (*probe)(struct i2c_client *, const struct i2c_device_id *); int (*remove)(struct i2c_client *); void (*shutdown)(struct i2c_client *); void (*alert)(struct i2c_client *, enum i2c_alert_protocol protocol, unsigned int data); int (*command)(struct i2c_client *client, unsigned int cmd, void *arg); struct device_driver driver ; const struct i2c_device_id *id_table ; int (*detect)(struct i2c_client *, struct i2c_board_info *); const unsigned short *address_list; struct list_head clients ; };
5、i2c_device_id
1 2 3 4 struct i2c_device_id { char name[I2C_NAME_SIZE]; kernel_ulong_t driver_data; };
6、i2c_msg
linux的i2c通信是以 i2c_msg 作为操作单位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 struct i2c_msg { __u16 addr; __u16 flags; #define I2C_M_RD 0x0001 #define I2C_M_TEN 0x0010 #define I2C_M_RECV_LEN 0x0400 #define I2C_M_NO_RD_ACK 0x0800 #define I2C_M_IGNORE_NAK 0x1000 #define I2C_M_REV_DIR_ADDR 0x2000 #define I2C_M_NOSTART 0x4000 #define I2C_M_STOP 0x8000 __u16 len; __u8 *buf; };
三、内核i2c驱动框架
li2c总线的硬件结构一般如下图所示
cpu 作为主设备挂接在所有总线上,而对应的设备根据硬件设计挂接在相应的总线上。图所示gsensor挂接在i2c0上,camera挂接在i2c1上,tp挂接在i2c2上。硬件结构非常简单,而linux的实现相对而言复杂度还是蛮高的,向上面的i2c设备 gsensor、camera、tp 等对于总线来讲只是地址上的不同而已,本质上都是i2c设备没有什么不同。 linux-4.9提供6种添加i2c设备的方法,参考 Documentation/i2c/instantiating-devices,下面逐一讨论。
1、使用dts添加i2c设备
只需在dts文件中添加i2c设备相关节点,内核就会自动创建对应的 i2c_client 结构。 例如:添加两个设备 24c256、pca9532以以100kHz的速度连接到i2c1总线。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 i2c1: i2c@400 a0000 { clock-frequency = <100000 >; flash@50 { compatible = "atmel,24c256" ; reg = <0x50 >; }; pca9532: gpio@60 { compatible = "nxp,pca9532" ; gpio-controller; #gpio-cells = <2> ; reg = <0x60 >; }; };
这样内核在加载的时候就会自动创建出 name 为 24c256 和 pca9532 的i2c_client结构并将其注册进入i2c bus。它的流程如下所示:
上图展示了整个注册流程,对于驱动工程师来讲非常简单,只需在dts中填充对应的信息就行了。而内核却帮我我们完成了一系类注册流程。而作为驱动工程师不仅仅要做到知其然,还要知其所以然,下面以mtk平台为例分析整个注册流程。
源码路径drivers/i2c/busses/i2c-mtk.c,ic原厂提供i2c函数都被放在drivers/i2c/busses/这个目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 static s32 __init mt_i2c_init (void ) { #ifdef CONFIG_MTK_I2C_ARBITRATION int ret; ret = enable_arbitration(); if (ret) { pr_info("Cannot enalbe arbitration.\n" ); return ret; } #endif if (!map_dma_regs()) pr_info("Mapp dma regs successfully.\n" ); if (!mt_i2c_parse_comp_data()) pr_info("Get compatible data from dts successfully.\n" ); pr_info(" mt_i2c_init driver as platform device\n" ); return platform_driver_register(&mt_i2c_driver); }
上面代码向内核注册了一个名叫 “mt-i2c” 的 platform 驱动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #define I2C_DRV_NAME "mt-i2c" static const struct of_device_id mtk_i2c_of_match [] = { { .compatible = "mediatek,i2c" , .data = &i2c_common_compat}, {}, }; static struct platform_driver mt_i2c_driver = { .probe = mt_i2c_probe, .remove = mt_i2c_remove, .driver = { .name = I2C_DRV_NAME, .owner = THIS_MODULE, .pm = &mt_i2c_dev_pm_ops, .of_match_table = of_match_ptr(mtk_i2c_of_match), }, };
可以看到它 match 的设备的 compatible 字段是 “mediatek,i2c” ,于是在dts中找对应的设备节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 i2c0: i2c0@11007000 { compatible = "mediatek,i2c" ; id = <0 >; ... }; i2c1: i2c1@11008000 { compatible = "mediatek,i2c" ; id = <1 >; ... }; i2c2: i2c2@11009000 { compatible = "mediatek,i2c" ; id = <2 >; ... }; i2c3: i2c3@1100f 000 { compatible = "mediatek,i2c" ; id = <3 >; ... }; i2c4: i2c4@11011000 { compatible = "mediatek,i2c" ; id = <4 >; ... }; i2c5: i2c5@11016000 { compatible = "mediatek,i2c" ; id = <5 >; ... }; i2c6: i2c6@1100 d000 { compatible = "mediatek,i2c" ; id = <6 >; ... };
凡是在dts中具有compatible字段的节点,都会被内核注册为platform设备,例如上面的 i2c0,将会被转换为名字为"11007000.i2c0"的platform设备,再看i2c0到i2c6的节点都有相同的compatible字段"mediatek,i2c",因此当驱动mt_i2c_driver注册的时候,会分别与之匹配调用对应的 mt_i2c_probe 函数,也就是说会调用6次mt_i2c_probe函数分别注册i2c0到i2c6, 以i2c0为例进行分析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 static int mt_i2c_probe (struct platform_device *pdev) { int ret = 0 ; struct mt_i2c *i2c ; unsigned int clk_src_in_hz; struct resource *res ; const struct of_device_id *of_id ; i2c = devm_kzalloc(&pdev->dev, sizeof (struct mt_i2c), GFP_KERNEL); if (i2c == NULL ) return -ENOMEM; ret = mt_i2c_parse_dt(pdev->dev.of_node, i2c); if (ret) return -EINVAL; i2c->dev_comp = of_id->data; i2c->adap.dev.of_node = pdev->dev.of_node; i2c->dev = &i2c->adap.dev; i2c->adap.dev.parent = &pdev->dev; i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &mt_i2c_algorithm; i2c->adap.algo_data = NULL ; i2c->adap.timeout = 2 * HZ; i2c->adap.retries = 1 ; i2c->adap.nr = i2c->id; spin_lock_init(&i2c->cg_lock); strlcpy(i2c->adap.name, I2C_DRV_NAME, sizeof (i2c->adap.name)); ret = i2c_add_numbered_adapter(&i2c->adap); return 0 ; }
上述函数,从dts获取相关的平台台相关的硬件信息,通信方式(mt_i2c_algorithm)、硬件总线号(adap.nr )等,以及平台相关的信息,通信超时时间、通信重复次数等,利用这些信息创建并初始化一个 i2c_adapter(包含在mt_i2c中),并将其注册进内核,来看看它的注册过程,它的代码在 drivers/i2c/i2c-core.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 int i2c_add_numbered_adapter (struct i2c_adapter *adap) { if (adap->nr == -1 ) return i2c_add_adapter(adap); return __i2c_add_numbered_adapter(adap); } EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter); static int __i2c_add_numbered_adapter(struct i2c_adapter *adap){ int id; mutex_lock(&core_lock); id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1 , GFP_KERNEL); mutex_unlock(&core_lock); if (WARN(id < 0 , "couldn't get idr" )) return id == -ENOSPC ? -EBUSY : id; return i2c_register_adapter(adap); }
可以看到其实是调用了内核提供 i2c_register_adapter 函数来进行注册,来看看它干了什么
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 static int i2c_register_adapter (struct i2c_adapter *adap) { int res = -EINVAL; if (WARN_ON(!is_registered)) { res = -EAGAIN; goto out_list; } if (WARN(!adap->name[0 ], "i2c adapter has no name" )) goto out_list; if (!adap->algo) { pr_err("adapter '%s': no algo supplied!\n" , adap->name); goto out_list; } if (!adap->lock_ops) adap->lock_ops = &i2c_adapter_lock_ops; rt_mutex_init(&adap->bus_lock); rt_mutex_init(&adap->mux_lock); mutex_init(&adap->userspace_clients_lock); INIT_LIST_HEAD(&adap->userspace_clients); if (adap->timeout == 0 ) adap->timeout = HZ; dev_set_name(&adap->dev, "i2c-%d" , adap->nr); adap->dev.bus = &i2c_bus_type; adap->dev.type = &i2c_adapter_type; res = device_register(&adap->dev); if (res) { pr_err("adapter '%s': can't register device (%d)\n" , adap->name, res); goto out_list; } dev_dbg(&adap->dev, "adapter [%s] registered\n" , adap->name); pm_runtime_no_callbacks(&adap->dev); pm_suspend_ignore_children(&adap->dev, true ); pm_runtime_enable(&adap->dev); #ifdef CONFIG_I2C_COMPAT res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev, adap->dev.parent); if (res) dev_warn(&adap->dev, "Failed to create compatibility class link\n" ); #endif i2c_init_recovery(adap); of_i2c_register_devices(adap); i2c_acpi_register_devices(adap); i2c_acpi_install_space_handler(adap); if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); mutex_lock(&core_lock); bus_for_each_drv(&i2c_bus_type, NULL , adap, __process_new_adapter); mutex_unlock(&core_lock); return 0 ; out_list: mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); mutex_unlock(&core_lock); return res; }
这个函数对adapte进行了一些错误检查,并进一步对它进行初始化,并将其注册进i2c总线,该函数还会调用 of_i2c_register_devices 创建 dts中对应的 i2c 设备相关的 i2c_client,看看它怎么做的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 static void of_i2c_register_devices (struct i2c_adapter *adap) { struct device_node *bus , *node ; struct i2c_client *client ; if (!adap->dev.of_node) return ; dev_dbg(&adap->dev, "of_i2c: walking child nodes\n" ); bus = of_get_child_by_name(adap->dev.of_node, "i2c-bus" ); if (!bus) bus = of_node_get(adap->dev.of_node); for_each_available_child_of_node(bus, node) { if (of_node_test_and_set_flag(node, OF_POPULATED)) continue ; client = of_i2c_register_device(adap, node); if (IS_ERR(client)) { dev_warn(&adap->dev, "Failed to create I2C device for %s\n" , node->full_name); of_node_clear_flag(node, OF_POPULATED); } } of_node_put(bus); }
这个函数就是检测adap的硬件总线控制器设备节点是否存在,如果存在则对该总线节点的每一个子节点执行 of_i2c_register_device 函数,来看看它干了什么。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 &i2c0 { cap_touch@24 { compatible = "mediatek,cap_touch" ; reg = <0x24 >; interrupt-parent = <&pio>; interrupts = <0 IRQ_TYPE_EDGE_FALLING 0 0 >; int -gpio = <&pio 0 0 >; rst-gpio = <&pio 174 0 >; status = "okay" ; }; }; static struct i2c_client *of_i2c_register_device (struct i2c_adapter *adap, struct device_node *node) { struct i2c_client *result ; struct i2c_board_info info = {}; struct dev_archdata dev_ad = {}; const __be32 *addr_be; u32 addr; int len; dev_dbg(&adap->dev, "of_i2c: register %s\n" , node->full_name); 这里将返回 cap_touch 并将其存入 info.type if (of_modalias_node(node, info.type, sizeof (info.type)) < 0 ) { dev_err(&adap->dev, "of_i2c: modalias failure on %s\n" , node->full_name); return ERR_PTR(-EINVAL); } addr_be = of_get_property(node, "reg" , &len); if (!addr_be || (len < sizeof (*addr_be))) { dev_err(&adap->dev, "of_i2c: invalid reg on %s\n" , node->full_name); return ERR_PTR(-EINVAL); } addr = be32_to_cpup(addr_be); if (addr & I2C_TEN_BIT_ADDRESS) { addr &= ~I2C_TEN_BIT_ADDRESS; info.flags |= I2C_CLIENT_TEN; } if (addr & I2C_OWN_SLAVE_ADDRESS) { addr &= ~I2C_OWN_SLAVE_ADDRESS; info.flags |= I2C_CLIENT_SLAVE; } if (i2c_check_addr_validity(addr, info.flags)) { dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n" , addr, node->full_name); return ERR_PTR(-EINVAL); } info.addr = addr; info.of_node = of_node_get(node); info.archdata = &dev_ad; if (of_get_property(node, "wakeup-source" , NULL )) info.flags |= I2C_CLIENT_WAKE; result = i2c_new_device(adap, &info); if (result == NULL ) { dev_err(&adap->dev, "of_i2c: Failure registering %s\n" , node->full_name); of_node_put(node); return ERR_PTR(-EINVAL); } return result; }
这个函数创建了一个局部的i2c_board_info结构,从dts中获取到i2c子设备相关信息并将其初始化之后,将作为参数用于创建i2c_client,看看i2c_new_device怎么创建一个新的i2c设备。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 struct i2c_client *i2c_new_device (struct i2c_adapter *adap, struct i2c_board_info const *info) { struct i2c_client *client ; int status; client = kzalloc(sizeof *client, GFP_KERNEL); if (!client) return NULL ; client->adapter = adap; client->dev.platform_data = info->platform_data; if (info->archdata) client->dev.archdata = *info->archdata; client->flags = info->flags; client->addr = info->addr; client->irq = info->irq; strlcpy(client->name, info->type, sizeof (client->name)); status = i2c_check_addr_validity(client->addr, client->flags); if (status) { dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n" , client->flags & I2C_CLIENT_TEN ? 10 : 7 , client->addr); goto out_err_silent; } status = i2c_check_addr_busy(adap, i2c_encode_flags_to_addr(client)); if (status) goto out_err; client->dev.parent = &client->adapter->dev; client->dev.bus = &i2c_bus_type; client->dev.type = &i2c_client_type; client->dev.of_node = info->of_node; client->dev.fwnode = info->fwnode; i2c_dev_set_name(adap, client); status = device_register(&client->dev); if (status) goto out_err; dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n" , client->name, dev_name(&client->dev)); return client; out_err: dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x (%d)\n" , client->name, client->addr, status); out_err_silent: kfree(client); return NULL ; }
到此为止就完成了i2c0节点下的cap_touch的设备注册,of_i2c_register_devices函数会遍历i2c0节点下的子节点并依次进行注册。
最后在来对整个注册流程进行一个梳理,对应前面的框图,对于mtk平台对每一个i2c总线节点都会注册一个adapter,在adapter注册的时候后会遍历子节点下的每个i2c设备并创建对应的i2c设备结构client。而在创建过程中会用到一个中间结构 i2c_board_info,它用于描述i2c设备的硬件信息,在注册完成之后就被释放掉。
2、通过总线号添加i2c设备
这种方法适用于许多I2C总线是系统总线的嵌入式系统。 在这样的系统上,每个I2C总线都有一个事先已知的编号。 因此可以预先声明该总线上的I2C设备。 这是通过调用i2c_register_board_info()注册的struct i2c_board_info数组完成的,在没有dts之前使用的就是这种方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #define I2C_BOARD_INFO(dev_type, dev_addr) \ .type = dev_type, .addr = (dev_addr) static struct i2c_board_info h4_i2c_board_info [] __initdata = { { I2C_BOARD_INFO("isp1301_omap" , 0x2d ), .irq = OMAP_GPIO_IRQ(125 ), }, { I2C_BOARD_INFO("24c01" , 0x52 ), .platform_data = &m24c01, }, { I2C_BOARD_INFO("24c01" , 0x57 ), .platform_data = &m24c01, }, }; static void __init omap_h4_init (void ) { (...) i2c_register_board_info(1 , h4_i2c_board_info, ARRAY_SIZE(h4_i2c_board_info)); (...) }
上面的代码在I2C总线1上声明了3个设备,包括它们各自的地址和其驱动程序所需的自定义数据。 注册I2C总线查询后,I2C内核将自动实例化I2C设备。以s3c2410为例进行分析,代码路径:drivers/i2c/busses/i2c-s3c2410.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 static int s3c24xx_i2c_probe (struct platform_device *pdev) { struct s3c24xx_i2c *i2c ; struct s3c2410_platform_i2c *pdata = NULL ; struct resource *res ; int ret; strlcpy(i2c->adap.name, "s3c2410-i2c" , sizeof (i2c->adap.name)); i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &s3c24xx_i2c_algorithm; i2c->adap.retries = 2 ; i2c->adap.class = I2C_CLASS_DEPRECATED; i2c->tx_setup = 50 ; i2c->adap.algo_data = i2c; i2c->adap.dev.parent = &pdev->dev; i2c->adap.nr = i2c->pdata->bus_num; i2c->adap.dev.of_node = pdev->dev.of_node; ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0 ) { pm_runtime_disable(&pdev->dev); s3c24xx_i2c_deregister_cpufreq(i2c); clk_unprepare(i2c->clk); return ret; }
同样是初始化adapter相关参数并向内核注册adapter
1 2 3 i2c_add_numbered_adapter-> __i2c_add_numbered_adapter-> i2c_register_adapter
最后还是调用 i2c_register_adapter 这个函数来看看这种方式调用的是什么函数
1 2 3 4 5 6 7 8 9 10 11 static int i2c_register_adapter (struct i2c_adapter *adap) { int res = -EINVAL; if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); }
由于前面已经分析过这个函数,就直接给出关键代码,在这句代码中发现一个参数 __i2c_first_dynamic_bus_num 这是一个内核创建的全来表示当前局整型变量用的i2c总线的数量,这个机制的一个特点就是i2c总线的数量是由设备注册的时候添加的。它是什么时候添加的呢?先往下看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 static void i2c_scan_static_board_info (struct i2c_adapter *adapter) { struct i2c_devinfo *devinfo ; down_read(&__i2c_board_lock); list_for_each_entry(devinfo, &__i2c_board_list, list ) { if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info)) dev_err(&adapter->dev, "Can't create device at 0x%02x\n" , devinfo->board_info.addr); } up_read(&__i2c_board_lock); }
可以看出这个函数很简单,就是遍历 __i2c_board_list 链表,找到其中挂接在 adapter->nr 上的设备, 然后使用它的设备信息调用 i2c_new_device 创建一个 i2c_client 设备。 设备信息是通过 i2c_register_board_info 注册的,来看一下这个函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 int i2c_register_board_info (int busnum, struct i2c_board_info const *info, unsigned len) { int status; down_write(&__i2c_board_lock); printk("i2c_register_board_info busnum = %d\n" ,busnum); if (busnum >= __i2c_first_dynamic_bus_num) __i2c_first_dynamic_bus_num = busnum + 1 ; for (status = 0 ; len; len--, info++) { struct i2c_devinfo *devinfo ; devinfo = kzalloc(sizeof (*devinfo), GFP_KERNEL); if (!devinfo) { pr_debug("i2c-core: can't register boardinfo!\n" ); status = -ENOMEM; break ; } devinfo->busnum = busnum; devinfo->board_info = *info; list_add_tail(&devinfo->list , &__i2c_board_list); } up_write(&__i2c_board_lock); return status; }
我们看见这个函数的功能很简单,当前 busnum 大于 __i2c_first_dynamic_bus_num 则更新 __i2c_first_dynamic_bus_num ,总线数量其实是在添加设备信息的时候添加的。当添加了设备信息之后将该设备信息链接到 __i2c_board_list 全局链表,__i2c_board_list 维护着由 i2c_register_board_info 注册的设备信息。
整个过程分为两步:
首先 arch/arm/mach-xxx 文件调用 i2c_register_board_info 函数 先向 __i2c_board_list 链表添加板子上的设备信息
然后在调用 drivers/i2c/busses/i2c-xxx 文件向内核注册创建并初始化adapter结构并注册进内核,在内核中遍历 __i2c_board_list 使用挂接在对应adapter上的设备信息 i2c_devinfo->info 创建出对应的i2c_client,调用流程如下:
1 2 3 4 5 6 i2c_add_numbered_adapter-> __i2c_add_numbered_adapter ---> i2c_register_adapter ---> if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); ---> if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info))
3、动态添加i2c设备
前面的两种方式都是静态的方式添加的,就是在内核加载之前先提供i2c设备信息,在加载的时候创建,而内核也提供了动态加载的方法。一个个典型的例子是电视适配器。它们通常是通过I2C总线连接到主芯片的调谐器,视频解码器,音频解码器等。 由于不会事先知道I2C总线的编号,因此无法使用上述方法1和2。
1 2 3 4 5 6 7 8 9 10 11 12 static struct i2c_board_info sfe4001_hwmon_info = { I2C_BOARD_INFO("max6647" , 0x4e ), }; int sfe4001_init (struct efx_nic *efx) { efx->board_info.hwmon_client = i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info); }
使用这个方式自己创建出一个 i2c_board_info 结构,并直接调用函数 i2c_new_device 创建一个i2c_client.上面的代码实例化了所讨论的网络适配器上I2C总线上的1个I2C设备,这个方式是动态的添加一个 i2c_client 的方式,使用这个方式的原因是我们事先不知道,我们的设备会挂在哪个i2c总线上。这种情况下还有一种可能就是我们不知道,总线上是否存在这样一个设备,我们想在创建前先检测这个总线是否存在这个设备于是可以使用下面的方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 static const unsigned short normal_i2c[] = { 0x2c , 0x2d , I2C_CLIENT_END };static int usb_hcd_nxp_probe (struct platform_device *pdev) { struct i2c_adapter *i2c_adap ; struct i2c_board_info i2c_info ; i2c_adap = i2c_get_adapter(2 ); memset (&i2c_info, 0 , sizeof (struct i2c_board_info)); strlcpy(i2c_info.type, "isp1301_nxp" , I2C_NAME_SIZE); isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info, normal_i2c, NULL ); i2c_put_adapter(i2c_adap); }
上面的代码在所讨论的OHCI适配器上的I2C总线上最多实例化1个I2C设备。 它首先尝试在地址0x2c处进行尝试,如果在该位置未找到任何内容,则尝试在地址0x2d中进行处理,如果仍然找不到任何内容,则放弃。这里面有个关键函数 i2c_new_probed_device 来看看这个函数的实现原理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 struct i2c_client *i2c_new_probed_device (struct i2c_adapter *adap, struct i2c_board_info *info, unsigned short const *addr_list, int (*probe)(struct i2c_adapter *, unsigned short addr)) { int i; if (!probe) probe = i2c_default_probe; for (i = 0 ; addr_list[i] != I2C_CLIENT_END; i++) { if (i2c_check_7bit_addr_validity_strict(addr_list[i]) < 0 ) { dev_warn(&adap->dev, "Invalid 7-bit address 0x%02x\n" , addr_list[i]); continue ; } if (i2c_check_addr_busy(adap, addr_list[i])) { dev_dbg(&adap->dev, "Address 0x%02x already in use, not probing\n" , addr_list[i]); continue ; } if (probe(adap, addr_list[i])) break ; } if (addr_list[i] == I2C_CLIENT_END) { dev_dbg(&adap->dev, "Probing failed, no device found\n" ); return NULL ; } info->addr = addr_list[i]; return i2c_new_device(adap, info); } static int i2c_default_probe (struct i2c_adapter *adap, unsigned short addr) { int err; union i2c_smbus_data dummy ; #ifdef CONFIG_X86 if (addr == 0x73 && (adap->class & I2C_CLASS_HWMON) && i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE_DATA)) err = i2c_smbus_xfer(adap, addr, 0 , I2C_SMBUS_READ, 0 , I2C_SMBUS_BYTE_DATA, &dummy); else #endif if (!((addr & ~0x07 ) == 0x30 || (addr & ~0x0f ) == 0x50 ) && i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) err = i2c_smbus_xfer(adap, addr, 0 , I2C_SMBUS_WRITE, 0 , I2C_SMBUS_QUICK, NULL ); else if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE)) err = i2c_smbus_xfer(adap, addr, 0 , I2C_SMBUS_READ, 0 , I2C_SMBUS_BYTE, &dummy); else { dev_warn(&adap->dev, "No suitable probing method supported for address 0x%02X\n" , addr); err = -EOPNOTSUPP; } return err >= 0 ; }
4、动态探测I2C总线添加i2c设备
有时没有足够的有关I2C设备的信息,甚至无法调用i2c_new_probed_device()。典型的情况是PC主板上的硬件监视芯片。有几十种模型,它们可以存在于25个不同的地址。鉴于那里有大量的主板,几乎不可能建立一个完整的硬件监控芯片清单。幸运的是,这些芯片中的大多数都有制造商和设备ID寄存器,因此可以通过探测来识别它们。也就是我们的detect内核中的机制了。在这种情况下,既不声明也不显式实例化I2C设备。取而代之的是,i2c-core会在加载驱动程序后立即探测此类设备,如果找到了驱动程序,则会自动实例化I2C设备 。这也就是 adapter 中 class 成员变量的作用了,内核在加载驱动时会使用驱动提供的地址链表 i2c_driver->address_list,自动去具有同类 class 的 adapter 上探测这个链表上的地址,如果探测到了则实例化驱动
为了防止此机制的任何不当行为,适用以下限制:
I2C设备驱动程序必须实现detect()方法,该方法通过从任意寄存器读取来识别支持的设备。
仅对可能具有受支持设备并同意进行探测的总线进行探测。例如,这避免了在电视适配器上探测硬盘监控芯片的麻烦。
例:请参阅drivers/hwmon/lm90.c中的lm90_driver和lm90_detect()
那些熟悉2.4内核和早期2.6内核的i2c子系统的人会发现,此方法本质上与此处所做的相似。两个重要区别是:
探测只是现在实例化I2C设备的一种方法,而那是那时的唯一方法。在可能的情况下,应首选方法1、2、3。方法4仅应在没有其他方法的情况下使用,因为它可能会产生不良的副作用。
I2C总线必须明确地说明哪些I2C驱动程序类可以对其进行探测(通过类位域),而所有I2C总线默认情值为空类,这意味着不进行探测。类位域的目的是限制上述不希望的副作用。
再一次声明,应尽可能避免使用方法4。显式设备实例化(方法1、2、3)是更可取的,因为它更安全,更快捷。
由于内核不推荐使用这种方式就不详细分析了给出调用流程就行了,感兴趣跟着调用流程看看
1 2 3 4 5 6 7 8 9 10 11 i2c_add_numbered_adapter-> __i2c_add_numbered_adapter ---> i2c_register_adapter ---> bus_for_each_drv(&i2c_bus_type, NULL , adap, __process_new_adapter); ---> i2c_do_add_adapter ---> i2c_detect ---> i2c_detect_address ---> i2c_default_probe driver->detect(temp_client, &info); i2c_new_device list_add_tail(&client->detected, &driver->clients);
这种方式适用于不知道设备被挂在哪个总线上的情况,通过遍历所有的总线,去判断设备是否在总线上,如果存在则调用 driver->detect 进一步获取设备信息,用于完善info结构,如果设备信息完善则创建 i2c_client。
5、从用户空间添加i2c设备
通常,内核应该知道连接了哪些I2C设备以及它们位于什么地址。但是,在某些情况下却没有,因此添加了sysfs接口以让用户提供信息。该接口由2个属性文件组成,new_device和delete_device。这两个文件都是只写的,并且必须为它们写正确的参数,以便正确地创建或删除I2C设备。
创建一个i2c设备
文件 new_device 用于创建一个i2c设备,具有2个参数:I2C设备的名称(字符串)和I2C设备的地址(一个数字,通常以十六进制表示,以0x开头,但也可以以十进制表示。)例如:
1 echo eeprom 0x50>/sys/bus/i2c/devices/i2c-3/new_device
删除一个i2c设备
文件delete_device,用于删除一个i2c设备,具有一个参数:I2C设备的地址。由于在给定的I2C网段上没有两个设备可以住在同一地址,因此该地址足以唯一地标识要删除的设备。例:
1 echo 0x50 >/sys/bus/i2c/devices/i2c-3 /delete_device
来看看内核的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 static ssize_t i2c_sysfs_new_device (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_adapter *adap = to_i2c_adapter(dev); struct i2c_board_info info ; struct i2c_client *client ; char *blank, end; int res; memset (&info, 0 , sizeof (struct i2c_board_info)); blank = strchr (buf, ' ' ); if (!blank) { dev_err(dev, "%s: Missing parameters\n" , "new_device" ); return -EINVAL; } if (blank - buf > I2C_NAME_SIZE - 1 ) { dev_err(dev, "%s: Invalid device name\n" , "new_device" ); return -EINVAL; } memcpy (info.type, buf, blank - buf); res = sscanf (++blank, "%hi%c" , &info.addr, &end); if (res < 1 ) { dev_err(dev, "%s: Can't parse I2C address\n" , "new_device" ); return -EINVAL; } if (res > 1 && end != '\n' ) { dev_err(dev, "%s: Extra parameters\n" , "new_device" ); return -EINVAL; } if ((info.addr & I2C_ADDR_OFFSET_TEN_BIT) == I2C_ADDR_OFFSET_TEN_BIT) { info.addr &= ~I2C_ADDR_OFFSET_TEN_BIT; info.flags |= I2C_CLIENT_TEN; } if (info.addr & I2C_ADDR_OFFSET_SLAVE) { info.addr &= ~I2C_ADDR_OFFSET_SLAVE; info.flags |= I2C_CLIENT_SLAVE; } client = i2c_new_device(adap, &info); if (!client) return -EINVAL; mutex_lock(&adap->userspace_clients_lock); list_add_tail(&client->detected, &adap->userspace_clients); mutex_unlock(&adap->userspace_clients_lock); dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n" , "new_device" , info.type, info.addr); return count; } static DEVICE_ATTR (new_device, S_IWUSR, NULL , i2c_sysfs_new_device) ;static ssize_t i2c_sysfs_delete_device (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_adapter *adap = to_i2c_adapter(dev); struct i2c_client *client , *next ; unsigned short addr; char end; int res; res = sscanf (buf, "%hi%c" , &addr, &end); if (res < 1 ) { dev_err(dev, "%s: Can't parse I2C address\n" , "delete_device" ); return -EINVAL; } if (res > 1 && end != '\n' ) { dev_err(dev, "%s: Extra parameters\n" , "delete_device" ); return -EINVAL; } res = -ENOENT; mutex_lock_nested(&adap->userspace_clients_lock, i2c_adapter_depth(adap)); list_for_each_entry_safe(client, next, &adap->userspace_clients, detected) { if (i2c_encode_flags_to_addr(client) == addr) { dev_info(dev, "%s: Deleting device %s at 0x%02hx\n" , "delete_device" , client->name, client->addr); list_del(&client->detected); i2c_unregister_device(client); res = count; break ; } } mutex_unlock(&adap->userspace_clients_lock); if (res < 0 ) dev_err(dev, "%s: Can't find device in list\n" , "delete_device" ); return res; } static DEVICE_ATTR_IGNORE_LOCKDEP (delete_device, S_IWUSR, NULL , i2c_sysfs_delete_device) ;static struct attribute *i2c_adapter_attrs [] = { &dev_attr_name.attr, &dev_attr_new_device.attr, &dev_attr_delete_device.attr, NULL }; ATTRIBUTE_GROUPS(i2c_adapter);
可以看见其实很简单,就是获取初入的name和addr动态初始化一个info,然后利用 new_device 函数创建一个i2c_client ,这种方式和方式2是一样的,只是将方式2开放给用户空间一个接口。
6、acpi方式添加
参考: kernel-4.9/Documentation/acpi/enumeration.txt.
三、获取 i2c_client 结构
有了具体的设备结构 i2c_client, 我们要怎么用呢,比如我想向i2c0上的 cap_touch 发送数据,怎么获取到对应的 i2c_client 结构呢?很简单因为 i2c_client 被挂接到了 i2c 总线上,因此我们只需要向 i2c 总线上注册一个 i2c_driver ,并且使用要用到的 i2c_client 的name作为 i2c_driver 的 i2c_device_id->name。那么总线就会去匹配和 i2c_device_id->name 相同 name 的 i2c_client(这是i2c总线的match函数匹配规则),匹配成功则调用driver的probe成员函数并且将i2c_client作为参数传入,这样我们就获取到了我们想要的具体的 i2c_client 设备结构。 于是想要获取到 cap_touch 的 i2c_client 的示例代码如下(代码并不完整这只是一个伪代码):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 int my_i2c_probe (struct i2c_client *client, const struct i2c_device_id *id) { printk("my_drv_probe\n" ); return 0 ; } int my_i2c_remove (struct i2c_client * client) { printk("my_drv_remove\n" ); return 0 ; } static const struct i2c_device_id my_id_table [] = { { "cap_touch" , 0 }, { NULL , 0 }, }; static struct i2c_driver my_i2c_driver = { .probe = my_i2c_probe, .remove = my_i2c_remove, .driver = { .name = "cap_touch" , }, .id_table = my_id_table, }; static int my_i2c_init (void ) { i2c_add_driver(&my_i2c_driver); return 0 ; } static void my_i2c_exit (void ) { } module_init(my_i2c_init); module_exit(my_i2c_exit);
i2c_add_driver 的内部工作原理到底是怎么样的呢,看看源码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #define i2c_add_driver(driver) \ i2c_register_driver(THIS_MODULE, driver) int i2c_register_driver (struct module *owner, struct i2c_driver *driver) { int res; if (WARN_ON(!is_registered)) return -EAGAIN; driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; INIT_LIST_HEAD(&driver->clients); res = driver_register(&driver->driver); if (res) return res; pr_debug("driver [%s] registered\n" , driver->driver.name); i2c_for_each_dev(driver, __process_new_driver); return 0 ; }
调用driver_register这个函数将驱动注册进入内核时,会使用设备模型的匹配机制,和总线上的设备进行匹配。简单描述一下调用流程:
1 2 3 4 5 6 7 8 9 10 bus_add_driver----> driver_attach----> 无论如何最终都会调用这个函数 bus_for_each_dev----> __driver_attach----> driver_match_device----> drv->bus->match(dev, drv) really_probe----> dev->bus->probe(dev) drv->probe(dev)
最终调用总线上的match函数 i2c_device_match
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 static int i2c_device_match (struct device *dev, struct device_driver *drv) { struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver ; if (!client) return 0 ; if (of_driver_match_device(dev, drv)) return 1 ; if (acpi_driver_match_device(dev, drv)) return 1 ; driver = to_i2c_driver(drv); if (driver->id_table) return i2c_match_id(driver->id_table, client) != NULL ; return 0 ; }
从该函数知道,i2c总线提供了3中匹配的方式,无论是什么方式都是获取我们需要的 i2c_client 结构:
使用设备树 compatible 字段进行匹配
acpi 方式匹配(这个用了再来补充)
使用 id_table方式进行匹配
其中设备树方式在设备模型中已讨论,这种匹配方式只能匹配到设备树中生成的设备,而我们根本不会将 i2c_client 写到设备树中,因此这个匹配方式是匹配不到我们需要的 i2c_client 设备的,我也不知道为什么会写入这种规则,有大佬知道可以告知一下,这里讨论 id_table 方式
1 2 3 4 5 6 7 8 9 10 static const struct i2c_device_id *i2c_match_id (const struct i2c_device_id *id, const struct i2c_client *client) { while (id->name[0 ]) { if (strcmp (client->name, id->name) == 0 ) return id; id++; } return NULL ; }
代码看起来很简单,就是比较 i2c_client->name 和 i2c_device_id->name 是否相同,如果相同则匹配成功,匹配成功后调用总线对应的 probe 函数 i2c_device_probe
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 static int i2c_device_probe (struct device *dev) { struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver ; int status; if (!client) return 0 ; if (!client->irq) { int irq = -ENOENT; if (dev->of_node) { irq = of_irq_get_byname(dev->of_node, "irq" ); if (irq == -EINVAL || irq == -ENODATA) irq = of_irq_get(dev->of_node, 0 ); } else if (ACPI_COMPANION(dev)) { irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0 ); } if (irq == -EPROBE_DEFER) return irq; if (irq < 0 ) irq = 0 ; client->irq = irq; } driver = to_i2c_driver(dev->driver); if (!driver->probe || !driver->id_table) return -ENODEV; if (client->flags & I2C_CLIENT_WAKE) { int wakeirq = -ENOENT; if (dev->of_node) { wakeirq = of_irq_get_byname(dev->of_node, "wakeup" ); if (wakeirq == -EPROBE_DEFER) return wakeirq; } device_init_wakeup(&client->dev, true ); if (wakeirq > 0 && wakeirq != client->irq) status = dev_pm_set_dedicated_wake_irq(dev, wakeirq); else if (client->irq > 0 ) status = dev_pm_set_wake_irq(dev, client->irq); else status = 0 ; if (status) dev_warn(&client->dev, "failed to set up wakeup irq\n" ); } dev_dbg(dev, "probe\n" ); status = of_clk_set_defaults(dev->of_node, false ); if (status < 0 ) goto err_clear_wakeup_irq; status = dev_pm_domain_attach(&client->dev, true ); if (status == -EPROBE_DEFER) goto err_clear_wakeup_irq; status = driver->probe(client, i2c_match_id(driver->id_table, client)); if (status) goto err_detach_pm_domain; return 0 ; err_detach_pm_domain: dev_pm_domain_detach(&client->dev, true ); err_clear_wakeup_irq: dev_pm_clear_wake_irq(&client->dev); device_init_wakeup(&client->dev, false ); return status; }
i2c_device_probe 函数又根据更新了了一次 irq,并最终调用了注册的 i2c_driver 结构的 probe 成员函数。于是在 probe 函数中我们就获取到了我们需要的 i2c_client 结构。内核也提供了一个demo,参考kernel-4.9,Documentation/i2c/upgrading-clients
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 struct example_state { struct i2c_client *client ; .... }; static int example_probe (struct i2c_client *client, const struct i2c_device_id *id) { struct example_state *state ; struct device *dev = &client->dev; state = kzalloc(sizeof (struct example_state), GFP_KERNEL); if (state == NULL ) { dev_err(dev, "failed to create our state\n" ); return -ENOMEM; } state->client = client; i2c_set_clientdata(client, state); dev_info(dev, "example client created\n" ); return 0 ; } static int example_remove (struct i2c_client *client) { struct example_state *state = i2c_get_clientdata(client); kfree(state); return 0 ; } static struct i2c_device_id example_idtable [] = { { "example" , 0 }, { } }; MODULE_DEVICE_TABLE(i2c, example_idtable); static struct i2c_driver example_driver = { .driver = { .owner = THIS_MODULE, .name = "example" , .pm = &example_pm_ops, }, .id_table = example_idtable, .probe = example_probe, .remove = example_remove, };
四、使用 i2c_client 通信
获取到 i2c_client 结构之后,就可以使用它来进行i2c通信了,内核使用 i2c_msg 结构装了传输的数据,每次通讯都是以 i2c_msg 为单位的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 struct i2c_msg { __u16 addr; __u16 flags; #define I2C_M_RD 0x0001 #define I2C_M_TEN 0x0010 #define I2C_M_RECV_LEN 0x0400 #define I2C_M_NO_RD_ACK 0x0800 #define I2C_M_IGNORE_NAK 0x1000 #define I2C_M_REV_DIR_ADDR 0x2000 #define I2C_M_NOSTART 0x4000 #define I2C_M_STOP 0x8000 __u16 len; __u8 *buf; };
1、i2c_master_send
该函数用于向 i2c_client 发送buf指向的数据,数据长度为count字节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 int i2c_master_send (const struct i2c_client *client, const char *buf, int count) { int ret; struct i2c_adapter *adap = client->adapter; struct i2c_msg msg ; msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.len = count; msg.buf = (char *)buf; ret = i2c_transfer(adap, &msg, 1 ); return (ret == 1 ) ? count : ret; } EXPORT_SYMBOL(i2c_master_send);
2、i2c_master_recv
该函数用于向 i2c_client 接收数据长度为count字节的数据,数据被存在buf中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int i2c_master_recv (const struct i2c_client *client, char *buf, int count) { struct i2c_adapter *adap = client->adapter; struct i2c_msg msg ; int ret; msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.flags |= I2C_M_RD; msg.len = count; msg.buf = buf; ret = i2c_transfer(adap, &msg, 1 ); return (ret == 1 ) ? count : ret; } EXPORT_SYMBOL(i2c_master_recv);
3、i2c_transfer
该函数向 i2c_adapter 所表示的总线上传输 num 个 msgs。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 int i2c_transfer (struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { int ret; if (adap->algo->master_xfer) { #ifdef DEBUG for (ret = 0 ; ret < num; ret++) { dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, len=%d%s\n" , ret, (msgs[ret].flags & I2C_M_RD) ? 'R' : 'W' , msgs[ret].addr, msgs[ret].len, (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "" ); } #endif if (in_atomic() || irqs_disabled()) { ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT); if (!ret) return -EAGAIN; } else { i2c_lock_bus(adap, I2C_LOCK_SEGMENT); } ret = __i2c_transfer(adap, msgs, num); i2c_unlock_bus(adap, I2C_LOCK_SEGMENT); return ret; } else { dev_dbg(&adap->dev, "I2C level transfers not supported\n" ); return -EOPNOTSUPP; } } EXPORT_SYMBOL(i2c_transfer);