Linux I2C体系结构分析

本文深入探讨了Linux I2C系统结构,通过在板级文件中定义i2c_board_info来指定设备名称和地址,并将其注册到__i2c_board_list链表。在i2c_register_adapter和i2c_scan_static_board_info过程中,链表被用于搜索和匹配I2C设备。当设备适配器未知时,利用detect函数进行识别和分配。
摘要由CSDN通过智能技术生成
开发环境:Linux-2.6.32.2内核   Fedora 10虚拟机 gcc4.3.2版本的交叉编译器
一、I2C体系结构
      Linux的I2C体系结构分为3个组成部分:I2C核心、I2C总线驱动、I2C设备,如下图所示。I2C核心提供总线驱动和设备驱动的注册、注销方法。它以通用的,与平台无关的接口实现了I2C中设备与适配器的沟通。I2C总线驱动对硬件体系结构中适配器的实现,主要包括适配器i2c_adapter、适配器通信算法i2c_algorithm,如果CPU集成了I2C控制器并且linux内核支持这个CPU,那么总线驱动就不用管,比如S3C2440就属于这类情况,在后文中我们将分析它的总线驱动;I2C设备驱动是具体的一个设备(如AT24C02),挂接在CPU控制的I2C适配器的设备驱动,有了这部分驱动才能使用控制器操作该设备,设备驱动主要包括i2c_driver 和i2c_client数据结构。填充i2c_driver 结构体并实现其本身对应设备类型的驱动。
                         
二、分析I2C核心
linux-2.6.32.2/drivers/i2c/i2c-core.c //i2c子系统的公用代码,驱动开发者只需要用而不需要修改
1. 初始化i2c子系统
static int __init i2c_init(void)//在系统启动模块加载阶段中调用来初始化i2c子系统
   1.1 bus_register(&i2c_bus_type);//注册一条IIC总线,注册适配器、IIC设备、IIC设备驱动都会连接到这条总线上
   1.2 class_compat_register("i2c-adapter");//注册适配器类,用于实现文件系统的部分功能  (驱动人员不用关心)
   1.3 retval = i2c_add_driver(&dummy_driver);//将一个空驱动注册到总线上  (驱动人员不用关心)
     struct bus_type i2c_bus_type = {
          .name          = "i2c",
          .match          = i2c_device_match,
          .probe          = i2c_device_probe,
          .remove          = i2c_device_remove,
          .shutdown     = i2c_device_shutdown,
          .suspend     = i2c_device_suspend,
          .resume          = i2c_device_resume,
     };
2. 卸载i2c子系统
static void __exit i2c_exit(void)
   i2c_del_driver(&dummy_driver);//注销空驱动
   bus_unregister(&i2c_bus_type);//注销一条IIC总线
3.函数接口
3.1适配器i2c_adapter的添加、删除
  int i2c_add_adapter(struct i2c_adapter *adapter)
  int i2c_add_numbered_adapter(struct i2c_adapter *adap)//两个接口都是向IIC子系统添加适配器结构体,该结构体在前面要进行分配和初始化
使用:在总线驱动probe()被调用。如:s3c24xx_i2c_probe,先设置adap.name、adap.owner、adap.algo、adap.retries  adap.class、adap.algo_data、adap.dev.parent、adap.nr等成员
  int i2c_del_adapter(struct i2c_adapter *adap)//删除上面两个接口添加的适配器结构体
3.2增加/删除i2c_driver
  int i2c_register_driver(struct module *owner, struct i2c_driver *driver);
  int i2c_del_driver(struct i2c_driver *driver);
  inline int i2c_add_driver(struct i2c_driver *driver);
使用:在设备驱动i2c_dev_init被调用。如i2c-dev.c中的i2c_dev_init()函数。首先要定义一个i2c_driver结构体
static struct i2c_driver i2cdev_driver = {     .driver = {          .name     = "dev_driver",     },     .attach_adapter     = i2cdev_attach_adapter,     .detach_adapter     = i2cdev_detach_adapter,};
在i2c_register_driver设置driver->driver.owner、driver->driver.bus
3.3 i2c_client依附/脱离
  int i2c_attach_client(struct i2c_client *client);
  int i2c_detach_client(struct i2c_client *client);
  //当一个具体的client被侦测到并被关联的时候,设备和sysfs文件将被注册。相反地,在client被取消关联的时候,sysfs文件和设备也被注销。
3.4i2c传输、发送和接收
  int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num);
  int i2c_master_send(struct i2c_client *client,const char *buf ,int count);
  int i2c_master_recv(struct i2c_client *client, char *buf ,int count);
  i2c_transfer()函数用于进行I2C适配器和I2C设备之间的一组消息交互,i2c_master_send()函数和i2c_master_recv()函数内部会调用i2c_transfer()函数分别完成一条写消息和一条读消息。 i2c_transfer()函数本身不具备驱动适配器物理硬件完成消息交互的能力,它只是寻找到i2c_adapter 对应的i2c_algorithm,并使用i2c_algorithm的master_xfer()函数真正驱动硬件流程。(比如:s3c24xx_i2c_xfer)
2.2 IDR机制/include/linux/idr.h
二、分析重要的结构体
linux-2.6.32.2/include/linux/i2c.h
1.struct i2c_msg;   消息结构体,是适配器到IIC设备传输数据的基本单位
struct i2c_msg {
     __u16 addr;     /* slave address IIC设备地址          */
     __u16 flags;   /*消息类型标志*/
     __u16 len;          /* msg length     消息字节长度          */
     __u8 *buf;          /* pointer to msg data     指向消息数据的缓冲区*/
#define I2C_M_TEN          0x0010     /* this is a ten bit chip address */
#define I2C_M_RD          0x0001     /* read data, from slave to master */ //主机从从机读数据
#define I2C_M_NOSTART          0x4000     /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR     0x2000     /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK     0x1000     /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK          0x0800     /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN          0x0400     /* length will be first received byte */ //第一次接收的字节长度
};
//==============Start IIC总线层=========================================
2.struct i2c_algorithm;         描述了适配器与设备之间的通信方法
struct i2c_algorithm {
     int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,int num);
     //指向实现IIC总线通信协议的函数
     int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,unsigned short flags, char read_write,
                  u8 command, int size, union i2c_smbus_data *data);
        //指向实现SMBus总线通信协议的函数,SMBus总线通信协议是基于IIC协议的原理(也是2条总线,时钟和数据)
     u32 (*functionality) (struct i2c_adapter *);//确定适配器支持哪些传输类型
};
例子:
static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
     .master_xfer          = s3c24xx_i2c_xfer,
     .functionality          = s3c24xx_i2c_func,
};
3.struct i2c_adapter;
       IIC总线适配器,即是IIC总线控制器。主要功能是完成IIC总线控制器相关的数据通信。为描述了各种IIC适配器提供了通用的"模版",定义指向具体IIC适配器的总线通信方法i2c_algorithm的指针algo、实现IIC总线操作原子性操作的lock信号量。特定的适配器可在此基础上进行扩充
struct i2c_adapter {
     struct module *owner;
     unsigned int id;
     unsigned int class;            /* classes to allow probing for 允许探测的驱动类型 */
     const struct i2c_algorithm *algo; /* the algorithm to access the bus  总线通信方法指针*/
     void *algo_data;                      /* algorithm数据*/
     u8 level;                /* nesting level for lockdep */
     struct mutex bus_lock;
     int timeout;               /* in jiffies */
     int retries;
     struct device dev;          /* the adapter device */
     int nr;      //通过nr整型数从红黑树得到与之对应的i2c_adapter适配器结构
     char name[48];  /*适配器名称*/
     struct completion dev_released; /*用于同步*/
};
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
 //==================End IIC总线==================================
//==================Start IIC设备层================================
4.struct i2c_client; //IIC设备,一个结构体描述一个真实的物理IIC设备
struct i2c_client {
     unsigned short flags;          /* div., see below          */
     unsigned short addr;          /* chip address - NOTE: 7bit    芯片低7位地址*/
     char name[I2C_NAME_SIZE];  /*设备名字*/
     struct i2c_adapter *adapter;     /* the adapter we sit on     依附i2c_adapter*/
     struct i2c_driver *driver;     /* and our access routines 依附i2c_driver  */
     struct device dev;          /* the device structure      设备结构体    */
     int irq;               /* irq issued by device          */
     struct list_head detected;  /*链表头 */
};
#define to_i2c_client(d) container_of(d, struct i2c_client, dev)
5.struct i2c_driver; //IIC设备驱动
每个IIC设备对应一个驱动,即是每个i2c_client对应一个i2c_driver结构,通过包含指针来连接
struct i2c_driver {
    unsigned int class; /*驱动类型*/
/*************************************传统函数**********************************/
     int (*attach_adapter)(struct i2c_adapter *);       /*依附i2c_adapter函数指针*/
    int (*detach_adapter)(struct i2c_adapter *);       /*脱离i2c_adapter函数指针*/
/**********************************************************************************/
  //新旧两种驱动程序函数,只能选择其中一种。新的支持IIC设备的动态插入和拔出,旧的不支持!!!!!!!
/************************************新型函数**************************************/
     int (*probe)(struct i2c_client *, const struct i2c_device_id *);
    int (*remove)(struct i2c_client *);
    void (*shutdown)(struct i2c_client *);
    int (*suspend)(struct i2c_client *, pm_message_t mesg);
    int (*resume)(struct i2c_client *); /* probe,remove,suspend,resume驱动方法重要成员函数 */
/***********************************************************************************/
    int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);   /*类似ioctl*/
    struct device_driver driver;   /*指向设备驱动的结构体*/
    const struct i2c_device_id *id_table;   /* 驱动支持多个设备,这里面就要包含这些设备的ID */
    const struct i2c_client_address_data *address_data;   / *设备映射到内存的地址范围*/
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值