一、Linux I2C驱动框架
以前使用I2C时候,会建立一个i2c的文件和i2c通信设备的文件,也叫做驱动。I2C驱动主要分为两个驱动:
①、I2C主机驱动(i2c文件)
②、I2C设备驱动(i2c通信设备)
对于主机驱动,主要就是I2C控制器驱动,一旦编写好就不需要修改,这个驱动提供I2C传输接口,I2C设备直接调用这个接口就可以完成通信。对于Linux的分离分层也正好符合。因此Linux内核也将I2C驱动分为两部分:
①、I2C总线驱动,I2C 总线驱动就是 SOC 的 I2C 控制器驱动,也叫做 I2C 适配器驱动。对于I2C的主机驱动。
②、I2C设备驱动,主要是I2C通信的设备,要根据具体的设备来编写驱动。
1、I2C总线驱动
I2C有自己的总线,不需要使用platform总线。I2C 总线驱动重点是 I2C 适配器(也就是 SOC的 I2C 接口控制器)驱动,这里要用到两个重要的数据结构:i2c_adapter和 i2c_algorithm, Linux 内核将 SOC 的 I2C 适配器抽象成i2c_adapter,i2c_adapter 结构体定义在 include/linux/i2c.h 文件中,结构体内容如下:
498 struct i2c_adapter {
499 struct module *owner;
500 unsigned int class; /* classes to allow probing for */
501 const struct i2c_algorithm *algo; /* 总线访问算法 */
502 void *algo_data;
503
504 /* data fields that are valid for all devices */
505 struct rt_mutex bus_lock;
506
507 int timeout; /* in jiffies */
508 int retries;
509 struct device dev; /* the adapter device */
510
511 int nr;
512 char name[48];
513 struct completion dev_released;
514
515 struct mutex userspace_clients_lock;
516 struct list_head userspace_clients;
517
518 struct i2c_bus_recovery_info *bus_recovery_info;
519 const struct i2c_adapter_quirks *quirks;
520 };
第 501 行, i2c_algorithm 类型的指针变量 algo,对于一个 I2C 适配器,肯定要对外提供读写 API 函数,设备驱动程序可以使用这些 API 函数来完成读写操作。 i2c_algorithm 就是 I2C 适配器与 IIC 设备进行通信的方法。
i2c_algorithm 结构体定义在 include/linux/i2c.h 文件中,内容如下(删除条件编译):
391 struct i2c_algorithm {
......
398 int (*master_xfer)(struct i2c_adapter *adap,
struct i2c_msg *msgs,
399 int num);
400 int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
401 unsigned short flags, char read_write,
402 u8 command, int size, union i2c_smbus_data *data);
403
404 /* To determine what the adapter supports */
405 u32 (*functionality) (struct i2c_adapter *);
......
411 };
第 398 行, master_xfer 就是 I2C 适配器的传输函数,可以通过此函数来完成与 IIC 设备之间的通信。
第 400 行, smbus_xfer 就是 SMBUS 总线的传输函数。
综上所述, I2C 总线驱动,或者说 I2C 适配器驱动的主要工作就是初始化 i2c_adapter 结构体变量,然后设置 i2c_algorithm 中的 master_xfer 函数。完成以后通过i2c_add_adapter 或i2c_add_numbered_adapter这两个函数向系统注册设置好的 i2c_adapter,这两个函数的原型如下:
定义在include/linux/i2c.h
int i2c_add_adapter(struct i2c_adapter *adapter)
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
adapter或adap:要添加到Linux内核中的i2c_adapter,也就是I2C控制器。
返回值:0:成功,负值,失败。
这两个函数的区别在于 i2c_add_adapter 使用动态的总线号,而 i2c_add_numbered_adapter使用静态总线号。如果要删除 I2C 适配器的话使用 i2c_del_adapter 函数即可,函数原型如下:
定义在include/linux/i2c.h
void i2c_del_adapter(struct i2c_adapter * adap)
adap:要删除的I2C控制器。
一般I2C总线驱动有SOC厂家编写,因为不同的 SOC厂家I2C在硬件上可能不一样。所以SOC厂家会将他们自己的I2C控制器的驱动编写好。