Linux i2c驱动框架分析 (一)

Linux i2c驱动框架分析 (一)
Linux i2c驱动框架分析 (二)
Linux i2c驱动框架分析 (三)
通用i2c设备驱动分析

Linux的i2c体系结构

Linux的i2c体系结构分为3个组成部分。
(1) i2c核心
i2c核心提供了i2c总线驱动和设备驱动的注册、注销方法,i2c通信方法上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。

(2) i2c总线驱动
i2c总线驱动是对i2c硬件体系结构中适配器端的实现。
i2c总线驱动主要包含了i2c适配器数据结构i2c_adapter、i2c适配器的i2c_algorithm数据结构和控制i2c适配器产生通信信号的函数。
经由i2c总线驱动的代码,我们可以控制i2c适配器以主控方式产生开始位、停止位、读写周期,以及以从设备方式被读写、产生ack等。

(3) i2c设备驱动
i2c设备驱动是对i2c硬件体系结构中设备端的实现,设备挂接在i2c适配器上,通过i2c适配器与cpu交换数据。i2c设备驱动主要包含了数据结构i2c_driver和i2c_client,我们需要根据具体设备实现其中的成员函数。

i2c驱动框架如下图所示。
在这里插入图片描述
在Linux内核源代码中的drivers目录下包含一个i2c目录,而在i2c目录下又包含如下文件和文件夹:
在这里插入图片描述
i2c-core.c,这个文件实现了i2c核心的功能。
i2c-dev.c,实现了i2c适配器设备文件的功能,每一个i2c适配器都被分配一个设备。
busses文件夹包含了一些I2C总线的驱动,如针对S3C2410、S3C2440和S3C6410等处理器的i2c控制器驱动为i2c-s3c2410.c。
algos文件夹,实现了一些i2c总线适配器的algorithm。

主要的数据结构

i2c_adapter结构体,描述一个i2c适配器(控制器),定义如下:

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	*/
	const struct i2c_lock_operations *lock_ops;
	struct rt_mutex bus_lock;
	struct rt_mutex mux_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;
};

i2c_algorithm结构体,描述一个适配器的总线通信方法:

struct i2c_algorithm {

	//传输数据函数
	int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
			   int num);

	//SMBus传输函数
	int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
			   unsigned short flags, char read_write,
			   u8 command, int size, union i2c_smbus_data *data);

	/* 这个函数返回适配器支持的功能 */
	u32 (*functionality) (struct i2c_adapter *);

#if IS_ENABLED(CONFIG_I2C_SLAVE)
	int (*reg_slave)(struct i2c_client *client);
	int (*unreg_slave)(struct i2c_client *client);
#endif
};

SMBus大部分基于i2c总线规范,SMBus不需增加额外引脚。与i2c总线相比,SMBus增加了一些新的功能特性,在访问时序也有一定的差异。

i2c_driver结构体,描述一个i2c设备驱动,定义如下:

struct i2c_driver {
	unsigned int class;

	//老式的探测函数,已不推荐使用
	int (*attach_adapter)(struct i2c_adapter *) __deprecated;

	/* 驱动与适配时,会调用probe函数 */
	int (*probe)(struct i2c_client *, const struct i2c_device_id *);
	
	......
	
	struct device_driver driver;

	//该驱动所支持的设备ID
	const struct i2c_device_id *id_table;

	/* 探测函数 */
	int (*detect)(struct i2c_client *, struct i2c_board_info *);

	//探测设备地址列表
	const unsigned short *address_list;

	//该驱动支持的设备会通过这个链表头链在一起
	struct list_head clients;
}

i2c_client结构体,描述一个i2c设备,定义如下:

struct i2c_client {
	unsigned short flags;		/* div., see below		*/

	//设备地址
	unsigned short addr;		

	char name[I2C_NAME_SIZE];

	//设备所挂在的控制器
	struct i2c_adapter *adapter;	/* the adapter we sit on	*/

	struct device dev;		/* the device structure		*/

	int irq;			/* irq issued by device		*/

	//通过这个链表节点,挂接在驱动的clients链表
	struct list_head detected;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
	i2c_slave_cb_t slave_cb;	/* callback for slave mode	*/
#endif
};

下面梳理一下i2c_driver、i2c_client、i2c_adapter和i2c_algorithm这4个数据结构的作用及其盘根错节的关系。

  1. i2c_adapter与i2c_algorithm
    i2c_adapter对应于物理上的一个i2c适配器,而i2c_algorithm对应一套通信方法。一个i2c适配器需要i2c_algorithm中提供的通信函数来控制适配器上产生特定的访问周期。缺少 i2c_algorithm的i2c_adapter什么也做不了,因此i2c_adapter中包含其使用的 i2c_algorithm 的指针。i2c_algorithm中的关键函数master_xfer()用于产生i2c访问周期需要的信号,以 i2c_msg为单位。i2c_msg结构体也非常关键,代码清单如下给出了它的定义:
struct i2c_msg {
	__u16 addr;	/* 设备地址	*/
	__u16 flags;
#define I2C_M_RD		0x0001	/* read data, from slave to master */
														/* I2C_M_RD is guaranteed to be 0x0001! */
#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */
#define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
#define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_NOSTART */
#define I2C_M_STOP		0x8000	/* if I2C_FUNC_PROTOCOL_MANGLING */
	__u16 len;		/* 信息长度				*/
	__u8 *buf;		/* 信息数据			*/
};
  1. i2c_driver与i2c_client
    i2c_driver对应一套驱动方法,其主要成员函数是probe()、 remove()、 suspend()、 resume()等,另外id_table是该驱动所支持的i2c设备的ID表。i2c_client对应于真实的物理设备,每个i2c设备都需要一个i2c_client来描述。i2c_driver与i2c_client的关系是一对多,一个 i2c_driver上可以支持多个同等类型的i2c_client。

  2. i2c_adpater与i2c_client
    i2c_adpater与i2c_client的关系与i2c硬件体系中适配器和设备的关系一致,即i2c_client依附于i2c_adpater。由于一个适配器上可以连接多个I2C设备,所以一个i2c_adpater也可以被多个i2c_client 依附,i2c_adpater中包括依附于它的i2c_client的链表。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值