【IMX6ULL驱动学习】I2C驱动
I2C驱动框架分为两部分:
- I2C总线驱动:I2C 总线驱动就是 SOC 的 I2C 控制器驱动,也叫做 I2C 适配器驱动。
- I2C设备驱动:I2C 设备驱动就是针对具体的 I2C 设备而编写的驱动。
13.1. I2C总线驱动
总线驱动主要实现I2C总线的初始化和配置,提供I2C总线的访问算法,供I2C设备驱动调用。具体来说就是初始化i2c_adapter
结构体变量,然后设置i2c_algorithm
中的master_xfer
函数。完成以后通过 i2c_add_numbered_adapter
或 i2c_add_adapter
这两个函数向系统注册设置好的 i2c_adapter
,
13.2. I2C设备驱动
设备驱动包含两个数据结构:i2c_client
和i2c_driver
。基于总线-设备-驱动模型,i2c_client
描述设备信息,i2c_driver
(类似于platform_driver
)描述驱动内容。
i2c_client
结构体(类似于platform_device
)i2c_client
结构体描述一个I2C设备的信息,一个设备对应一个i2c_client
结构体变量i2c_client
结构体中包含了一个device
结构体变量,这个变量是驱动模型的核心,通过这个变量可以将I2C设备注册到总线上i2c_client
结构体中还包含了设备的I2C地址、所属的I2C适配器等信息i2c_client
结构体一般由内核自动创建,驱动开发者不需要手动创建
struct i2c_client {struct device dev; /* 设备模型核心结构体 */struct i2c_adapter *adapter; /* 该I2C设备所属的I2C适配器 */const struct i2c_device_id *id_entry; /* 该I2C设备对应的ID表项 */char name[I2C_NAME_SIZE]; /* 设备名称 */unsigned short flags; /* 设备标志 */unsigned short addr; /* I2C设备地址 */... };
i2c_driver
结构体(类似于platform_driver
)i2c_driver
结构体描述一个I2C设备驱动的信息,一个驱动对应一个i2c_driver
结构体变量i2c_driver
结构体中包含了驱动的名字、ID表、设备树匹配表、文件操作函数集、probe
和remove
函数等信息i2c_driver
结构体通过i2c_add_driver
函数向系统注册
I2C设备驱动编写核心工作就是构建struct i2c_driver {struct device_driver driver; /* 设备驱动模型核心结构体 */const struct i2c_device_id *id_table; /* 该驱动支持的I2C设备ID表 */const struct of_device_id *of_match_table; /* 该驱动支持的设备树匹配表 */int (*probe)(struct i2c_client *client, const struct i2c_device_id *id); /* 设备初始化函数 */int (*remove)(struct i2c_client *client); /* 设备卸载函数 */struct file_operations *fops; /* 文件操作函数集 */... };
i2c_driver
结构体变量,完成probe
和remove
函数(函数原型已经在i2c_driver
中声明),构建文件操作函数集,并通过i2c_add_driver
函数向系统注册
13.3. 设备树下I2C设备驱动编写
13.3.1. 添加设备树
在I2C总线驱动下设置设备树,关键是设置compatible
属性和reg
属性
compatible
属性用于匹配驱动reg
属性用于指定I2C设备的地址
&i2c1 {clock-frequency = <100000>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_i2c1>;status = "okay";ap3216c@1e{compatible = "alientek,ap3216c";my_name = "ap3216c";reg = <0x1e>;};
};
ap3216c
的compatible = "alientek,ap3216c"
属性用于匹配驱动,reg = <0x1e>
属性指定I2C设备的地址为0x1e
13.3.2. 构造i2c_driver
结构体变量
- 构建设备ID表
struct of_device_id
- 构建文件操作函数集
struct file_operations
- 实现
probe
和remove
函数 - 构建
i2c_driver
结构体变量 - 值得注意的是,
i2c_driver
中必须确保传统匹配方式ID列表i2c_device_id
存在,不然设备树节点与驱动无法匹配,具体而言/* 设备树列表 */ static const struct of_device_id ap3216_dt_match[] = {{ .compatible = "alientek,ap3216c" },{ }, };/* 传统匹配方式ID列表 */static const struct i2c_device_id ap3216c_id[] = {{"alientek,ap3216c", 0}, {}};static struct i2c_driver ap3216_i2c_driver = {.driver = {.owner = THIS_MODULE,.name = "ap3216c",.of_match_table = ap3216_dt_match,/* 设备树列表 */},.probe = ap3216_i2c_probe,.remove = ap3216_i2c_remove,.id_table = ap3216c_id,/* 传统匹配方式ID列表 */};
13.3.3. 创建/注销I2C设备驱动
- 在
init
函数中调用i2c_add_driver
函数注册I2C设备驱动int i2c_add_driver(struct i2c_driver *driver) // driver:指向i2c_driver结构体变量的指针
- 在
exit
函数中调用i2c_del_driver
函数注销I2C设备驱动