一. 简介
现在,我们来学习一下如何在
Linux
下开发
I2C
接口器件
驱动,重点是学习
Linux
下的
I2C
驱动框架,按照指定的框架去编写
I2C
设备驱动。
本文来了解以下 Linux下 I2C
驱动框架,框架下的 i2C总线驱动(也就是I2C控制器驱动)。
二. Linux下I2C驱动实验: I2C驱动框架与I2C总线驱动
1. Linux I2C 驱动框架简介
回想一下我们在裸机篇中是怎么编写
AP3216C
驱动的,我们编写了四个文件:
bsp_i2c.c
、
bsp_i2c.h
、
bsp_ap3216c.c
和
bsp_ap3216c.h
。其中前两个是
I.MX6U
的
IIC
接口驱动,后两个文
件是
AP3216C
这个
I2C
设备驱动文件。相当于有两部分驱动:
(1)
I2C
主机驱动。
(2)
I2C
设备驱动。
对于
I2C
主机驱动,一旦编写完成就不需要再做修改,其他的
I2C
设备直接调用主机驱动提供的
API
函数完成读写操作即可。这个正好符合
Linux
的驱动分离与分层的思想,因此,
Linux
内核也将
I2C
驱动分为两部分:
(1)
I2C
总线驱动,
I2C
总线驱动就是
SOC
的
I2C
控制器驱动,也叫做
I2C
适配器驱动。
(2)
I2C
设备驱动,
I2C
设备驱动就是针对具体的
I2C
设备而编写的驱动。
2. I2C 总线驱动(I2C控制器驱动)
首先来看一下
I2C
总线,在讲
platform
的时候就说过,
platform
是虚拟出来的一条总线,目的是为了实现总线、设备、驱动框架。
对于
I2C
而言,不需要虚拟出一条总线,直接使用
I2C
总线即可。
I2C
总线驱动重点是
I2C
适配器
(
也就是
SOC
的
I2C
接口控制器
)
驱动。
(1) I2C总线驱动的结构体
这里要用到两个重要的数据结构:i2c_adapter
和
i2c_algorithm。
Linux
内核将
SOC
的
I2C
适配器
(
控制器
)
抽象成
i2c_adapter
,
i2c_adapter
结构体定义在
include/linux/i2c.h
文件中,结构体内容如下:
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 */
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_bus_recovery_info *bus_recovery_info;
const struct i2c_adapter_quirks *quirks;
};
第 4
行,
i2c_algorithm
类型的指针变量
algo
,对于一个
I2C
适配器,肯定要对外提供读
写
API
函数,设备驱动程序可以使用这些
API
函数来完成读写操作。
i2c_algorithm
就是
I2C
适
配器与
IIC
设备进行通信的方法。
i2c_algorithm
结构体定义在
include/linux/i2c.h
文件中,内容如下
(
删除条件编译
)
:
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 *);
......
};
第
3
行,
master_xfer
就是
I2C
适配器的传输函数,可以通过此函数来完成与
IIC
设备之间的通信。
第 6
行,
smbus_xfer
就是
SMBUS
总线的传输函数。
综上所述,I2C 总线驱动,或者说 I2C 适配器驱动的主要工作就是初始化 i2c_adapter 结构体变量,然后设置 i2c_algorithm 中的 master_xfer 函数。
(2) I2C 总线驱动注册与注销
完成以后通过
i2c_add_numbered_adapter函数 或
i2c_add_adapter函,
这两个函数向系统注册设置好的
i2c_adapter
,这两个函数的原型如下:
int i2c_add_adapter(struct i2c_adapter *adapter)
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
这两个函数的区别在于, i2c_add_adapter 函数使用动态的总线号,而 i2c_add_numbered_adapter 函数使用静态总线号。函数参数和返回值含义如下:
adapter
或
adap
:要添加到
Linux
内核中的
i2c_adapter
,也就是
I2C
适配器。
返回值:
0
,成功;负值,失败。
如果要删除
I2C
适配器的话使用
i2c_del_adapter
函数即可,函数原型如下:
void i2c_del_adapter(struct i2c_adapter * adap)
函数参数和返回值含义如下:
adap
:要删除的
I2C
适配器。
返回值:
无。
三. 总结
关于
I2C
的总线
(
控制器或适配器
)
驱动就讲解到这里,一般
SOC
的
I2C
总线驱动都是由半导体厂商编写的,比如,
I.MX6U
的
I2C
适配器驱动
NXP
已经编写好了,这个不需要用户去编
写。
因此,
I2C
总线驱动对我们这些
SOC
使用者来说是被屏蔽掉的,我们只要专注于
I2C
设备驱
动即可。除非你是在半导体公司上班,工作内容就是写
I2C
适配器驱动。