文章目录
I2C-子系统
I2C系统框架
1.框架介绍:
应用程序层(app层)
------------------------------------------------------------------------------------------------------------
i2c driver层: i2c_client driver
设备驱动,对I2C从设备的软件实现,一个具体的I2C客户驱动包括两部分:一部分是i2c_driver,用于将设备挂接于i2c总线;另一部分是设备本身的驱动。
I2C客户驱动程序由i2c_driver和i2c_client来描述。
------------------------------------------------------------------------------------------------------------
i2c core:i2c核心层
提供了I2C总线驱动(适配器)和设备驱动的注册、注销方法,I2C通信方法(”algorithm”)上层的,与具体硬件无关的代码以及探测设备检测设备地址的上层代码等。
------------------------------------------------------------------------------------------------------------
i2c adapter层: 总线驱动,i2c控制器层,初始化i2c控制器,实现i2c时序。
I2C总线驱动是I2C适配器的软件实现, 提供I2C适配器与从设备间完成数据通信的能力。I2C总线驱动由i2c_adapter和i2c_algorithm来描述。
I2C适配器是SoC中内置i2c控制器的软件抽象,可以理解为他所代表的是一个I2C主机。
------------------------------------------------------------------------------------------------------------
居中的图片: 框架图
2. I2c工具
i2c-get i2c-set i2cdetect i2cdump i2cget i2cset
总线扫描
/ # i2cdetect -l
i2c-0 i2c rk3x-i2c I2C adapter
i2c-2 i2c rk3x-i2c I2C adapter
3. 相关重要结构体和函数:
3.1 i2c_client:
每一个i2c从设备都需要用一个i2c_client结构体来描述,i2c_client对应真实的i2c物理设备device。
i2c_client不是我们自己写程序去创建的,而是通过以下常用的方式自动创建的:
方法一: 分配、设置、注册i2c_board_info
方法二: 获取adapter调用i2c_new_device
方法三: 通过设备树(devicetree)创建
方法1和方法2通过platform创建,这两种方法在内核3.0版本以前使用所以在这不详细介绍;**方法3是最新的方法,**3.0版本之后的内核都是通过这种方式创建
I2c_client 代表i2c从设备
struct i2c_client { // 用来描述一个i2c次设备
unsigned short flags; // 描述i2c次设备特性的标志位
unsigned short addr; // i2c 次设备的地址
// _LOWER_ 7 bits
char name[I2C_NAME_SIZE]; // i2c次设备的名字
struct i2c_adapter *adapter; // 指向与次设备匹配成功的适配器
struct device dev; // 该次设备对应的device
int irq; // 次设备的中断引脚
struct list_head detected; // 作为一个链表节点挂接到与他匹配成功的i2c_driver 相应的链表头上
};
3.2 i2c_driver:
用于管理I2C的驱动程序和i2c设备(client)的匹配探测,实现与应用层交互的文件操作集合fops、cdev等
I2c_driver代表I2C从设备驱动
struct i2c_driver { // 代表从设备驱动
unsigned int class; // i2c设备驱动所支持的i2c设备的类型
/* 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; // 该i2c设备驱动所对应的device_driver
const struct i2c_device_id *id_table; // 设备驱动层用来匹配设备的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; // 用来挂接与该i2c_driver匹配成功的i2c_client (次设备)的一个链表头
};
3.3 i2c_adapter:
i2c总线适配器其实就是一个i2c总线控制器,本质上是一个物理设备,主要用来完成i2c总线控制器相关的数据通信,当向I2C核心层注册一个I2C适配器时就需要提供这样的一个结构体变量。
struct i2c_adapter {
struct module *owner; /*所有者*/
unsigned int class; /*该适配器支持的从设备的类型*/
const struct i2c_algorithm *algo; /* 该适配器与从设备的通信算法*/
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; /* 该适配器设备对应的device */
int nr; // 适配器的编号
char name[48]; // 适配器的名字
struct completion dev_released;
struct mutex userspace_clients_lock;
struct list_head userspace_clients; // 用来挂接与适配器匹配成功的从设备i2c_client的一个链表头
struct i2c_bus_recovery_info *bus_recovery_info;
const struct i2c_adapter_quirks *quirks;
};
3.4 i2c_algorithm:
代表的是适配器的通信算法,在构建i2c_adapter结构体变量的时候会去填充这个元素。
I2C总线数据通信算法,通过管理I2C总线控制器,实现对I2C总线上数据的发送和接收等操作。亦可以理解为I2C总线控制器(适配器adapter)对应的驱动程序,每一个适配器对应一个驱动程序,用来描述适配器和设备之间的通信方法
struct i2c_algorithm {
/* If an adapter algorithm can't do I2C-level access, set master_xfer
to NULL. If an adapter algorithm can do SMBus access, set
smbus_xfer. If set to NULL, the SMBus protocol is simulated
using common I2C messages */
/* master_xfer should return the number of messages successfully
processed, or a negative value on error */
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.5 代码目录:
/drivers/i2c 目录下:
I2c-core.c 实现I2C核心的功能
I2c-dev.c 通用的从设备驱动
Busses I2C适配器的驱动
Algos 实现了一些I2C总线适配器的algorithm