红联Linux门户
Linux帮助

linux I2C驱动移植

发布时间:2017-06-08 11:11:43来源:blog.csdn.net/edroid1530作者:Escropion
I²C总线仅使用SCL,SDA两根信号线实现设备间的数据交互,被广泛应用于微控制领域芯片与芯片之间的通信,如EEPROM,实时时钟,小型LCD等与CPU之间的通信。
 
I2C协议
I2C利用两根总线根据自己的通信协议实现数据交互
起始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。
停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。
linux I2C驱动移植
ACK应答信号:发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。
linux I2C驱动移植
以上就是I2C的时序,在单片机上用到I2C我们需要自己写时序,然而在Linux I2C中我们不需要自己写时序,内核已经帮我们实现。
 
Linux I2C架构层次
linux I2C驱动移植
第一层:提供i2c adapter的硬件驱动,探测、初始化i2c adapter(如申请i2c的io地址和中断号),驱动soc控制的i2c adapter在硬件上产生信号(start、stop、ack)以及处理i2c中断。覆盖图中的硬件实现层
第二层:提供i2c adapter的algorithm,用具体适配器的xxx_xferf()函数来填充i2c_algorithm的master_xfer函数指针,并把赋值后的i2c_algorithm再赋值给i2c_adapter的algo指针。覆盖图中的访问抽象层、i2c核心层
第三层:实现i2c设备驱动中的i2c_driver接口,用具体的i2c device设备的attach_adapter()、detach_adapter()方法赋值给i2c_driver的成员函数指针。实现设备device与总线(或者叫adapter)的挂接。覆盖图中的driver驱动层
第四层:实现i2c设备所对应的具体device的驱动,i2c_driver只是实现设备与总线的挂接,而挂接在总线上的设备则是千差万别的,所以要实现具体设备device的write()、read()、ioctl()等方法,赋值给file_operations,然后注册字符设备(多数是字符设备)。覆盖图中的driver驱动层
第一层和第二层又叫i2c总线驱动(bus),第三第四属于i2c设备驱动(device driver)。
在linux驱动架构中,几乎不需要驱动开发人员再添加bus,因为linux内核几乎集成所有总线bus,如usb、pci、i2c等等。并且总线bus中的(与特定硬件相关的代码)已由芯片提供商编写完成,例如三星的s3c-2440平台i2c总线bus为/drivers/i2c/buses/i2c-s3c2410.c
 
Linux I2C驱动结构
linux下I2C驱动体系结构包括I2C总线驱动,I2C核心,I2C从设备驱动三个部分。一般来说,如果CPU中集成了I2C控制器并且Linux内核支持这个CPU,那么总线驱动方面内核会帮我们实现。但如果CPU中没有I2C控制器,而是外接的话则需要我们自己实现I2C总线驱动。对于设备驱动来说,常用的设备驱动内核已经帮我们实现,同样,如果用到比较少见的I2C设备,内核没有帮我们实现,则需要我们自己完成设备驱动的编写。
* I2C总线驱动
2440中的I2C控制器有一个驱动(s3c2440中的I2C适配器驱动基于platform实现)。这个驱动用来操作控制器来产生特定的I2C的时序信号,来发送数据和接收数据。也就是让适配器工作。
* I2C设备驱动
挂接在I2C总线上的从设备AT24C02(e2prom)为例,它也有一个驱动,这个用来操作读写我们的芯片,读取和存放具体获得的数据。
* I2C核心
通过一系列的通信方法(algorithm)把总线驱动,设备驱动与用户层串起来,其中还包括有总线驱动和设备驱动的注册,注销方法。i2c-core.c实现i2c核心的功能以及/proc/bus/i2c*接口。
 
driver的I2C目录下的文件介绍
i2c-core.c为I2C驱动中的I2C核心,提供了一组不依赖于硬件平台的接口函数(/proc/bus/i2c*接口)作为I2C总线驱动和I2C设备驱动之间的纽带。如:
int i2c_add_adapter(struct i2c_adapter *adapter)
int i2c_del_adapter(struct i2c_adapter *adap)
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
void i2c_del_driver(struct i2c_driver *driver)
i2c-dev.c实现了I2C适配器设备文件的功能,每一个I2C适配器都被分配至少一个设备。通过适配器访设备时的主设备号都为89,次设备号为0-255。 I2c-dev.c并没有针对特定的设备而设计,只是提供了通用的read(),write(),和ioctl()等接口,应用层可以借用这些接口访问挂接在适配器上的I2C设备的存储器或寄存器,并控制I2C设备的工作方式。
busses文件夹中包含了一些I2C总线的驱动,如针对S3C2410处理器的I2C控制器驱动为i2c-s3c2410.c。在该文件中,定义描述具体I2C总线适配器的i2c_adapter数据结构、实现在具体I2C适配器上的I2C总线通信方法, 并由i2c_algorithm数据结构进行描述。 经过I2C总线驱动的的代码,可以为我们控制I2C产生开始位、停止位、读写周期以及从设备的读写、产生ACK等。
algos文件夹实现了一些I2C总线适配器的algorithm。
 
关于AT24C02
AT24C02的存储容量为2Kb (2048bit) ,内容分成32页,每页8Byte,共256Byte,操作时有两种寻址方式:芯片寻址和片内子地址寻址。
(1)芯片寻址:AT24C02的芯片地址为1010,其地址控制字格式为 1010A2A1A0R/W。其中A2,A1,A0可编程地址选择位。A2,A1,A0引脚接高、
低电平后得到确定的三位编码,与1010形成7位编码, 即为该器件的地址码。R/W为芯片读写控制位,该位为0,表示芯片进行写操作。
(2)片内子地址寻址:芯片寻址可对内部256B中的任一个进行读/写操作,其寻址范围为00~FF,共256个寻址单位。
 
修改内核添加I2C支持
1.添加make menuconfig
Device Drivers  --->  
<*> I2C support  --->     
[*]   Enable compatibility bits for old user-space
<*>   I2C device interface 
< >   I2C bus multiplexing support  
[*]   Autoselect pertinent helper modules
I2C Hardware Bus support  --->  
[*]   I2C Core debugging messages
[*]   I2C Algorithm debugging messages
[ ]   I2C Bus debugging messages 
[*] Misc devices  --->
EEPROM support  --->   
<*> I2C EEPROMs from most vendors 
<*> SPI EEPROMs from most vendors  
<*> Old I2C EEPROM reader  
< > Maxim MAX6874/5 power supply supervisor 
<*> EEPROM 93CX6 support       
2.修改内核文件 linux/arch/arm/mach-s3c2440/mach-smdk2440.c
添加如下代码:
#include <linux/i2c/at24.h>  /*添加头文件*/
static struct at24_platform_data at24c02 ={
.byte_len   = SZ_2K / 8,  
.page_size  = 8,  
.flags      = 0,  
}
static struct i2c_board_info __initdata smdk_i2c_devices[] = {  
/* more devices can be added using expansion connectors */  
{  
I2C_BOARD_INFO("24c02", 0x50),  
.platform_data = &at24c02,  
},  
};  
3./*在smdk2440_machine_init函数中增加如下:*/
i2c_register_board_info(0, smdk_i2c_devices, ARRAY_SIZE(smdk_i2c_devices));
 
测试EEPROM
对内核完成上述修改之后,重新编译内核并烧录到开发板运行。启动后进入
/sys/devices/platform/s3c2440-i2c/i2c-0/0-0050/进行以下测试:
linux I2C驱动移植
 
本文永久更新地址:http://www.linuxdiyf.com/linux/31337.html