I2C驱动开发手册

2020/09/03 LINUX 共 3502 字,约 11 分钟

I2C驱动开发手册

目录

1. 介绍

本文介绍了Siflower的I2C驱动的流程

1.1. 适用人员

开发人员应该具备以下技能:

  • 熟悉C语言
  • 熟悉Linux Device Driver开发

1.2. 开发环境

  • 可以正常编译通过的Siflower SDK环境 该环境的搭建请参考快速入门

2. I2C概述

I2C总线是由philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。 sfax8 i2c总线由一个串行数据线SDA和串行时钟线SCL组成.这两根线负责在连到bus上的设备之间传输信息。每个设备必须要有一个单独的地址,并且在数据传输时,可以作为master或者slave。Master发起数据传输并生成时钟信号,并允许这个传输,这时指定地址的设备都作为slave,.为了服从于i2c系统,i2c总线接口需要外部的硬件i2c(sfax8 i2c有3个)支持。这个i2c可以作为master或者slave. I2C block diagram
Master/slave and transmit/receive relationship Data transfer on the i2c bus

Master transmit and slave receive: master transmitter初始化数据传输,生成时钟,向slave地址发出请求,Slave receiver在收到master的请求后回这个请求,transmitter在收到receiver的ack后发出数据,receiver从bus获取数据,当数据发完也由master transmitter来终止传输。
Master receive and slave transmit: master receiver初始化数据传输,生成时钟,并发出数据请求, slave transmitter在收到请求后,回复这个请求,发送数据到bus,receiver从bus获取数据,数据发完后,由master receiver来终止传输。

3. I2C驱动

3.1. 重要接口

static struct file_operations i2c_ops = {  
    .owner = THIS_MODULE,  
    .open  = sfax8_i2c_debug_open,  
    .read  = sfax8_i2c_debug_read,  
    .write  = sfax8_i2c_debug_write,  
    .llseek  = default_llseek,  
    .release = single_release,  
};   //创建debug节点,并有debug的作用

static struct i2c_algorithm i2c_sf_algo = {  
    .master_xfer    = i2c_sf_xfer,    //进行数据传输  
    .functionality  = i2c_sf_func,  
};  

static const struct file_operations i2cdev_fops = {  
    .owner      = THIS_MODULE,  
    .llseek     = no_llseek,  
    .read       = i2cdev_read,  
    .write      = i2cdev_write,    
    .unlocked_ioctl = i2cdev_ioctl,  
    .open       = i2cdev_open,  
    .release    = i2cdev_release,  
};   //对i2c设备的数据传输过程

3.2. 重要结构体

struct i2c_rdwr_ioctl_data {  
    struct i2c_msg __user \*msgs;    /\* pointers to   i2c_msgs \*/  
    __u32 nmsgs;            /\* number of i2c_msgs \*/  
};  
/* This is the structure as used in the I2C_RDWR ioctl call */ 
 
struct i2c_msg {  
    __u16 addr; /* slave address */  
    __u16 flags;  
    __u16 len;      /* msg length */  
    __u8 *buf;      /* pointer to msg data */  
};  
//an I2C transaction segment beginning with START  

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;                                                                                                                                                       
    struct rt_mutex bus_lock;        /* data fields that are valid for all devices */                                                                                                               
    int timeout;            /* in jiffies */                               
    int retries;                                                           
    struct device dev;      /* the adapter device */                                                                                                                     
};                                                                         
/*                                                                         
 * i2c_adapter is the structure used to identify a physical i2c bus along  
 * with the access algorithms necessary to access it.                      
 */ 

3.3. 驱动框架

  • sf_i2c_probe:获取设备中断,分配设备内存,请求io资源,获取dts中的时钟频率,这里只支持standard mode(100kHz),fast mode(400kHz),high speed mode(3.4mHz),若fifo depth为0,则设为16.注册i2c_sf_isr到i2c中断,当出现i2c中断时都会调这个函数。添加i2c adapter。
  • I2cdec_ioctl:

| cmd | function |
| — | ——– |
| I2C_TENBIT | flag设置7bit或者10bit地址模式 |
| I2C_PEC | flag设置packet err checking |
| I2C_RETRIES | 设置当丢失仲裁时,重试的次数 |
| I2C_TIMEOUT | 设置i2c等待传输完成的最大时间 |
| I2C_RDWR | 进行数据传输 |
其中flag配置,都需要在进行数据传输的时候才会去配置寄存器进行配置。

  • i2cdev_ioctl_rdrw:从用户层将数据copy到内核.为了避免因为仲裁导致数据不能立即发出去,所以message数量不能特别大,这里定义最大message数量为42.每个message的长度也限制为8192,确定了配置正确后,调用i2c_transfer传输数据,数据传输完成后,将receiver的数据copy到用户空间。
  • i2c_master_recv:进行master receive模式的单个message传输。
  • I2c_master_send:进行master transmit模式的单个message传输。
  • i2c_transfer:调用master_xfer来传输数据,考虑到仲裁的问题,在timeout时间时候数据发送不成功,则会重新进行调用master_xfer来进行数据传输。
  • i2c_sf_xfer:判断i2c bus状态是否为busy,如果为busy,则会直接结束,若为idle,则调用i2c_sf_xfer_init开始传输,然后等待数据传输完,若在timeout时间内还没有完成则报错退出(timeout时间为设置的值,若未设,则会根据数据量与传输速度计算得到)。
  • i2c_sf_xfer_init:根据用户配置的参数,配置是否为10bit地址,配置slave地址,打开i2c adapter。
  • i2c_sf_isr:当出现i2c中断时被调用,首先会判断i2c是否被enable,中断是否打开,若i2c enable且中断打开,则会去判断是什么中断,若是tx abort中断,将bus状态置为idle,并丢弃tx/rx buffer中的数据。若是rx full中断,调用i2c_sf_read。若是tx empty中断,则调用i2c_sf_xfer_msg。
  • i2c_sf_read:触发rx full中断时,从rx data buffer中读出有效数据。
  • i2c_sf_xfer_msg:触发tx empty时,写数据到tx buffer。
  • sfax8_i2c_debug_read:cat i2c_debug,可以看到i2c debug的用法。
  • sfax8_i2c_debug_write:可以通过echo i2c_debug来读写目的寄存器。
  • sfax8_i2c_debug_write:可以通过echo i2c_debug来读写目的寄存器。

文档信息

Search

    Table of Contents