linux的i2c驱动框架是基于总线模型设计的,就是在内核中会注册一条i2c总线,在总线中提供了注册i2c_driver和i2c_adapter的接口,学过总线模型都知道,总线有两部分device和driver组成,在总线描述结构中有个成员struct subsys_private *p;这个成员里面又有两个链表分别为struct klist klist_devices;,struct klist klist_drivers;这两个链表是用来管理总线下的device和driver成员,在这里i2c_adapter属于device部分,也就是说i2c_adapter会注册到总线的struct klist klist_devices链表中
来,为了需要,i2c总线的device部分还有另外一个结构i2c_client(i2c_driver和i2c_adapter匹配成功后的‘“产物”),既然device部分有两个结构,总线中必然要对它们进行区分,这两个结构中都会包含一个struct device结构,struct device这个结构中有个type成员,i2c_adapter和i2c_client对type这个成员分别赋值i2c_adapter_type、i2c_client_type进行区分,上面说了device部分,自然i2c_driver就属于i2c总线的driver部分。在i2c总线中i2c_adapter对应于一个i2c控制器(当然没有也可以软件模拟一个),i2c_client对应一个真实存在的i2c设备,而i2c_driver并没有与实际的硬件对应,虽然没有对应的硬件设备,但它负责了i2c设备跟linux其他功能模块的对接工作,因为i2c芯片多种多样,功能也各不相同,至于i2c芯片是什么功能,由i2c_driver来处理。先来看下i2c_adapter的注册:
i2c总线提供了两个注册接口分别为int i2c_add_numbered_adapter(struct i2c_adapter *adap)、int i2c_add_adapter(struct i2c_adapter*adapter),这两个接口的区别在于总线id号的分配,存放在struct i2c_adapter结构的nr成员,i2c_add_numbered_adapter是由驱动指定struct i2c_adapter结构的nr成员,为-1时自动分配(所以该接口支持自动分配总线id,和手动设置),而i2c_add_adapter只支持自动分配。它们最终都是调用i2c_register_adapter
static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = 0;
/* Can't register until after driver model init */
if (unlikely(WARN_ON(!i2c_bus_type.p))) {
res = -EAGAIN;
goto out_list;
}
/* Sanity checks */
if (unlikely(adap->name[0] == '\0')) {
pr_err("i2c-core: Attempt to register an adapter with "
"no name!\n");
return -EINVAL;
}
if (unlikely(!adap->algo)) {
pr_err("i2c-core: Attempt to register adapter '%s' with "
"no algo!\n", adap->name);
return -EINVAL;
}
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);
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
res = device_register(&adap->dev);
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
/* create pre-declared device nodes */
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
/* Notify drivers */
mutex_lock(&core_lock);
bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
mutex_unlock(&core_lock);
return 0;
}
i2c_register_adapter里面主要是调用三个函数首先是调用device_register注册一个device,然后是调用i2c_scan_static_board_info(adap);
和bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);先来看下i2c_scan_static_board_info
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中取出前面已经注册的struct i2c_devinfo结构,通过判断devinfo->busnum == adapter->nr是否相等来识别该dev与i2c_adapter的是否匹配,如果匹配,则调用i2c_new_device创建一个i2c设备,再来看下bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);bus_for_each_drv这个函数的主要作用是遍历已注册进i2c总线的所以i2c_driver然后调用__process_new_adapter对每一个i2c_driver与adap进行匹配,__process_new_adapter这个函数里面的调用比较多,所以这里以主要函数调用流程来说明它们的匹配过程:
i2c_do_add_adapter
i2c_detect(adap, driver);//
for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1)
{
temp_client->addr = address_list[i];
i2c_detect_address(temp_client, driver);
i2c_check_addr_validity//检测该设备地址的有效性,无效则返回
i2c_check_addr_busy//检测该设备地址是否已经注册,是则返回
i2c_default_probe//硬件的识别
driver->detect(temp_client,&info);//调用i2c_driver的detect函数,根据临时分配的struct i2c_client *temp_client结构构造一个struct i2c_board_info info(单板信息),下面会根据这个单板信息创建一个设备
i2c_new_device//产生另一个结构i2c_client,把i2c_driver跟i2c_adapter关联起来
}
如上用函数调用过程了解了大概过程,但有些细节还是要用文字描述下,首先是调用i2c_do_add_adapter转接一下,然后是调用i2c_detect,由上可见,这个函数传进来的参数有两个,分别为adap和driver,再这个函数里面首先会临时分配一个struct i2c_client *temp_client结构,并把adap赋值给temp_client的adapter成员,在硬件的识别过程需要用到,取出i2c_driver里面的address_list,这是个指针,里面存放有该driver支持的i2c设备地址,逐个取出该address_list,并赋值给temp_client结构的addr成员,然后再调用i2c_detect_address把这个临时分配的结构当作参数传送进去,进去这个函数首先是调用i2c_check_addr_validity检测该设备地址的有效性,无效则返回,再调用 i2c_check_addr_busy检测该设备地址是否已经注册,是则返回,然后调用i2c_default_probe进行真正的硬件识别(识别原理就是先发送i2c的start信号,发送地址,然后判断有没有收到回应信号来识别,这里需要注意一下,数据传输接口由adapter来提供,如果adapter没有提供会调用i2c总线默认的数据传输接口),之后调用driver的detect函数根据这个临时分配的个struct i2c_client结构构造出另一个结构struct i2c_board_info info,再就是调用i2c_new_device(adapter, &info);根据刚构造出的struct i2c_board_info info创建一个设备。这就完成了一个i2c_adapter的注册。由上面可知在注册一个i2c_adapter的过程中,有两处地方会调用 i2c_new_device来创建一个i2c设备,并产生另外一个结构i2c_client,来看下它的实现:
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));
/* 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;
client->dev.type = &i2c_client_type;
client->dev.of_node = info->of_node;
/* 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);
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;
}
这里可以看到首先是构造一个struct i2c_client结构,并对它进行初始化,上面可以看到client->dev.parent = &client->adapter->dev;把adapter的dev作为该设备的parent,然后调用device_register注册一个设备,也就是把它作为一个子项注册进adapter的dev中(这个在上层通过adapter访问一个具体的i2c设备时检测一个设备是否存在时用到,也就是遍历该adapter的dev下的子项来检测,后面会讲),这个只是注册一个设备,还需要调用device_create才能能生成一个设备文件,在i2c中,创建一个设备文件已经做成一个接口注册进i2c总线中了,由上可见,在调用i2c_register_adapter和i2c_new_device都会调用device_register注册一个设备会调用device_add,在device_add中又有一个判断并调用
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev);i2c的设备文件的创建就是在这里完成的(但需要注意并不是两处的device_register调用注册都会创建一个设备,只有在注册i2c_adapter的时候才会生成,因为它里面会有判断),创建一个i2c设备文件接口是在i2c_dev.c里面实现的,应用层访问一个i2c设备文件的入口也是在这里实现,来看下它的具体实现:
static int __init i2c_dev_init(void)
{
int res;
printk(KERN_INFO "i2c /dev entries driver\n");
res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
if (res)
goto out;
i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
if (IS_ERR(i2c_dev_class)) {
res = PTR_ERR(i2c_dev_class);
goto out_unreg_chrdev;
}
/* Keep track of adapters which will be added or removed later */
res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
if (res)
goto out_unreg_class;
/* Bind to already existing adapters right away */
i2c_for_each_dev(NULL, i2cdev_attach_adapter);
return 0;
}
i2cdev_fops是i2c设备文件上层访问入口函数集,调用register_chrdev(I2C_MAJOR, “i2c”, &i2cdev_fops);把它跟 i2c主设备号I2C_MAJOR进行绑定,因为这个是系统分配给i2c的主设备号,注册一个i2c设备都会使用这个主设备号来创建设备文件,这使得上层应用i2c设备文件的访问入口为 i2cdev_fops提供的函数集(应用并不是直接就访问到这里来,而是需要通过虚拟文件系统的映射才会访问到这里来),然后这里是注册i2c设备文件的创建或销毁接口res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);看下代码
static struct notifier_block i2cdev_notifier = {
.notifier_call = i2cdev_notifier_call,
};
static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,void *data)
{
struct device *dev = data;
switch (action) {
case BUS_NOTIFY_ADD_DEVICE:
return i2cdev_attach_adapter(dev, NULL);
case BUS_NOTIFY_DEL_DEVICE:
return i2cdev_detach_adapter(dev, NULL);
}
return 0;
}
static int i2cdev_detach_adapter(struct device *dev, void *dummy)
{
struct i2c_adapter *adap;
struct i2c_dev *i2c_dev;
if (dev->type != &i2c_adapter_type)//对dev的type进行判断,不是i2c_adapter_type类型返回
return 0;
adap = to_i2c_adapter(dev);
i2c_dev = i2c_dev_get_by_minor(adap->nr);
if (!i2c_dev) /* attach_adapter must have failed */
return 0;
device_remove_file(i2c_dev->dev, &dev_attr_name);
return_i2c_dev(i2c_dev);
device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
return 0;
}
这里提供了创建和销毁一个i2c设备文件的接口,在上面提到的blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev);调用,就会调用到这里的i2cdev_attach_adapter(dev, NULL);函数进行一个i2c设备文件的创建,由上面代码可见,i2cdev_attach_adapter首先就是对dev的type成员变量进行判断,不是i2c_adapter_type类型的就返回,不进行设备文件的创建,是则调用device_create进行设备文件的创建。了解了i2c_adapter和i2c设备文件的创建流程,现在回到i2c_driver中来,i2c框架是基于总线模型设计的,必然会遵守总线模型的双匹配机制,也就是在注册一个i2c_driver也会来匹配注册进i2c总线的i2c_adapter,在总线中也提供另一个用来注册i2c_driver的接口i2c_register_driver,这个函数做两件事情:1、调用driver_register(&driver->driver);注册一个driver,这是任何总线注册一个driver都会做的事情,这里不加以讨论2、i2c_for_each_dev(driver, __process_new_driver);这个跟注册i2c_adapter调用的是相反的,在这里是逐个取出i2c总线下已注册的i2c_adapter然后进行该i2c_driver address_list下的设备地址进行识别,识别过程跟上面的是一样的。
i2c总线是基于数据协议传输的,势必会涉及到数据的收发,在i2c总线中,对数据协议传输分为两个层面:一个是硬件层面(与底层硬件直接打交道,由i2c_adapter成员来完成)、另一个属软件层面(通过软件进行封装,最终找到对应的i2c_adapter进行数据的收发),在一开始就讲到,i2c_adapter对应于一个i2c控制器,自然与i2c设备的通讯由它来完成,内核用一个数据结构来对一个i2c控制器进行描述
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 这个结构用来提供与i2c设备通讯的接口*/
void *algo_data;
/* 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_algorithm
struct i2c_algorithm {
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,int num);
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,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 *);
};
这个结构提供了两个数据传输接口master_xfer、smbus_xfer,master_xfer这个是通用的i2c传输接口,而smbus_xfer接口是为了应用层对i2c的操作更加的通用性扩展出来smbus数据传输协议(属软件协议)。可根据需要去实现这个接口,另外还提供了一个用来检测该i2c_adapter支持的功能的接口functionality,下面以一个具体的实例进行这些功能接口的实现,如下是s3c2410平台实现的一个struct i2c_algorithm
static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
.master_xfer = s3c24xx_i2c_xfer,
.functionality = s3c24xx_i2c_func,
};
static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msgs, int num)
{
struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
int retry;
int ret;
pm_runtime_get_sync(&adap->dev);
clk_enable(i2c->clk);
for (retry = 0; retry < adap->retries; retry++) {//失败重复发送
ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
if (ret != -EAGAIN) {
clk_disable(i2c->clk);
pm_runtime_put_sync(&adap->dev);
return ret;
}
dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);
udelay(100);
}
return -EREMOTEIO;
}
这里主要是调用s3c24xx_i2c_doxfer把数据包传给struct s3c24xx_i2c结构的msg成员,然后启动数据发送(即是触发中断),发送失败按设定的重复次数进行重复启动传输,真正的传输在中断完成,中断处理函数比较长(主要是数据的收发),这里就不贴出来了,贴下i2c协议以及注意事项:
i2c总线在传送数据过程中有3种类型信号:开始信号、结束信号和响应信号
1、开始信号(S):SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据
2、结束信号(P):SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据
3、响应信号(ACK):接收器在接收到8位数据后,在第9个时钟周期,拉低SDA电平
数据传输的注意事项:
1、SDA上传输的数据必须在SCL为高电平期间保持稳定,SDA上的数据只能在SCL为低电平期间变化
2、并非每传输8位数据之后都会有ACK信号,有以下三种例外
(1)当从机不能响应从机地址时(例如它正忙于其他事而无法响应I2C总线的操作,或这个地址没有对应的从机),这时,主机发出一个P信号终止传输或者重新发出一个S信号开始新的传输
(2)如果从机接收器在传输过程中不能接受更多的数据时,它也不会发出ACK信号。这样,主机就可以意识到这点,从而发出一个P信号终止传输或者重新发出一个S信号开始新的传输
(3)主机接收器在接收到最后一个字节后,也不会发出ACK信号,于是,从机发送器释放SDA线,以允许主机发出P信号结束传输
3、发送到SDA线上的每个字节必须是8位的,每次传输可以发送的字节数量不受限制。每个字节后必须跟一个响应位。首先传输的是数据的最高位(MSB)。如果从机要完成一些其他功能后才能继续接收或发送下一个字节,从机可以拉低SCL迫使主机进入等待状态。当从机准备好接收下一个数据并释放SCL后,数据继续传输。如果主机在传输数据期间也需要完成一些其他功能,也可以拉低SCL以占住总线
启动传输时,即发出一个S信号,接着发出从机的地址(从机地址有7位和10位,如果为10位分两字节传输,这里要注意每次传输的8位数据中最高位(MSB)先发送)和一位表示传输方向的位(0表示写,1表示读)
如上讲了硬件层面的数据传输,i2c_adapter直接与硬件打交道。但是在写i2c_driver驱动的需要从i2c设备中读取或发送数据怎么办?在i2c总线中也封装了一些i2c数据传输的接口(这就是上面说的,数据传输的软件层面),在i2c_core.c文件下有i2c_master_send、i2c_master_recv、i2c_smbus_read_byte、i2c_smbus_read_byte、i2c_smbus_read_byte_data、i2c_smbus_write_byte_data、i2c_smbus_read_word_data、i2c_smbus_write_word_data,i2c总线主要为驱动编程人员封装了这几个i2c数据传输的接口,可根据需要去具体使用,对于这些接口的实现,主要还是通过找到adapter->algo->smbus_xfer来进行数据传输。
讲了这么多还是很有必要了解下应用层访问一个i2c设备的具体过程,在上面讲创建一个i2c设备文件的时候,略微提了一下i2c的上层访问入口函数操作集i2cdev_fops,下面看下它的实现
static const struct file_operations i2cdev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = i2cdev_read,
.write = i2cdev_write,
.unlocked_ioctl = i2cdev_ioctl,
.open = i2cdev_open,
.release = i2cdev_release,
};
上层应用打开一个i2c设备就会调用这里的i2cdev_open函数(通过虚拟文件系统映射),先看下打开一个i2c设备的过程:
static int i2cdev_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct i2c_client *client;
struct i2c_adapter *adap;
struct i2c_dev *i2c_dev;
i2c_dev = i2c_dev_get_by_minor(minor);
if (!i2c_dev)
return -ENODEV;
adap = i2c_get_adapter(i2c_dev->adap->nr);
if (!adap)
return -ENODEV;
/* This creates an anonymous i2c_client, which may later be
* pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
*
* This client is ** NEVER REGISTERED ** with the driver model
* or I2C core code!! It just holds private copies of addressing
* information and maybe a PEC flag.
*/
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adap);
return -ENOMEM;
}
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
client->adapter = adap;
file->private_data = client;
return 0;
}
首先是调用i2c_dev_get_by_minor通过设备的次设备号找到它的struct i2c_dev,内核有个i2c_dev_list链表对i2c_dev成员进行管理,这个函数的主要实现就是从i2c_dev_list链表中逐个取出i2c_dev成员,进行i2c_dev->adap->nr 和该设备次设备号的比较,相等则返回i2c_dev,然后调用i2c_get_adapter找到它的adapter,构造一个struct i2c_client *client;并把adapter赋值给client的adapter成员,然后把client成员放在文件描述结构file的私有数据private_data成员里面,方便在读写函数中直接从文件描述结file中private_data取出该设备对应的struct i2c_client结构。对于读写数据,都差不多,只要去看它的一个实现就够了,看下它的写函数:
static ssize_t i2cdev_write(struct file *file, const char __user *buf,size_t count, loff_t *offset)
{
int ret;
char *tmp;
struct i2c_client *client = file->private_data;
if (count > 8192)
count = 8192;
tmp = memdup_user(buf, count);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",iminor(file->f_path.dentry->d_inode), count);
ret = i2c_master_send(client, tmp, count);
kfree(tmp);
return ret;
}首先取出在open时构造的struct i2c_client *client结构,然后是对写长度的判断,由此可见,对于i2c设备一次最大只能写8192个字节,调用memdup_user从用户空间映射到内核空间(为了安全考虑),再是调用i2c_master_send发送数据,这个函数是在i2c_core.c里实现的
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);
/*
* If everything went ok (i.e. 1 msg transmitted), return #bytes
* transmitted, else error code.
*/
return (ret == 1) ? count : ret;
}
在这里需要注意一点,从client中取出设备地址,但是在前面打开一个i2c设备,只是构造一个struct i2c_client并把i2c_adapter赋值给它的adapter成员,没有做任何的初始化,那么就要考虑client中addr的来源了(稍后再讲),这里是构造一个数据包,然后调用i2c_transfer进行发送,这个也是在i2c_core.c里面提供
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
unsigned long orig_jiffies;
int ret, try;
/* REVISIT the fault reporting model here is weak:
*
* - When we get an error after receiving N bytes from a slave,
* there is no way to report "N".
*
* - When we get a NAK after transmitting N bytes to a slave,
* there is no way to report "N" ... or to let the master
* continue executing the rest of this combined message, if
* that's the appropriate response.
*
* - When for example "num" is two and we successfully complete
* the first message but get an error part way through the
* second, it's unclear whether that should be reported as
* one (discarding status on the second message) or errno
* (discarding status on the first one).
*/
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_adapter(adap);
if (!ret)
/* I2C activity is ongoing. */
return -EAGAIN;
} else {
i2c_lock_adapter(adap);
}
/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
for (ret = 0, try = 0; try <= adap->retries; try++) {
ret = adap->algo->master_xfer(adap, msgs, num);
if (ret != -EAGAIN)
break;
if (time_after(jiffies, orig_jiffies + adap->timeout))
break;
}
i2c_unlock_adapter(adap);
return ret;
} else {
dev_dbg(&adap->dev, "I2C level transfers not supported\n");
return -EOPNOTSUPP;
}
}
从代码可见,最终还是调用adap->algo->master_xfer,这就回到了i2c_adapter部分,在前面可以知道i2c_adapter主要是负责硬件数据传输的启动,最终在i2c_driver里面注册的i2c中断来完成数据传输的过程。到这里,上层应用访问一个i2c设备到硬件的数据传输就贯通起来了,在上面还有一个疑点,client->addr从哪里来?其实这在open函数已经有注释了,如下是内核在i2cdev_open中的一段注释:
/* This creates an anonymous i2c_client, which may later be
* pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
*
* This client is * NEVER REGISTERED * with the driver model
* or I2C core code!! It just holds private copies of addressing
* information and maybe a PEC flag.
*/
意思就是打开一个i2c设备后可以通过系统调用ioctl发送 I2C_SLAVE或者I2C_SLAVE_FORCE.命令来设置i2c设备的地址,最终是调用这里的函数:
static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct i2c_client *client = file->private_data;
unsigned long funcs;
dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
cmd, arg);
switch (cmd) {
case I2C_SLAVE:
case I2C_SLAVE_FORCE://设置i2c设备地址
/* NOTE: devices set up to work with "new style" drivers
* can't use I2C_SLAVE, even when the device node is not
* bound to a driver. Only I2C_SLAVE_FORCE will work.
*
* Setting the PEC flag here won't affect kernel drivers,
* which will be using the i2c_client node registered with
* the driver model core. Likewise, when that client has
* the PEC flag already set, the i2c-dev driver won't see
* (or use) this setting.
*/
if ((arg > 0x3ff) ||
(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
return -EINVAL;
if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
return -EBUSY;
/* REVISIT: address could become busy later */
client->addr = arg;
return 0;
case I2C_TENBIT:
if (arg)
client->flags |= I2C_M_TEN;
else
client->flags &= ~I2C_M_TEN;
return 0;
case I2C_PEC:
if (arg)
client->flags |= I2C_CLIENT_PEC;
else
client->flags &= ~I2C_CLIENT_PEC;
return 0;
case I2C_FUNCS://获取该设备下的i2c控制器支持的功能
funcs = i2c_get_functionality(client->adapter);
return put_user(funcs, (unsigned long __user *)arg);
case I2C_RDWR://读写数据除了调用read、write外,这里还提供了一个读写数据命令
return i2cdev_ioctl_rdrw(client, arg);
case I2C_SMBUS:
return i2cdev_ioctl_smbus(client, arg);
case I2C_RETRIES://设置重复发送次数
client->adapter->retries = arg;
break;
case I2C_TIMEOUT://设置设备响应的超时时间
/* For historical reasons, user-space sets the timeout
* value in units of 10 ms.
*/
client->adapter->timeout = msecs_to_jiffies(arg * 10);
break;
default:
/* NOTE: returning a fault code here could cause trouble
* in buggy userspace code. Some old kernel bugs returned
* zero in this case, and userspace code might accidentally
* have depended on that bug.
*/
return -ENOTTY;
}
return 0;
}
由上代码可见除了发送 I2C_SLAVE或者I2C_SLAVE_FORCE来设置地址外,内核还提供了其他的命令来访问和设置一些重要的信息,看注释,这里还需要注意一下,在发送I2C_SLAVE设置设备地址会去调用 i2cdev_check_addr(client->adapter, arg)来检测这个设备是否已经注册进该adapter,是才设置,否则返回busy标志,而发送I2C_SLAVE_FORCE设置地址不会去检测。