第三十节、i2c总线实现client设备和驱动
本节用于介绍i2c总线实现client设备和驱动
一、Linuxl2C驱动框架简介
Linux中的l2C也是按照平台总线模型设计的,既然也是按照平台总线模型设计的,是不是也分为一个device 和一个driver呢?但是I2C这里的device 不叫 device,而是叫client。在讲platform的时候就说过,platform是虚拟出来的一条总线,目的是为了实现总线、设备、驱动框架。对于l2C而言,不需要虚拟出一条总线,直接使用l2C总线即可。
同样,我们也是先从非设备树开始,先来看一下,在没有设备树之前我们是怎么实现的l2C的device部分,也就是client部分。然后在学习有了设备树之后,我们的client是怎么编写的。按照Linux的发展路径来学习。
在没有使用设备树之前,我们使用的是i2c_board_info这个结构体来描述一个I2C设备的,i2c_board_info这个结构体如下:
文件位置路径:include/uapi/linux/i2c-dev.h
1 | struct i2c_board_info { |
在这个结构体里面,type和addr这两个成员变量是必须要设置的,一个是l2C设备的名字,,这个名字就是用来进行匹配用的,一个是l2C设备的器件地址。也可以使用宏:
1 | #define I2C_BOARD_INFO(dev_type, dev_addr) \ |
可以看出,I2C_BOARD_INFO宏其实就是设置i2c_board_info的type和addr这两个成员变量。
I2C设备和驱动的匹配过程是由I2C核心来完成的,在Linux源码的 drivers/i2c/i2c-core-base.c就是l2C的核心部分,I2C核心提供了一些与具体硬件无关的API函数,如下:
1、i2c_get_adapter函数
作用:获得一个l2C适配器
文件位置路径:include/linux/i2c.h
实际函数位置路径:drivers/i2c/i2c-core-base.c
1 | struct i2c_adapter *i2c_get_adapter(int nr) |
2、i2c_new_device函数
作用:把I2C适配器和I2C器件关联起来。
文件位置路径:include/linux/i2c.h
实际函数位置路径:drivers/i2c/i2c-core-base.c
1 | struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) |
3、i2c_put_adapter函数
作用:释放l2C适配器
文件位置路径:include/linux/i2c.h
实际函数位置路径:drivers/i2c/i2c-core-base.c
1 | void i2c_put_adapter(struct i2c_adapter *adap) |
4、i2c_unregister_device函数
作用:注销一个client
文件位置路径:include/linux/i2c.h
实际函数位置路径:drivers/i2c/i2c-core-base.c
1 | void i2c_unregister_device(struct i2c_client *client) |
在使用了设备树以后,就不用这么复杂了,使用设备树的时候只要在对应的I2C节点下创建相应设备的节点即可,比如我想添加一个RTC的设备,我就可以在对应的I2C的节点下这样写,如下图所示:
1 | &i2c0 { |
这些设备我们可以在文件系统的/sys/bus/i2c/devices/路径下看到我们所有的I2C设备的节点
1 | root@localhost:~# ls /sys/bus/i2c/devices/ |
然后我们再来看driver部分。不管是使用设备树还是非设备树,driver部分就比较复杂了。和注册一个杂项设备或者是字符设备的套路一样,我们也是要先定一个一个i2c_driver的结构体,然后在对他进行初始化,我们来看一下这个结构体的定义,如下图所示:
文件位置路径:include/linux/i2c.h
1 | struct i2c_driver { |
在驱动注册之前i2c_driver结构体需要被正确地初始化,有4个成员要求必须被初始化,其中id_table不管用不用设备树都要被初始化,否则不能匹配成功:
1 | static struct i2c_driver xxx_driver = { |
初始化完成以后就是把i2c_driver注册进内核,注册进内核我们使用是的是i2c_add_driver
1、i2c_add_driver函数
作用:注册一个i2c驱动
函数原型:
文件位置路径:include/linux/i2c.h
实际函数位置路径:drivers/i2c/i2c-core-base.c
1 |
|
2、i2c_del_driver函数
作用:删除一个i2c驱动
函数原型:
文件位置路径:include/linux/i2c.h
实际函数位置路径:drivers/i2c/i2c-core-base.c
1 | void i2c_del_driver(struct i2c_driver *driver) |