I2C总线(四)I2C子系统(2)

I2C总线(四)I2C子系统(2)_第1张图片

分为应用层、内核层 以及硬件层。主要分析内核空间部分,内核空间部分可以分为:IIC设备驱动、IIC核心以及IIC总线驱动

1、IIC核心

IIC核心提供IIC总线驱动和设备驱动的注册、注销方法,IIC通信方法(algorithm)上层的,与具体的适配器无关的代码以及探测设备、检测设备地址的上层代码等。

2、IIC总线驱动

IIC总线驱动是对IIC硬件体系结构中适配器端的实现,就是怎样操作IIC模块工作。适配器可由CPU控制,甚至直接集成到CPU里面。IIC总线驱动主要包括了IIC适配器数据结构i2c_adapter、i2c适配器的algorithm数据结构i2c_algorithm和IIC适配器产生通信信号的函数。

3、IIC设备驱动

IIC设备驱动是对IIC硬件体系结构中设备端的实现,比如说设备上的EEPROM设备等。设备一般挂接在CPU控制的IIC适配器上,通过IIC适配器和CPU交换数据。IIC设备驱动主要包括了数据i2c_driver和i2c_client,需要根据具体设备实现其中的成员函数。

IIC核心部分是linux内核自带的,不需要开发;

IIC总线驱动部分一般是由厂商提供的,如三星公司提供的IIC总线驱动为/drivers/i2c/buses/i2c-s3c2410.c

IIC设备驱动需要自己写。

LINUX下IIC驱动体系中的四个主要数据结构以及相互之间的关系

1、i2c_driver —— IIC设备驱动:

struct i2c_driver {
	unsigned int class;            驱动类型
	int (*attach_adapter)(struct i2c_adapter *) __deprecated;  当检测到适配器时调用的函数
	int (*probe)(struct i2c_client *, const struct i2c_device_id *);
	int (*remove)(struct i2c_client *);
	void (*shutdown)(struct i2c_client *);                   关闭IIC设备
	int (*suspend)(struct i2c_client *, pm_message_t mesg);   挂起IIC设备
	int (*resume)(struct i2c_client *);                       恢复IIC设备
	void (*alert)(struct i2c_client *, unsigned int data);
	int (*command)(struct i2c_client *client, unsigned int cmd, void *arg); 使用命令使设备完成特殊的功能。类似ioctl()函数
	struct device_driver driver;                            设备驱动结构体
	const struct i2c_device_id *id_table;                    设备ID表
	int (*detect)(struct i2c_client *, struct i2c_board_info *);  自动探测设备的回调函数
	const unsigned short *address_list;                    设备地址所在列表
	struct list_head clients;                            指向驱动支持的设备
};

这里简单地把源码里的简介翻译翻译:

首先i2c_driver代表一个i2c设备驱动,@class:表示我们将注册的是那种设备(探测时用);@attach_adapter:添加总线时,告诉驱动的回调函数(以后可能要弃用);@probe:绑定设备时的回调函数;@remove:解除绑定时调用的回调函数;@shutdown:设备关闭时调用的回调函数;@suspend:设备挂起时调用的回调函数;@resume:设备恢复时调用的回调函数;@alert:警惕回调函数(翻译可能不准确);@command:实现特殊功能的回调函数;@driver:设备驱动模型中的驱动;@id_table:这个IIC驱动支持的设备链表;@detect:检测设备的回调函数;@address_list:检测的IIC设备的地址;@clients:检测到的我们写的client(仅仅iic核心会用)

2、i2c_client:

一个连接到i2c_bus总线上的设备用i2c_client表示,赋予linux的操作是由管理设备的驱动程序里面定义的

struct  i2c_client
{
	unsigned short  flags;       标志位
	unsigned short  addr;     设备的地址,低7位为芯片地址
	char name[I2C_NAME_SIZE];     设备的名称,最大为20个字节
	struct  i2c_adapter *adapter;  依附的适配器i2c_adapter,适配器指明所属的总线
	struct  i2c_driver *driver;    指向设备对应的驱动程序
	struct device  dev;       设备结构体
	int irq;            设备申请的中断号
	struct list_head  list;   连接到总线上的所有设备
	struct list_head   detected;   已经被发现的设备链表
};

下面是源码里的简介翻译:

首先,i2c_client代表一个IIC从设备;@flags:就是一个标示, I2C_CLIENT_TEN表示IIC从设备使用的芯片地址是10bit的,I2C_CLIENT_PEC表示设备使用SMBus错误检查;@addr:从设备在连接到相应适配器总线上使用的地址;@name:设备的名字;@adapter:挂接设备的适配器;@driver:访问设备的驱动;@irq:表明由设备产生的中断;@detected:一个i2c_driver支持的client的数量或i2c核心的用户空间设备的链表。

设备结构体i2c_client中addr的低8位表示设备地址。设备地址由读写位、器件类型和自定义地址组成,如下图:

第7位是R/W位,0表示写,2表示读,所以I2C设备通常有两个地址,即读地址和写地址;
类型器件由中间4位组成,这是由半导体公司生产的时候就已经固化了;
自定义类型由低3位组成。由用户自己设置;

     IIC设备还有一些重要的注意事项
1、i2c_client数据结构是描述IIC设备的“模板”,驱动程序的设备结构中应包含该结构;
2、adapter指向设备连接的总线适配器,系统可能有多个总线适配器。内核中静态指针数组adapters记录所有已经注册的总线适配器设备;
3、driver是指向设备驱动程序,这个驱动程序是在系统检测到设备存在时赋值的;

结构体i2c_driveri2c_client的关系较为简单,其中i2c_driver表示一个IIC设备驱动,i2c_client表示一个IIC设备。关系如下图:

I2C总线(四)I2C子系统(2)_第2张图片

3、i2c_adapter —— IIC总线控制器:

i2c_adapter:IIC总线适配器就是一个IIC总线控制器,在物理上连接若干个IIC设备。IIC总线适配器本质上是一个物理设备,其主要功能是完成IIC总线控制器相关的数据通信:

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;	          超时
	int retries;              重试次数
	struct device dev;	  指向适配器的设备结构体
	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;
};

4、i2c_algorithm

          每一个适配器对应一个驱动程序,该驱动程序描述了适配器与设备之间的通信方法:

i2c_algorithm 是为一类使用相同总线算法寻址的一个接口。当适配器不能使用i2c访问设备时,把master_xfer设置为NULL;如果一个适配器可以做SMBus访问时,设置smbus_xfer,如果把smbus_xfer设置成NULL,SMBus协议使用通用I2C模拟的消息

struct i2c_algorithm {
传输函数指针,指向实现IIC总线通信协议的函数,用来确定适配器支持那些传输类型
	int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);

smbus方式传输函数指针,指向实现SMBus总线通信协议的函数。SMBus和IIC之间可以通过软件方式兼容,所以这里提供了一个函数,但是一般都赋值为NULL
	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 *);
};

下面主要说说i2c_adapter和i2c_algorithm、i2c_driver和i2c_client的关系

a -- i2c_adapteri2c_algorithm

i2c_adapter对应与物理上的一个适配器,而i2c_algorithm对应一套通信方法,一个i2c适配器需要i2c_algorithm中提供的(i2c_algorithm中的又是更下层与硬件相关的代码提供)通信函数来控制适配器上产生特定的访问周期。缺少i2c_algorithm的i2c_adapter什么也做不了,因此i2c_adapter中包含其使用i2c_algorithm的指针。
           i2c_algorithm中的关键函数master_xfer()用于产生i2c访问周期需要的start stop ack信号,以i2c_msg(即i2c消息)为单位发送和接收通信数据。
           i2c_msg也非常关键,调用驱动中的发送接收函数需要填充该结构体

struct i2c_msg {  
	__u16 addr; /* slave address            */  
	__u16 flags;          
	__u16 len;      /* msg length               */  
	__u8 *buf;      /* pointer to msg data          */  
};  

b -- i2c_driveri2c_client

      i2c_driver对应一套驱动方法,其主要函数是attach_adapter()和detach_client()
      i2c_client对应真实的i2c物理设备device,每个i2c设备都需要一个i2c_client来描述
      2c_driver与i2c_client的关系是一对多。一个i2c_driver上可以支持多个同等类型的i2c_client.
c -- i2c_adapteri2c_client

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

IIC设备驱动程序大致可以分为设备层总线层。设备层包括一个重要的数据结构,i2c_client。总线层包括两个重要的数据结构,分别是i2c_adapteri2c_algorithm。一个i2c_algorithm结构表示适配器对应的传输数据方法。3个数据结构关系:

I2C总线(四)I2C子系统(2)_第3张图片

IIC设备层次结构较为简单,但是写IIC设备驱动程序却相当复杂。

IIC设备驱动程序的步骤

I2C总线(四)I2C子系统(2)_第4张图片

 

你可能感兴趣的:(IIC)