====本文系本站原创,欢迎转载! 转载请注明出处: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驱动分析与实现(二)》