目录
1. I2C驱动层次结构图
2. struct i2c_driver结构体
3. struct i2c_client结构体
3. 数据收发相关函数
4. I2c应用层驱动
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;
}