本文中第1、2、3、4、5、6部分是参考前辈的博客总结
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_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的描述。
........
}; 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设备总线模型。内核真是精彩啊!!!