本文中第1、2、3、4、5、6部分是参考前辈的博客总结https://blog.csdn.net/wangpengqi/article/details/17711165
1.IIC简介
IIC是philips提出的外设总线。
IIC只有两条线,一条串行数据线SDA;一条是时钟线SCL。使用SCL,SDA这两条线就实现了设备之间的数据交互。
2.Linux下的驱动思路
在linux下编写I2C驱动,目前主要有两种方法,一种是把I2C设备当做一个普通字符设备,另一种是利用Linux内核提供的I2C子系统来完成。两种方法有一些区别:
第一种方法:
优点:思路比较直接,不需要花很多时间去了解Linux中复杂的I2C子系统的操作方法。
缺点:要求工程师不仅要对I2C设备的操作熟悉,而且要熟悉I2C的适配器(I2C控制器)操作。
要求工程师对I2C的适配器及I2C的设备操作方法都比较熟悉,最重要的写出的程序可移植性差。
对内核资源无法直接使用,因为内核提供的所有I2C设备,及设备驱动都是基于I2C子系统的格式。
第一种方法的优点就是第二种方法的缺点,第一方法的缺点就是第二种方法的优点。
3.I2C架构概述
Linux下的I2C体系结构分为3个组成部分:
I2C核心:I2C核心提供了I2C总线驱动和设备驱动的注册,注销方法,I2C通信方法(algorithm)上层的,与具体适配器无关的代码以及探测设备,检测设备地址的上层代码等。
I2C总线驱动:I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可由CPU控制,甚至可以直接集成在CPU内部。
I2C设备驱动:I2C设备驱动(也称为客户驱动)是对I2C硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。
4.Linux驱动中I2C驱动架构
上图中完整的描述了Linux I2C驱动架构,虽然I2C硬件体系结构比较简单,但是I2C体系结构在Linux中的实现却相当复杂。
那么我们如何编写特定的I2C接口器件的驱动程序?就是说上述架构中有哪些是需要我们完成,而哪些是Linux内核已经完善的或者是芯片厂商提供的。
5.架构层次分类
第一层:提供i2c adapter的硬件驱动,探测,初始化i2c adapter(如申请i2c的io地址和中断号)驱动soc控制的i2c adapter在硬件上产生信号(stop,start,ack)以及处理I2c中断。覆盖图中硬件实现层。
第二层:提供i2c adapter 的algorithm,用具体适配器的xxx_xferf()函数来填充i2c_algorithm的master_xfer函数指针,并把赋值后的i2c_algorithm再赋值给i2c_adapter的algo指针。覆盖图中的访问抽象层、i2c核心层。
第三层:实现i2c设备驱动中的i2c_driver接口,用具体的i2c device设备attch_adapter();detach_adapter();方法赋值给i2c_driver的成员函数指针。实现设备device与总线(或者叫adapter)的挂接。覆盖图中driver驱动层。
第四层:实现i2c设备所对应的具体device的驱动,i2c_driver只是实现设备与总线的挂接,而挂接在总线上的设备则是千差万别的,所以要实现具体的设备device的read(),write(),ioctl();等方法,赋值给file_operations,然后注册字符设备(多数是字符设备),覆盖图中的driver驱动层。
第一层和第二层又叫i2c总线驱动(bus),第三第四属于i2c设备驱动(device driver)。
在linux驱动架构中,几乎不需要驱动开发人员再添加bus,因为linux内核几乎集成了所有的总线bus,如usb,pci,i2c,等,并且总线bus中的(与特定硬件相关的代码)已经由芯片厂商编写完成,
第三第四层与特定device相关的就需要驱动工程师来实现了。
Linux下I2C体系文件架构
i2c-core.c这个文件实现了I2C核心功能以及/proc/bus/i2c*接口。
i2c-dev.c实现了I2C适配器的设备文件的功能,每个I2c适配器都被分配一个设备。通过适配器访问设备时的主设备号都为89,次设备号为0-255.I2C-dev.c并没有针对特定的设备而设计,只是提供了通用的read(),write(),和ioctl(),等接口。应用层可以借用这些接口访问挂接在适配器上的I2C设备的存储空间或寄存器,并控制I2C设备的工作方式。
busses文件夹,这个文件夹包含了一些I2C总线的驱动,如针对S3C2410、S3C2440等处理器的I2C控制驱动。
algos文件夹实现了一些I2C总线适配器的algorithm。
6.重要的结构体
i2c_driver
struct i2c_driver { unsigned int class; /* Notifies the driver that a new bus has appeared. You should avoid * using this, it will be removed in a near future. */ int (*attach_adapter)(struct i2c_adapter *) __deprecated;//依附i2c_adapter函数指针 /* Standard driver model interfaces */ int (*probe)(struct i2c_client *, const struct i2c_device_id *); int (*remove)(struct i2c_client *); /* driver model interfaces that don't relate to enumeration */ void (*shutdown)(struct i2c_client *); int (*suspend)(struct i2c_client *, pm_message_t mesg); int (*resume)(struct i2c_client *); /* Alert callback, for example for the SMBus alert protocol. * The format and meaning of the data value depends on the protocol. * For the SMBus alert protocol, there is a single bit of data passed * as the alert response's low bit ("event flag"). */ void (*alert)(struct i2c_client *, unsigned int data); /* a ioctl like command that can be used to perform specific functions * with the device. */ int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);//命令列表 struct device_driver driver; const struct i2c_device_id *id_table;//该驱动所支持的设备ID表 /* Device detection callback for automatic device creation */ int (*detect)(struct i2c_client *, struct i2c_board_info *); const unsigned short *address_list; struct list_head clients; };i2c_client
struct i2c_client { unsigned short flags; /* div., see below *///标志 unsigned short addr; /* chip address - NOTE: 7bit *///低7位为芯片地址 /* addresses are stored in the */ /* _LOWER_ 7 bits */ char name[I2C_NAME_SIZE]; //设备名称 struct i2c_adapter *adapter; /* the adapter we sit on *///依附的i2c_adapter struct i2c_driver *driver; /* and our access routines *///依附的i2c_driver struct device dev; /* the device structure *///设备结构体 int irq; /* irq issued by device *///链表头 struct list_head detected; };i2c_adapter
struct i2c_adapter { struct module *owner; //所属模块 unsigned int class; /* classes to allow probing for */ const struct i2c_algorithm *algo; /* the algorithm to access the bus *///总线通信方法指针 void *algo_data; //algorithm数据 /* data fields that are valid for all devices */ struct rt_mutex bus_lock; //控制并发访问的自旋锁 int timeout; /* in jiffies */ int retries; //重试次数 struct device dev; /* the adapter device */ //适配器设备 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; };
i2c_algorithm
struct i2c_algorithm { /* If an adapter algorithm can't do I2C-level access, set master_xfer to NULL. If an adapter algorithm can do SMBus access, set smbus_xfer. If set to NULL, the SMBus protocol is simulated using common I2C messages */ /* master_xfer should return the number of messages successfully processed, or a negative value on error */ int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,//i2c传输函数指针 int num); int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,//smbus传输函数指针 unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data); /* To determine what the adapter supports */ u32 (*functionality) (struct i2c_adapter *);//返回适配器支持的功能 };
各结构体的作用与他们之间的关系
i2c_adapter与i2c_algorithm
i2c_adapter对应物理上的一个适配器,也就是指的是CPU内部的I2C控制器,一个CPU内部可能有多个I2c适配器。而i2c_algorithm对应一套通信方法,一个i2c适配器需要i2c_algorithm中提供的通信函数来控制适配器产生特定的访问周期,缺少i2c_algorithm的i2c_adapter什么也做不了,因此i2c_adapter中包含其使用i2c_algorithm的指针。
i2c_algorithm
i2c_algorithm中的关键函数master_xfer()用于产生i2c访问周期需要的start stop ack信号,以i2c_msg(即i2c消息)为单位发送和接收通信数据。
i2c_msg也非常关键,调用驱动中的发送接收函数需要填充该结构体。
struct i2c_msg { __u16 addr; /* slave address */ __u16 flags; __u16 len; /* msg length */ __u8 *buf; /* pointer to msg data */ };
i2c_driver和i2c_client
i2c_driver对应一套驱动方法,其主要是驱动我们的i2c设备的,比如设备的初始化等等。
i2c_client对应真实的i2c屋里设备device,每个i2c设备都需要一个i2c_client来描述。
i2c_driver与i2c_client的关系是一对多,一个i2cdriver可以支持多个同类型的i2c_client.但必须是同类型的。
i2c_adapter和i2c_client的关系是i2c硬件体系中适配器和设备的关系,即i2c_client依附于i2c_adapter,由于一个适配器上可以连接多个i2c设备,所以i2c_adapter中包含依附于它的i2c_client的链表。
从i2c驱动架构图中可以看出,linux内核对i2c架构抽象了一个核心层core的中间件,它分离了设备驱动device driver和硬件控制的实现细节,core不但为下层的设备驱动提供了封装后的内核注册函数,而且还未硬件事件提供了注册接口(也就是i2c总线注册接口)。可以说core起到了承上启下的作用。
7.i2c驱动和设备的匹配过程
以一个tp驱动来详细说明i2c驱动和设备的注册过程。先说设备的注册过程。
7.1. i2c设备的注册过程
自从内核引入设备树以后,很多设备的注册都是通过设备树来完成的,i2c adapter和i2c设备也不例外。我们来看下dts文件中对i2c adapter的描述。
i2c0: i2c@e0170000 {
compatible = "actions,s700-i2c";
reg = <0 0xe0170000 0 0x1000>;
interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&clock CLK_I2C0>;
clock-names = "i2c0";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c0_default>;
status = "disabled";
};
i2c1: i2c@e0174000 {
compatible = "actions,s700-i2c";
reg = <0 0xe0174000 0 0x1000>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&clock CLK_I2C1>;
clock-names = "i2c1";
//pinctrl-names = "default";
//pinctrl-0 = <&pinctrl_i2c1_default>;
status = "disabled";
};
i2c2: i2c@e0178000 {
........}; i2c3: i2c@e017c000 {
........};
从上面可以看出这个CPU内有四个i2c adapter。关于适配器一端的相关驱动一般是有芯片厂商完成的,在内核中kernel/drivers/i2c/busses$目录下。我用的炬芯的芯片,可以看下它是怎么实现的。
static const struct of_device_id owl_i2c_dt_ids[] = { {.compatible = "actions,s900-i2c"}, {.compatible = "actions,s700-i2c"}, //将会与设备树中的compatible字段匹配。 {.compatible = "actions,ats3605-i2c"}, {}, }; MODULE_DEVICE_TABLE(of, owl_i2c_dt_ids); static struct platform_driver owl_i2c_driver = { .probe = owl_i2c_probe, .remove = owl_i2c_remove, .driver = { .name = "i2c-owl", .owner = THIS_MODULE, .of_match_table = of_match_ptr(owl_i2c_dt_ids), }, }; static int __init owl_i2c_init(void) { return platform_driver_register(&owl_i2c_driver); //将本驱动注册为平台设备驱动 } subsys_initcall(owl_i2c_init);//驱动入口
由设备树相关知识知道,设备树解析以后会将设备树内的设备添加并注册到设备链表内,本驱动将owl_i2c_driver驱动注册为平台设备后,如果能够在设备链表中匹配到与owl_i2c_driver中of_match_table中complatibale字段相同的名字,那么久去执行owl_i2c_driver的probe函数。
看一下probe函数。
static struct i2c_algorithm owl_i2c_algorithm = { .master_xfer = owl_i2c_xfer, //芯片厂商提供的i2c_algorithm通信方法,不需要用户去实现。 .functionality = owl_i2c_func, };
static int owl_i2c_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct owl_i2c_dev *dev;
struct i2c_adapter *adap;
struct resource *res;
int ret;
u32 phy_addr;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
init_completion(&dev->cmd_complete);
dev->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
phy_addr = res->start;
dev->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dev->base))
return PTR_ERR(dev->base);
dev->phys = res->start;
dev->irq = platform_get_irq(pdev, 0);
if (dev->irq < 0)
return dev->irq;
ret = devm_request_irq(&pdev->dev, dev->irq, owl_i2c_interrupt, 0,
dev_name(dev->dev), dev);
if (ret) {
dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, ret);
return ret;
}
platform_set_drvdata(pdev, dev);
adap = &dev->adapter;
snprintf(dev->adapter.name, sizeof(dev->adapter.name),
"OWL I2C adapter");
i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_HWMON;
adap->algo = &owl_i2c_algorithm; //注册一下i2c_algorithm指针
adap->timeout = OWL_I2C_TIMEOUT;
adap->dev.parent = dev->dev;
adap->dev.of_node = pdev->dev.of_node;
adap->nr = pdev->id;
ret = i2c_add_numbered_adapter(adap);
if (ret) {
dev_err(dev->dev, "Adapter %s registration failed\n",
adap->name);
clk_disable_unprepare(dev->clk);
return ret;
}
of_i2c_register_devices(adap); //of解析设备树,注册i2c设备,也就是client设备
dev_info(dev->dev, "I2C adapter ready to operate.\n");
return 0;
}
因此,本probe函数要执行四次,因为在设备树dts文件中有四个匹配到的i2c适配器。其中重要的是函数i2c_add_numbered_adapter 和of_i2c_register_devices(adap);
int i2c_add_numbered_adapter(struct i2c_adapter *adap) { if (adap->nr == -1) /* -1 means dynamically assign bus id */ return i2c_add_adapter(adap); return __i2c_add_numbered_adapter(adap); //里面调用i2c_register_adapter } static int i2c_register_adapter(struct i2c_adapter *adap) { int res = 0; rt_mutex_init(&adap->bus_lock); mutex_init(&adap->userspace_clients_lock); INIT_LIST_HEAD(&adap->userspace_clients); /* Set default timeout to 1 second if not already set */ if (adap->timeout == 0) adap->timeout = HZ; dev_set_name(&adap->dev, "i2c-%d", adap->nr); //设置adapter的name adap->dev.bus = &i2c_bus_type; //设置adapter的dev,bus为i2c_bus_type adap->dev.type = &i2c_adapter_type; res = device_register(&adap->dev); //将adapter注册进内核中的设备链表 if (res) goto out_list; dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); #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_adapter注册进系统中了,接下来看看of_i2c_register_devices(adap);
void of_i2c_register_devices(struct i2c_adapter *adap) { void *result; struct device_node *node; /* Only register child devices if the adapter has a node pointer set */ if (!adap->dev.of_node) return; for_each_available_child_of_node(adap->dev.of_node, node) { //遍历i2c adapter节点下的所有子节点。下文中的dts中adapter下有两个子节点。 struct i2c_board_info info = {}; struct dev_archdata dev_ad = {}; const __be32 *addr; int len; dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name); 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); continue; } addr = of_get_property(node, "reg", &len); //获取i2c设备地址 if (!addr || (len < sizeof(int))) { dev_err(&adap->dev, "of_i2c: invalid reg on %s\n", node->full_name); continue; } info.addr = be32_to_cpup(addr); if (info.addr > (1 << 10) - 1) { dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n", info.addr, node->full_name); continue; } info.irq = irq_of_parse_and_map(node, 0);//获取i2c设备中段 info.of_node = of_node_get(node); info.archdata = &dev_ad; if (of_get_property(node, "wakeup-source", NULL)) info.flags |= I2C_CLIENT_WAKE; request_module("%s%s", I2C_MODULE_PREFIX, info.type); result = i2c_new_device(adap, &info); //创建一个i2c设备 ,这个设备也就是下面代码中描述的i2c设备节点 if (result == NULL) { dev_err(&adap->dev, "of_i2c: Failure registering %s\n", node->full_name); of_node_put(node); irq_dispose_mapping(info.irq); continue; } } }
来看一下设备树中是怎么定义的,
i2c1: i2c@e0174000 {
clock-frequency = <400000>;
status = "okay";
mpu6500@68 {
compatible = "owl-gyrosensor";
interrupt-parent = <&gpioa>;
interrupts = <24>;
gpios = <&gpioa 24 0>; /* GPIOA24 */
i2c_adapter_id = <1>;
/*gyro_vcc = "ldo7";*/
/*vol_range = <1800000 1810000>;*/
MASTER_inv6500_position = "3";
SECONDARY_ak8963c_position = "3";
};
ft5x06@38 {
compatible = "ft5x06"; //非常重要,下文中会用到
reg = <0x38>;
tp_vcc = "ldo5";
reset_gpios = <&gpioc 27 1>; /*GPIOB(3) 0: high, 1: low*/
max_points = <10>;
x_pixel = <1024>;
y_pixel = <600>;
x_revert_en = <0>;
y_revert_en = <1>;
xy_swap_en = <0>;
rotate_degree = <270>; /* 0 90 180 270 */
interrupt-parent = <&sirq>;
interrupts =< 0 0x4 >; /*SIRQ0*/
vol_range = <3100000 3110000>;
};
};
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); //分配一个i2c_client结构体 if (!client) return NULL; client->adapter = adap; //这个client依附在adapter下 client->dev.platform_data = info->platform_data; if (info->archdata) client->dev.archdata = *info->archdata; client->flags = info->flags; client->addr = info->addr; //对i2c client的一些初始化,这些都是dts设备树中定义的值 client->irq = info->irq; strlcpy(client->name, info->type, sizeof(client->name)); //client name /* Check for address validity */ status = i2c_check_client_addr_validity(client); 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; } /* Check for address business */ status = i2c_check_addr_busy(adap, client->addr); if (status) goto out_err; client->dev.parent = &client->adapter->dev; client->dev.bus = &i2c_bus_type; //指定i2c_client->dev.bus为i2c_bus_type,后面会用到 client->dev.type = &i2c_client_type; client->dev.of_node = info->of_node; //综合上面,构造出了一个client结构体,并对其初始化,这个client就是描述的一个具体的i2c设备。 ACPI_HANDLE_SET(&client->dev, info->acpi_node.handle); /* For 10-bit clients, add an arbitrary offset to avoid collisions */ dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), client->addr | ((client->flags & I2C_CLIENT_TEN) ? 0xa000 : 0)); status = device_register(&client->dev); //将client->dev注册进内核中取。 bus_add_device(struct device *dev) klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);//Add the device to its bus's list of devices. //也就是将这个设备添加到其所在的bus 的链表中.上文中指定了client->dev.bus = &i2c_bus_type;
至此,内核中的i2c adapter 以及i2c设备已经全部注册完了,这些跟设备树紧密结合。
7.2. i2c驱动的注册过程
我们来一起看下i2c设备驱动是怎么注册进内核中去的,
static struct of_device_id ft5x06_of_match[] = { { .compatible = "ft5x06" }, //重要,在驱动和设备的匹配过程中会用到 { } }; MODULE_DEVICE_TABLE(i2c, ft5x06_id); static struct i2c_driver ft5x06_driver = { .driver = { .owner = THIS_MODULE, .name = FT5X06_NAME, .of_match_table = of_match_ptr(ft5x06_of_match), }, .class = I2C_CLASS_HWMON, .probe = ft5x06_probe, .remove = ft5x06_remove, .suspend = ft5x06_suspend, .resume = ft5x06_resume, .id_table = ft5x06_id, };
static int touch_ft5x06_init(void) { int err = 0, i = 0; struct i2c_client *client = NULL; tp_config_init(); #if CFG_FT_USE_CONFIG err = tp_of_data_get(); if (err < 0) { printk("ft get config err!!!"); return err; } tp_info.addr = cfg_dts.i2cAddr; ft5x06_hw_init(); //i2c设备硬件的一些初始化工作 err = i2c_add_driver(&ft5x06_driver); //重点,添加i2c驱动, 后面会重点分析, if (err) { FT5X06_WARNNING("add i2c driver failed"); goto out; } list_for_each_entry(client, &(ft5x06_driver.clients), detected) { for (i = 0; i < ARRAY_SIZE(ft5x06_attr); i++) { err = device_create_file(&client->dev, &ft5x06_attr[i]); if (err) { FT5X06_WARNNING("Add device file failed"); goto out; } } } out: printlf(); return err; }
其实tp的驱动中就只调用了个i2c_add_driver函数把i2c设备端的驱动ft5x06_driver注册进去。我们接下来进去看一下。
#define i2c_add_driver(driver) \
i2c_register_driver(THIS_MODULE, driver)
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
/* Can't register until after driver model init */
if (unlikely(WARN_ON(!i2c_bus_type.p)))
return -EAGAIN;
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type; //指定driver->driver.bus为i2c_bus_type,这个后面会用到
/* When registration returns, the driver core
* will have called probe() for all matching-but-unbound devices.
*/
res = driver_register(&driver->driver); //将ft5x06_driver->driver注册进去
INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */
i2c_for_each_dev(driver, __process_new_driver);
return 0;
}
EXPORT_SYMBOL(i2c_register_driver);
接下来我们看下i2c设备和驱动最精彩的匹配过程。
7.3. i2c设备和驱动的匹配过程
从上文中的 driver_register(&driver->driver);说起int driver_register(struct device_driver *drv) { int ret; struct device_driver *other; BUG_ON(!drv->bus->p); if ((drv->bus->probe && drv->probe) || (drv->bus->remove && drv->remove) || (drv->bus->shutdown && drv->shutdown)) printk(KERN_WARNING "Driver '%s' needs updating - please use " "bus_type methods\n", drv->name); other = driver_find(drv->name, drv->bus); //在bus上查找一下看有无相同名字的driver注册过 if (other) { printk(KERN_ERR "Error: Driver '%s' is already registered, " "aborting...\n", drv->name); return -EBUSY; } ret = bus_add_driver(drv); //将这个drv添加到对应的bus上 if (ret) return ret; ret = driver_add_groups(drv, drv->groups); if (ret) { bus_remove_driver(drv); return ret; } kobject_uevent(&drv->p->kobj, KOBJ_ADD); return ret; } EXPORT_SYMBOL_GPL(driver_register);
int bus_add_driver(struct device_driver *drv) { struct bus_type *bus; struct driver_private *priv; int error = 0; bus = bus_get(drv->bus); if (!bus) return -EINVAL; pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name); priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { error = -ENOMEM; goto out_put_bus; } klist_init(&priv->klist_devices, NULL, NULL); priv->driver = drv; drv->p = priv; priv->kobj.kset = bus->p->drivers_kset; error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, "%s", drv->name); if (error) goto out_unregister; klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); if (drv->bus->p->drivers_autoprobe) { //drv->bus->p->drivers_autoprobe 这个值为1,是在bus_register(struct bus_type *bus) error = driver_attach(drv); //函数中设置的,有兴趣的可以去看bus_register函数。这里就不展开了。 if (error) //接着执行最重要的driver_attach goto out_unregister; } module_add_driver(drv->owner, drv) }
int driver_attach(struct device_driver *drv) { return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); }
int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *, void *)) { struct klist_iter i; struct device *dev; int error = 0; if (!bus || !bus->p) return -EINVAL; klist_iter_init_node(&bus->p->klist_devices, &i, (start ? &start->p->knode_bus : NULL)); while ((dev = next_device(&i)) && !error) //对bus中的中每一个dev 都调用fn,fn也就是参数传递进来的__driver_attach函数。 error = fn(dev, data); klist_iter_exit(&i); return error; } EXPORT_SYMBOL_GPL(bus_for_each_dev);
static int __driver_attach(struct device *dev, void *data) { struct device_driver *drv = data; /* * Lock device and try to bind to it. We drop the error * here and always return 0, because we need to keep trying * to bind to devices and some drivers will return an error * simply if it didn't support the device. * * driver_probe_device() will spit a warning if there * is an error. */ if (!driver_match_device(drv, dev)) //首先执行driver_match_device return 0; if (dev->parent) /* Needed for USB */ device_lock(dev->parent); device_lock(dev); if (!dev->driver) driver_probe_device(drv, dev); device_unlock(dev); if (dev->parent) device_unlock(dev->parent); return 0; }
static inline int driver_match_device(struct device_driver *drv, struct device *dev) { return drv->bus->match ? drv->bus->match(dev, drv) : 1;//如果drv->bus->match函数存在则调用drv->bus->match函数 }
这个函数是存在的,在上文7.2节中指定了driver->driver.bus = &i2c_bus_type;
struct bus_type i2c_bus_type = { .name = "i2c", .match = i2c_device_match, .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, .pm = &i2c_device_pm_ops, };
因此drv->bus->match函数就为i2c_device_match函数。
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; /* Attempt an OF style match */ if (of_driver_match_device(dev, drv)) //用设备树的方式去匹配,我们的内核用到了设备树,因此先执行本函数。 return 1; /* Then ACPI style match */ if (acpi_driver_match_device(dev, drv))//其他的匹配方式,不太熟悉。 return 1; driver = to_i2c_driver(drv); /* match on an id table if there is one */ //用id_table的方式来 if (driver->id_table) return i2c_match_id(driver->id_table, client) != NULL; return 0; }
接下来是一连串的函数调用,最终通过比较compatible字段来进行匹配,我们一步一步看看。
static inline int of_driver_match_device(struct device *dev, const struct device_driver *drv) { return of_match_device(drv->of_match_table, dev) != NULL; //drv->of_match_table在上文中有提到,他的.compatible字段为 = "ft5x06" } const struct of_device_id *of_match_device(const struct of_device_id *matches, const struct device *dev) { if ((!matches) || (!dev->of_node)) return NULL; return of_match_node(matches, dev->of_node); //将dev的of_node传进去,看下of_node的定义,struct device_node *of_node; /* associated device tree node */ } //也就是这个设备在设备树中的节点,下文在匹配的时候会用到 const struct of_device_id *of_match_node(const struct of_device_id *matches, const struct device_node *node) { const struct of_device_id *match; unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); match = __of_match_node(matches, node); //执行, raw_spin_unlock_irqrestore(&devtree_lock, flags); return match; } const struct of_device_id *__of_match_node(const struct of_device_id *matches, const struct device_node *node) { if (!matches) return NULL; while (matches->name[0] || matches->type[0] || matches->compatible[0]) { //循环 int match = 1; if (matches->name[0]) match &= node->name && !strcmp(matches->name, node->name); if (matches->type[0]) match &= node->type && !strcmp(matches->type, node->type); if (matches->compatible[0]) //如果matches的compatible[0]存在,这个是存在的 match &= __of_device_is_compatible(node, //matches->compatible与node比较 matches->compatible); if (match) return matches; matches++; } return NULL; } static int __of_device_is_compatible(const struct device_node *device, const char *compat) { const char* cp; int cplen, l; cp = __of_get_property(device, "compatible", &cplen); //从设备树中获取本节点的compatible字段, if (cp == NULL) return 0; while (cplen > 0) { if (of_compat_cmp(cp, compat, strlen(compat)) == 0) //设备树总的compatible字段和驱动中的compatible字段比较,相等返回1. return 1; //比较结束 l = strlen(cp) + 1; cp += l; cplen -= l; } return 0; }我们来看一下设备树和驱动中对compatible字段都是如何定义的。
因此肯定能比较成功。经过层层返回,最终
driver_match_device(drv, dev) //返回1
if (!driver_match_device(drv, dev)) //不成立 return 0; if (dev->parent) /* Needed for USB */ device_lock(dev->parent); device_lock(dev); if (!dev->driver) driver_probe_device(drv, dev); //执行 device_unlock(dev); if (dev->parent) device_unlock(dev->parent);
int driver_probe_device(struct device_driver *drv, struct device *dev) { int ret = 0; if (!device_is_registered(dev)) return -ENODEV; pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); printk("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); pm_runtime_barrier(dev); ret = really_probe(dev, drv); //也不能说是真正的probe ,进去看看最激动人心的probe函数 pm_request_idle(dev); return ret; }
static int really_probe(struct device *dev, struct device_driver *drv) { int ret = 0; int local_trigger_count = atomic_read(&deferred_trigger_count); atomic_inc(&probe_count); pr_debug("bus: '%s': %s: probing driver %s with device %s\n", drv->bus->name, __func__, drv->name, dev_name(dev)); WARN_ON(!list_empty(&dev->devres_head)); dev->driver = drv; //设置dev->driver 为当前的drv,下文中i2c_device_probe函数会用到,通过dev-driver找到i2c驱动的driver /* If using pinctrl, bind pins now before probing */ ret = pinctrl_bind_pins(dev); if (ret) goto probe_failed; if (driver_sysfs_add(dev)) { printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", __func__, dev_name(dev)); goto probe_failed; } if (dev->bus->probe) { //如果dev->bus->probe函数存在,则执行dev->bus-probe函数,在上文的i2c_new_device函数中指定了 ret = dev->bus->probe(dev); //dev->bus为i2c_bus_type,因此,这个dev->bus->probe就是i2c_bus_type结构中的probe函数, if (ret) //即i2c_device_probe函数,因此这里回去执行i2c_device_probe, goto probe_failed; } else if (drv->probe) { //如果dev->bus->probe不存在则直接执行drv->probe, ret = drv->probe(dev); if (ret) goto probe_failed; } driver_bound(dev); //驱动和设备绑定 ret = 1; pr_debug("bus: '%s': %s: bound device %s to driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); goto done; }
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; driver = to_i2c_driver(dev->driver); //里面调用的是container_of(d, struct i2c_driver, driver),这个函数是通过一个结构 if (!driver->probe || !driver->id_table) //的成员返回该结构的首地址,不熟悉的自行百度。这样就找到了我们i2c 驱动。 return -ENODEV; client->driver = driver; //设置client->driver if (!device_can_wakeup(&client->dev)) device_init_wakeup(&client->dev, client->flags & I2C_CLIENT_WAKE); dev_dbg(dev, "probe\n"); status = dev_pm_domain_attach(&client->dev, true); if (status != -EPROBE_DEFER) { status = driver->probe(client, i2c_match_id(driver->id_table,//真正的probe函数,这里调用的就是ft5x06_driver结构的中的probe函数。 client)); //即ft5x06_probe(struct i2c_client *client,const struct i2c_device_id *id) if (status) { //在此函数对i2c设备进行初始化等等一些操作,完全是用户自己决定,这才是真正的probe函数。 client->driver = NULL; //走到这里真是激动啊,转了720度的圈才转回来。真是佩服内核的作者。 i2c_set_clientdata(client, NULL); dev_pm_domain_detach(&client->dev, true); } } return status; }
7.4.总结
至此,已经大概明白了内核下的IIC架构,真是有点复杂,其中包含了总线,设备,驱动模型、设备树等相关的知识。其中有很多细节还是没有去深究,只是大概了解了框架。我估计平台设备总线模型,SPI设备总线模型应该是跟IIC模型是类似的,后面再分析一下SPI设备总线模型。内核真是精彩啊!!!
本文中第1、2、3、4、5、6部分是参考前辈的博客总结https://blog.csdn.net/wangpengqi/article/details/17711165,拿来主义。