linux I2C驱动移植

linux I2C驱动移植

I²C总线仅使用SCL,SDA两根信号线实现设备间的数据交互,被广泛应用于微控制领域芯片与芯片之间的通信,如EEPROM,实时时钟,小型LCD等与CPU之间的通信。

I2C协议

I2C利用两根总线根据自己的通信协议实现数据交互

  • 起始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。
  • 停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。这里写图片描述

  • ACK应答信号:发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。
    这里写图片描述

以上就是I2C的时序,在单片机上用到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支持

  • 添加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       
  • 修改内核文件 linux/arch/arm/mach-s3c2440/mach-smdk2440.c
    添加如下代码:

    
    #include   /*添加头文件*/
    
    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,  
    },  
    };  
    
    /*在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/进行以下测试:

这里写图片描述

参考文档:http://blog.csdn.net/wangpengqi/article/details/17711165

你可能感兴趣的:(FL2440驱动)