linux的I2C设备驱动采用的设备-总线-驱动模型
内核维护I2C虚拟总线i2c_bus_type,在这个总线上维护着两个链表:dev链表(struct i2c_client)和drv链表(struct i2c_driver),前者每一个节点存放的硬件相关的信息,后者
每一个节点存放的是驱动信息。
驱动开发步骤:
1.在平台代码中添加i2c_board_info:(例如:arch/arm/mach-s5pv210/mach-cw210.c)
struct i2c_board_info {
char type[I2C_NAME_SIZE]; //最终赋值给i2c_client.name,也就是名字,用来匹配
unsigned short flags;
unsigned short addr; //设备地址,最终赋值给i2c_client.addr
void *platform_data; //硬件私有的信息
struct dev_archdata *archdata;
#ifdef CONFIG_OF
struct device_node *of_node;
#endif
int irq; //中断号,最终赋值给i2c_client.irq
};
2.在平台代码的模块init函数中注册i2c_board_info:
int i2c_register_board_info(int busnum,struct i2c_board_info const *info, unsigned len)
busnum:总线编号,从原理图可知
info:初始化好的i2c设备结构体
len:硬件信息的个数
3.在驱动代码中,初始化i2c_driver结构体:
#include <linux/i2c.h>
struct i2c_driver {
int (*probe)(struct i2c_client *, const struct i2c_device_id *); //匹配成功后第一个调用的函数
int (*remove)(struct i2c_client *);
...
struct device_driver driver;
const struct i2c_device_id *id_table; //其中的name变量用来匹配(重要)
...
};
注释:
probe函数根据传入的i2c_client结构体获得对应硬件信息,对硬件进行操作。
可在probe函数中注册字符设备,创建设备结点,为用户fops。
内核提供对i2c设备访问的接口:
s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)
s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command)
4.在模块init函数中注册i2c_driver:
int i2c_add_driver(struct i2c_driver *driver)
字符设备访问的函数:
i2c_smbus_read_byte_data等
参看内核源码Documentation\i2c\smbus-protocol,有相关的时序,同时需要参看硬件手册