目录

I2C主机控制器驱动(adapter):一般由SOC厂家负责设计实现,用于控制I2C主机控制器发出时序信号;
I2C Core:为上层提供统一的API接口和对其他模块进行注册和注销管理等;
I2C设备驱动(Client):调用I2C Core提供的统一API,根据I2C设备的访问规范,控制I2C控制器发出不同的时序信号,对I2C设备进行访问;该驱动称为内核层I2C设备驱动;
i2c-dev:将I2C主机控制器实现为一个字符设备,应用程序可直接通过访问/dev/i2c-N来访问I2C主机控制器,从而对I2C设备发起访问; 称为应用层I2C设备驱动;
该结构体用于表示i2c设备驱动;
- struct i2c_driver {
- //我们实例化什么样的i2c设备
- unsigned int class;
-
- //总线添加和移除时回调函数
- int (*attach_adapter)(struct i2c_adapter *) __deprecated;
- int (*detach_adapter)(struct i2c_adapter *) __deprecated;
-
- //设备绑定和解绑回调函数
- 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 *);
-
- //警报回调,例如SMBus警报协议
- void (*alert)(struct i2c_client *, unsigned int data);
-
- //总线信号回调
- int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
-
- //设备驱动模型驱动
- struct device_driver driver;
- //此驱动程序支持的I2C设备列表
- const struct i2c_device_id *id_table;
-
- /* Device detection callback for automatic device creation */
- int (*detect)(struct i2c_client *, struct i2c_board_info *);
- const unsigned short *address_list;
- struct list_head clients;
- };
常用的API:
//添加i2c设备驱动
int i2c_register_driver(struct module *, struct i2c_driver *);
或
#define i2c_add_driver(driver) \
i2c_register_driver(THIS_MODULE, driver)//删除i2c设备驱动
void i2c_del_driver(struct i2c_driver *);
可用宏简写上述两API;参数为已填充好的struct i2c_driver变量;
#define module_i2c_driver(__i2c_driver) \
module_driver(__i2c_driver, i2c_add_driver, \
i2c_del_driver)
示例:
- static struct i2c_driver ltc4151_driver = {
- .driver = {
- .name = "ltc4151",
- },
- .probe = ltc4151_probe,
- .remove = ltc4151_remove,
- .id_table = ltc4151_id,
- };
-
- module_i2c_driver(ltc4151_driver);
该结构体用于表示i2c从设备;
- struct i2c_client {
- unsigned short flags;
- /*
- #define I2C_CLIENT_PEC 0x04 //用于包错误检查
- #define I2C_CLIENT_TEN 0x10 //十位的芯片地址
- #define I2C_CLIENT_WAKE 0x80 //for board_info; true iff can wake
- */
-
- //连接到父适配器的I2C总线上使用的地址。
- unsigned short addr;
-
- //指示设备的类型,通常是一个通用的芯片名称,足以隐藏第二来源和兼容版本
- char name[I2C_NAME_SIZE];
-
- //适配器
- struct i2c_adapter *adapter;
- //设备驱动
- struct i2c_driver *driver;
- //设备
- struct device dev;
- //指示此设备生成的IRQ
- int irq;
- struct list_head detected;
- };
常用 API:
void *i2c_get_clientdata(const struct i2c_client *dev);
void i2c_set_clientdata(struct i2c_client *dev, void *data)
//作用:向I2c从设备写数据;
//I2c设备的地址包含在client中,要写的数据为buf,写的字节数为count;
int i2c_master_send(const struct i2c_client *client, const char *buf, int count);
//作用:向I2c从设备读数据; 参数同上;
int i2c_master_recv(const struct i2c_client *client, char *buf,int count);
将几个读写操作合并在一起执行的函数;
/*
adap:执行写操作的I2c主机控制器;
msgs:消息数组;
num:消息的数量;
*/
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
struct 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 */
- #define I2C_M_16BIT_REG 0x0002 /* indicate reg bit-width is 16bit */
- #define I2C_M_16BIT_DATA 0x0008 /* indicate data bit-width is 16bit */
-
- __u16 len; /* msg length 消息长度 */
- __u8 *buf; /* pointer to msg data 指向消息数据的指针 */
- };
内核驱动框架
-
- //用于设备树匹配
- const struct of_device_id of_mpu6050_id[] = {
- {
- .compatible = "mpu6050, 0",
- },
- {},
- };
-
-
- static struct i2c_driver mpu6050_drv = {
- .probe = mpu6050_drv_probe,
- .remove= mpu6050_drv_remove,
- .driver = {
- .name = "mpu6050",//随便写,出现在/sys/bus/i2c/driver/ 下
- .of_match_table = of_match_ptr(of_mpu6050_id),
- },
-
- .id_table = mpu6050_id_table,
- };
-
- #if 0
- static int __init mpu6050_drv_init(void)
- {
- return i2c_add_driver(&mpu6050_drv);
- }
-
- static void __exit mpu6050_drv_exit(void)
- {
- i2c_del_driver(&mpu6050_drv);
- }
-
- module_init(mpu6050_drv_init);
- moudle_exit(mpu6050_drv_exit);
- #else
- mpdule_i2c_driver(mpu6050_drv);
- #endif
- MODULE_LICENSE("GPL");
内核需要配置:
Device Drivers -->
-*- I2C support -->
<*> I2C device interface
应用层驱动主要调用所对应的Linux驱动为drivers/i2c/i2c-dev.c中;
应用层流程:
- {
- int ret = -1;
- struct i2c_msg msg[2];
- unsigned char buf[4] = {0};
- struct i2c_rdwr_ioctl_data rdwr = {0};
- unsigned int data;
-
- int fd = open(I2C_NAME,O_RDWR);
- if(0 > fd){
- printf("open %s failed\n",I2C_NAME);
- goto ERR0;
- }
-
- ret = ioctl(fd, I2C_SLAVE_FORCE, DEV_READ_ADDR);
- if(0 > ret){
- printf("ioctl I2C_SLAVE_FORCE 0x%x failed\n",DEV_READ_ADDR);
- goto ERR1;
- }
-
- msg[0].addr = DEV_READ_ADDR;
- msg[0].flags = 0;
- msg[0].len = 0x1;
- msg[0].buf = buf;
-
- msg[1].addr = DEV_READ_ADDR;
- msg[1].flags = 0;
- msg[1].flags |= I2C_M_RD;
- msg[1].len = 0x1;
- msg[1].buf = buf;
-
- rdwr.msgs = &msg[0];
- rdwr.nmsgs = (__u32)2;
-
- buf[0] = reg_addr & 0xff;
-
- ret = ioctl(fd, I2C_RDWR, &rdwr);
- if(0 > ret){
- printf("ioctl I2C_RDWR failed\n");
- goto ERR1;
- }
-
- data = buf[0];
-
- printf("0x%x: 0x%x\n", reg_addr, data);
-
- ERR1:
- close(fd);
- ERR0:
- return ret;
- }