【IMX6ULL驱动开发学习】09.Linux之I2C驱动框架简介和驱动程序模板( 三 )


一般需要在probe函数里面初始化 I2C 设备,要初始化 I2C 设备需要使用函数对 I2C 设备寄存器进行读写操作 。函数会调用 I2C 适配器中 里面的函数,对于 I.MX6U 而言是这个函数 。
int i2c_transfer(struct i2c_adapter *adap,struct i2c_msg *msgs,int num)
adap: 所使用的 I2C 适配器,会保存其对应的
msgs: I2C 要发送的一个或多个消息
num: 消息数量,msgs 的数量

【IMX6ULL驱动开发学习】09.Linux之I2C驱动框架简介和驱动程序模板

文章插图
返回值: 负值,失败,其他非负值,发送的 msgs 数量
msgs参数是一个类型的指针参数,Linux内核使用 结构体描述一个消息 。
struct i2c_msg {__u16 addr; /* 从机地址 */__u16 flags; /* 标志 */#define I2C_M_TEN 0x0010#define I2C_M_RD 0x0001#define I2C_M_STOP 0x8000#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#define I2C_M_RECV_LEN 0x0400__u16 len; /* 消息(本 msg)长度 */__u8 *buf; /* 消息数据 */};
使用函数发送数据前,要构建好 ,使用进行 I2C 数据收发的模板:
/* 设备结构体 */struct xxx_dev {......void *private_data; /* 私有数据,一般会设置为 i2c_client */};/** @description : 读取 I2C 设备多个寄存器数据* @param – dev : I2C 设备* @param – reg : 要读取的寄存器首地址* @param – val : 读取到的数据* @param – len : 要读取的数据长度* @return : 操作结果*/static int xxx_read_regs(struct xxx_dev *dev, u8 reg, void *val,int len){int ret;struct i2c_msg msg[2];struct i2c_client *client = (struct i2c_client *)dev->private_data;/* msg[0],第一条写消息,发送要读取的寄存器首地址 */msg[0].addr = client->addr; /* I2C 器件地址 */msg[0].flags = 0; /* 标记为发送数据 */msg[0].buf = ® /* 读取的首地址 */msg[0].len = 1; /* reg 长度 *//* msg[1],第二条读消息,读取寄存器数据 */msg[1].addr = client->addr; /* I2C 器件地址 */msg[1].flags = I2C_M_RD; /* 标记为读取数据 */msg[1].buf = val; /* 读取数据缓冲区 */msg[1].len = len; /* 要读取的数据长度 */ret = i2c_transfer(client->adapter, msg, 2);if(ret == 2) {ret = 0;} else {ret = -EREMOTEIO;}return ret;}/** @description : 向 I2C 设备多个寄存器写入数据* @param – dev : 要写入的设备结构体* @param – reg : 要写入的寄存器首地址* @param – buf : 要写入的数据缓冲区* @param – len : 要写入的数据长度* @return : 操作结果*/static s32 xxx_write_regs(struct xxx_dev *dev, u8 reg, u8 *buf,u8 len){u8 b[256];struct i2c_msg msg;struct i2c_client *client = (struct i2c_client *)dev->private_data;b[0] = reg; /* 寄存器首地址 */memcpy(&b[1],buf,len); /* 将要发送的数据拷贝到数组 b 里面 */msg.addr = client->addr; /* I2C 器件地址 */msg.flags = 0; /* 标记为写数据 */msg.buf = b; /* 要发送的数据缓冲区 */msg.len = len + 1; /* 要发送的数据长度 */return i2c_transfer(client->adapter, &msg, 1);}
在设备结构体里面添加一个执行void的指针成员变量,此成员变量用于保存设备的私有数据,在 I2C 设备驱动中一般将其指向 I2C 设备对应的 。
函数用于读取 I2C 设备多个寄存器数据,然后定义了一个 数组,2 个数组元素 。如图,I2C写时序图,因为 I2C 读取数据的时候要先发送要读取的寄存器地址,然后再读取数据,所以需要准备两个。一个用于发送寄存器地址,一个用于读取寄存器值 。
对于 msg[0],将 flags设置为 0,表示写数据 。msg[0]的 addr 是 I2C 设备的器件地址,msg[0]的 buf 成员变量就是要读取的寄存器地址 。对于 msg[1],将 flags 设置为 ,表示读取数据 。msg[1]的 buf 成员变量用于保存读取到的数据,len 成员变量就是要读取的数据长度 。调用函数完成 I2C 数据读操作 。