Linux I2C驱动分析与实现(一)

来源:互联网 发布:c语言谭浩强 编辑:程序博客网 时间:2024/05/17 01:29

====本文系本站原创,欢迎转载! 转载请注明出处:http://blog.csdn.net/yyplc====

本文基于内核版本linux-2.6.30.4分析.

Linux中i2c子系统框图如下:

•客户驱动

即I2C设备驱动,每个客户驱动可以为一个或多个I2C设备服务,并向用户空间提供相应的访问接口函数。

客户驱动需要向总线注册并通过i2c-core提供的接口与I2C设备通信。与客户程序相关的数据结构主要有struct i2c_driver和struct i2c_client

添加客户驱动:static inline int i2c_add_driver(struct i2c_driver *driver)

删除客户驱动:extern void i2c_del_driver(struct i2c_driver *);   

I2C-core核心

I2c-core核心是I2C总线的核心,承上启下,其实现与平台无关。I2C总线的初始化、注册和适配器添加和注销等相关工作均在I2C核心代码中完成,

除此之外,还向上层客户驱动提供相应的API接口函数,使得客户驱动独立于适配器驱动而工作。

• 适配器驱动

负责对I2C控制器的驱动实现,一个总线对应一个适配器。I2C总线上对I2C slave设备的具体

操作是在适配器驱动中完成的。适配器驱动作为platform_driver而注册,在probe()到驱动设

备后,向总线声明并被添加:i2c_add_numbered_adapter(&i2c->adap);

I2c-dev驱动是系统自带的一个通用客户驱动,它不是针对某一个I2C设备(即没有自己驱动设备id-table),它可以使得用户空间的程序通过i2c-tools访问总线上的i2c/SMBUS设备。

I2C子系统主要数据结构

•struct i2c_msg;             //I2C消息数据结构•struct i2c_algorithm;       //算法驱动数据结构•struct i2c_adapter;         //I2C适配器数据结构•struct i2c_client;          //I2C客户数据结构•struct i2c_driver;          //I2C设备驱动数据结构•struct i2c_board_info;      //描述板载I2C设备的信息   

以上数据结构在include/linux/i2c.h中定义,下面我们结合源码分析一下这些数据结构

I2C算法结构:

struct i2c_algorithm {   /* If an adapter algorithm can't do I2C-level access, set master_xfer      to NULL. If an adapter algorithm can do SMBus access, set      smbus_xfer. If set to NULL, the SMBus protocol is simulated      using common I2C messages */   /* master_xfer should return the number of messages successfully      processed, or a negative value on error */   int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,            int num);   int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,            unsigned short flags, char read_write,            u8 command, int size, union i2c_smbus_data *data);    /* To determine what the adapter supports */   u32 (*functionality) (struct i2c_adapter *);};

例如:

s3c2440 i2c 适配器驱动是这样实现这个算法结构体:

static const struct i2c_algorithm s3c24xx_i2c_algorithm = {     .master_xfer            = s3c24xx_i2c_xfer,     .functionality          = s3c24xx_i2c_func,};

s3c24xx_i2c_xfer 是适配器的对I2C设备的读写操作函数

s3c24xx_i2c_func函数决定了该适配器向i2c-core核心支持哪些API函数

I2c_adapter结构标识一个物理I2C总线(适配器),总线通过

算法结构访问到适配器。

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;     /* --- administration stuff. */    int (*client_register)(struct i2c_client *) __deprecated;    int (*client_unregister)(struct i2c_client *) __deprecated;     /* data fields that are valid for all devices  */    u8 level;                /* nesting level for lockdep */    struct mutex bus_lock;    struct mutex clist_lock;     int timeout;            /* in jiffies */    int retries;    struct device dev;      /* the adapter device */     int nr;    struct list_head clients;     /* DEPRECATED */    char name[48];    struct completion dev_released;};

I2c_msg是I2C消息,I2C通信是以i2c_msg为单位的。

struct i2c_msg {   __u16 addr;     /* slave address            */   __u16 flags;#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 */   __u16 len;      /* msg length               */   __u8 *buf;      /* pointer to msg data           */};

I2c_client描述了一个i2c设备。

struct i2c_client {     unsigned short flags;        /* div., see below         */     unsigned short addr;        /* chip address - NOTE: 7bit */                            /* addresses are stored in the      */                            /* _LOWER_ 7 bits        */     char name[I2C_NAME_SIZE];     struct i2c_adapter *adapter;    /* the adapter we sit on       */     struct i2c_driver *driver;  /* and our access routines    */     struct device dev;            /* the device structure          */     int irq;                     /* irq issued by device          */     struct list_head list;          /* DEPRECATED */     struct list_head detected;     struct completion released;};

I2c_driver描述了I2C设备的驱动。

struct i2c_driver {      int id;      unsigned int class;       /* Notifies the driver that a new bus has appeared. This routine       * can be used by the driver to test if the bus meets its conditions       * & seek for the presence of the chip(s) it supports. If found, it       * registers the client(s) that are on the bus to the i2c admin. via       * i2c_attach_client.  (LEGACY I2C DRIVERS ONLY)       */      int (*attach_adapter)(struct i2c_adapter *);      int (*detach_adapter)(struct i2c_adapter *);       /* tells the driver that a client is about to be deleted & gives it       * the chance to remove its private data. Also, if the client struct       * has been dynamically allocated by the driver in the function above,       * it must be freed here.  (LEGACY I2C DRIVERS ONLY)       */      int (*detach_client)(struct i2c_client *) __deprecated;      。。。}

I2C核心提供的API函数

•      extern int i2c_master_send(struct i2c_client *client, const char *buf,•                    int count);•      extern int i2c_master_recv(struct i2c_client *client, char *buf, int count); •      extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,•                 int num);•      extern s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,•                   unsigned short flags, char read_write, u8 command,•                   int size, union i2c_smbus_data *data);•      extern s32 i2c_smbus_read_byte(struct i2c_client *client);•      extern s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value);•      extern s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command);•      extern s32 i2c_smbus_write_byte_data(struct i2c_client *client,•                           u8 command, u8 value);•      extern s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command);•      extern s32 i2c_smbus_write_word_data(struct i2c_client *client,•                           u8 command, u16 value);

其中: i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 是实现其他函数的基础,换句话说,其它函数均是通过调用该函数来实现的。

下篇将具体谈谈Linux 中如何实现I2C客户程序。《Linux I2C驱动分析与实现(二)》