在<linux/i2c.h>中定义了i2c驱动中的一些结构体,包含了 i2c_client, i2c_driver, i2c_adapter, i2c_algorithm, i2c_msg, 下面分析一下这些结构体
1. i2c_client 结构体
该结构体定义了挂载在I2C总线下的slave设备,一个结构体对象代表一个slave设备
struct i2c_client {
unsigned int flags; /* 设备标志 */
unsigned int addr; /* slave地址,7-bit or 10-bit */
struct i2c_adapter *adapter; /* 适配器 */
struct i2c_driver *driver; /* 该设备驱动 */
int usage_count; /* 访问设备总数 */
struct device dev; /* 设备信息 */
struct list_head list; /* 挂载总线下的设备链表 */
char name[I2C_NAME_SIZE]; /* 设备名称 */
struct completion released;
};
2. i2c_driver 结构体
该结构体与i2c_client是一对多关系,即一个驱动可以对上多个设备.根据name进行匹配.
struct i2c_driver {
struct module *owner; /* 模块拥有这,基本上设置成.owner = THIS MODULE */
char name[32]; /* 驱动名称,用于与设备名称进行匹配 */
int id; /* 与设备匹配也可以使用ID,但好像用的不多 */
unsigned int class;
unsigned int flags; /* */
int (*attach_adapter)(struct i2c_adapter *); /* 通知总线上出现一个新的驱动程序 */
int (*detach_adapter)(struct i2c_adapter *); /* 总线上移除了一个驱动程序 */
int (*detach_client)(struct i2c_client *); /* 总线上移除了一个从设备,如果这个设备是动态创建的,这里就必须被释放掉 */
/* 可以对设备进行命令控制 */
int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
struct device_driver driver; /* 设备驱动信息 */
struct list_head list;
};
3. i2c_adapter 结构体
该结构体定义了一个物理层次的I2C总线
struct i2c_adapter {
struct module *owner;
unsigned int id; /* == is algo->id | hwdep.struct->id, */
unsigned int class;
struct i2c_algorithm *algo; /* 总线通信的算法 */
void *algo_data;
/* 设备注册和取消 */
int (*client_register)(struct i2c_client *);
int (*client_unregister)(struct i2c_client *);
/* data fields that are valid for all devices */
struct semaphore bus_lock;
struct semaphore clist_lock;
int timeout; /* 定义超时时间 */
int retries; /* 重试次数 */
struct device dev; /* adapter 设备 */
struct class_device class_dev; /* class 设备 */
#ifdef CONFIG_PROC_FS
/* 如果初始化adapter,就不需要设置 */
int inode;
#endif /* def CONFIG_PROC_FS */
int nr; /* 总线号 */
struct list_head clients;
struct list_head list;
char name[I2C_NAME_SIZE]; /* adapter名称 */
struct completion dev_released;
struct completion class_dev_released;
};
4. i2c_algorithm 结构体
该I2C主设备传输数据的算法. 其中提供了关键的函数master_xfer()用于产生i2c访问周期需要的信号,以i2c_msg为单位
struct i2c_algorithm {
char name[32]; /* 算法描述,以文本形式 */
unsigned int id;
/*
*一般都使用 master_xfer() 算法
*/
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);
/* 从设备发送/接收数据 */
int (*slave_send)(struct i2c_adapter *,char*,int);
int (*slave_recv)(struct i2c_adapter *,char*,int);
/* 设置参数方法 */
int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);
/* */
u32 (*functionality) (struct i2c_adapter *);
};
5. i2c_msg 结构体
struct i2c_msg {
__u16 addr; /* 从设备地址 */
__u16 flags; /* 设备标示 */
#define I2C_M_TEN 0x10 /* 这个使用10-bit地址 */
#define I2C_M_RD 0x01
#define I2C_M_NOSTART 0x4000
#define I2C_M_REV_DIR_ADDR 0x2000
#define I2C_M_IGNORE_NAK 0x1000
#define I2C_M_NO_RD_ACK 0x0800
__u16 len; /* msg 长度 */
__u8 *buf; /* msg数据指针 */
};
I2C_M_IGNORE_NAK:
设置这个标志意味当前i2c_msg忽略I2C器件的ack和nack信号。
I2C_M_NOSTART:
设置这个标志意味当前i2c_msg不发送start信号
1.msgs序列第一个数据必须是地址,同时必须不定义这个标志位
2.在进行读数据,要从写操作转变为读操作时,会发重复start信号和器件地址时,必须不定义这个标志位
3.其它情况下一的i2c_msg必须定义这个标志
以上只是我看完这个函数的理解,不一定正确。同时1和2总结下来就是发器件地址(注意,是器件地址,不是像EEPROM那样的EEPROM地址,这个地址是当数据发的)时会不设置I2C_M_NOSTART, 发数据时就设置I2C_M_NOSTART这个标志。
I2C_M_NO_RD_ACK:
这个标识表示在正行读操作时不去ACK,我不知道其它芯片如果,如果是AT24C04则一定不能设这个标志位了。
(下面三个标志为均为bit_doAddress函数使用,结合上面的说明,也就是这时I2C_M_NOSTART一定没有设置。)
I2C_M_RD:
表示这是一个读操作,默认是把相应的位置1
I2C_M_REV_DIR_ADDR:
表示把读写标志位反转,也就是读是把相应位置0
I2C_M_TEN:
表示这个器件的器件地址是10Bit的。一定要搞清,这是器件地址,不是指EEPROM的ROM地址。24C02等芯片真正的器件地址只有4位永远有效(0xA),低4位用来放其它东西了(根据容量有可能是器件地址的低3位,或ROM地址的高3位)。也是说,无论什么容量,这类器件的地址只是器件地址我们只选7位模式(内核只区分10位模式和其它模式)