接下来本节, 学习Linux下如何利用linux下I2C驱动体系结构来操作24C02
其中重要的文件介绍如下:
里面保存I2C的通信方面的算法
里面保存I2C设备驱动相关的文件,如下图所示,比如m41t00,就是RTC实时钟
这个文件实现了I2C核心的功能(I2C总线的初始化、注册和适配器添加和注销等相关工作)以及/proc/bus/i2c*接口。
提供了通用的read( ) 、 write( ) 和ioctl( ) 等接口,实现了I2C适配器设备文件的功能,其中I2C设备的主设备号都为89, 次设备号为0~255。
应用层可以借用这些接口访问挂接在适配器上的I2C设备的存储空间或寄存器, 并控制I2C设备的工作方式
显然,它和前几次驱动类似, I2C也分为总线驱动和设备驱动,总线就是协议相关的,它知道如何收发数据,但不知道数据含义,设备驱动却知道数据含义
对于i2c_add_adapter()而言,它使用的是动态总线号,即由系统给其分析一个总线号,而i2c_add_numbered_adapter()则是自己指定总线号,如果这个总线号非法或者是被占用,就会注册失败.
2.接下来便来分析I2C总线驱动
先进入init入口函数,如下图所示:
/*注册中断服务函数*/
而i2c_adapter适配器结构体的成员结构,如下所示:
int retries; //重试次数 char name[48]; //适配器名称
//设置IICSTAT寄存器的bit5=1,开始发送起始信号+IIC从设备地址值,并回应ACK
通过上面的代码和注释,发现主要是写入IIC从设备地址,然后发送起始信号+IIC从设备地址值,并回应ACK
显然IIC总线驱动i2c-s3c2410.c,主要设置适配器adapter,里面帮我们做好了IIC通信的架构,就是不知道发什么内容
6.还是首先来看它的init入口函数:
上图的第1个参数就是i2c_adapter适配器,第2个参数addr_data变量,里面存放了IIC设备地址的信息,第3个参数eeprom_detect就是具体的设备探测回调函数i2c_probe()函数,会通过adapter适配器发送IIC设备地址addr_data,如果收到ACK信号,就调用eeprom_detect()回调函数来注册i2c_client结构体,该结构体对应真实的物理从设备,而i2c_driver对应的是设备驱动,也就是说,只有当适配器支持这个设备驱动,才会注册i2c_client从设备,后面会讲这个回调函数如何注册i2c_client
当上面结构体的数组成员以I2C_CLIENT_END结尾,则表示地址已结束,比如at24c02设备为例,看这个结构体如何定义的:
一般而言,都不会设置.forces成员,这里只是打个比方
8.1接下来继续进入i2c_probe()函数继续分析,如下所示:
里面调用了i2c_probe_address()函数,从名称上来看,显然它就是用来发送起始信号+设备地址,来探测IIC设备地址用的
/*查找链表中其它IIC设备的设备地址,若这个设备地址已经被使用,则return*/
} else //否则使用默认函数传输设备地址
其中i2c_msg结构体的结构,如下所示:
上面代码中之所以读操作需要两个i2c_msg,写操作需要一个i2c_msg,是因为读IIC设备是两个流程
在上一节IIC接口下的24C02 驱动分析: 里就已经分析到了,
只要发送一个S起始信号则就是一个i2c_msg,如下两个读写操作图所示:
内核每发送一个Msg都会先发出S开始信号和设备地址.直到所有Msg传输完毕,最后发出P停止信号。
当i2c_transfer()返回值为正数,表示已经传输正数个数据,当返回负数,说明I2C传输出错
2) 将要发的设备地址结构体打包成i2c_msg,
4)若收到ACK回应,便进入回调函数,注册i2c_client从设备,使该设备与适配器联系在一起
所以适配器和iic设备驱动最终注册框架图如下所示:
9.接下来便来分析回调函数如何注册i2c_client从设备的
具体驱动代码如下所示:
* 设置字符设备的读写函数(实现对24C02的读写操作)