一. 简介
前面一篇文章学习了 Linux下 I2C 驱动框架与 I2C总线驱动(即I2C控制器驱动),文章如下:
Linux下I2C驱动实验: I2C驱动框架与I2C总线驱动-CSDN博客
Linux 内核也将 I2C 驱动分为两部分:
(1) I2C 总线驱动, I2C 总线驱动就是 SOC 的 I2C 控制器驱动,也叫做 I2C 适配器驱动。
(2) I2C 设备驱动, I2C 设备驱动就是针对具体的 I2C 设备而编写的驱动。
本文来学习一下 I2C 设备驱动。
二. Linux下I2C驱动实验:I2C设备驱动
I2C 设备驱动重点关注两个数据结构:i2c_client 和 i2c_driver,i2c_client 就是描述设备信息的,i2c_driver 描述驱动内容,类似于 platform_driver。
1. I2C 设备驱动涉及的结构体
(1)i2c_client 结构体
i2c_client 结构体定义在 include/linux/i2c.h 文件中,内容如下:
struct i2c_client {
unsigned short flags; /* 标志 */
unsigned short addr; /* 芯片地址,7 位,存在低 7 位*/
......
char name[I2C_NAME_SIZE]; /* 名字 */
struct i2c_adapter *adapter; /* 对应的 I2C 适配器 */
struct device dev; /* 设备结构体 */
int irq; /* 中断 */
struct list_head detected;
......
};
一个设备对应一个 i2c_client ,每检测到一个 I2C 设备就会给这个 I2C 设备分配一个 i2c_client 。
(2)i2c_driver结构体
i2c_driver 类似 platform_driver,是我们编写 I2C 设备驱动重点要处理的内容,i2c_driver 结构体定义在 include/linux/i2c.h 文件中,内容如下:
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;
/* 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 *);
/* 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;
/* 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;
};
第 10 行,当 I2C 设备和驱动匹配成功以后, probe 函数就会执行,和 platform 驱动一样。
第 28 行,device_driver 驱动结构体,如果使用设备树的话,需要设置 device_driver 的
of_match_table 成员变量,也就是驱动的兼容(compatible)属性。
第 29 行,id_table 是传统的、未使用设备树的设备匹配 ID 表。
对于我们 I2C 设备驱动编写人来说,重点工作就是构建 i2c_driver。
2. I2C 设备驱动注册与删除
构建完成 i2c_driver 结构体 以后,需要向Linux 内核注册这个 i2c_driver 。 i2c_driver 注册函数为 i2c_register_driver函数 ,此函数原型如下:
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
函数参数和返回值含义如下:
owner : 一般为 THIS_MODULE 。
driver :要注册的 i2c_driver 。
返回值: 0 ,成功;负值,失败。
i2c_add_driver 也常常用于注册 i2c_driver , i2c_add_driver 是一个宏,定义如下:
#define i2c_add_driver(driver) \
i2c_register_driver(THIS_MODULE, driver)
i2c_add_driver 就是对 i2c_register_driver 做了一个简单的封装,只有一个参数,就是要注册的 i2c_driver 。
注销 I2C 设备驱动的时候需要将前面注册的 i2c_driver 从 Linux 内核中注销掉,需要用到
i2c_del_driver 函数,此函数原型如下:
void i2c_del_driver(struct i2c_driver *driver)
函数参数和返回值含义如下:
driver :要注销的 i2c_driver 。
返回值: 无。
三. 总结
**i2c_client结构体:**表示I2C设备,不需要我们自己创建 i2c_client,我们一般在设备树里面添加具体的I2C芯片,比如 fxls8471,系统在解析设备树的时候,就会知道有这个I2C设备,然后会创建对应的i2c_client。
**i2c设备驱动框架:**i2c_driver初始化与注册,需要II2C设备驱动编写人员编写的,IIC驱动程序就是初始化i2c_driver,然后向系统注册。注册使用i2c_register_driver、i2c_add_driver,如果注销i2c_driver使用i2c_del_driver。