6.Linux驱动-I2C读写函数

0.前言

本文不涉及原理,只涉及如何使用

1.I2C_SMBUS

1.i2c_smbus的常用的函数集有:

s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command);
s32 i2c_smbus_write_byte_data(const struct i2c_client *client,u8 command, u8 value);

s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command);
s32 i2c_smbus_write_word_data(const struct i2c_client *client,u8 command, u16 value);

s32 i2c_smbus_read_block_data(const struct i2c_client *client,u8 command, u8 *values);
s32 i2c_smbus_write_block_data(const struct i2c_client *client,u8 command, u8 length, const u8 *values);

s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client,u8 command, u8 length, u8 *values);
s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client,u8 command, u8 length, const u8 *values);

2.向I2C设备中读出或者写入一个字节(8位)/两个字节(16位)的数据

/* client:client是指i2c slave 设备,使用时有时需要初始化其i2c地址
*  command :读写的寄存器地址
*  value:写入的数据,为8位
*/
s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command);
s32 i2c_smbus_write_byte_data(const struct i2c_client *client,u8 command, u8 value);

s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command);
/*value:写入的数据,为16位*/
s32 i2c_smbus_write_word_data(const struct i2c_client *client,u8 command, u16 value);

举例:读取slave地址为0x36的reg寄存器的8位值,向reg寄存器写入值0x10,16位的类似

pdata->client->addr = 0x36 ;
i2c_smbus_read_byte_data(pdata->client, reg);
i2c_smbus_write_byte_data(padta->client,reg,0x10);

3.读取或者写入指定长度的值,一般使用后面两个

/* client:client是指i2c slave 设备,使用时有时需要初始化其i2c地址
*  command :读写的寄存器地址
*  length  :读取或者写入长度
*  value   :写入的数据,值的类型为u8
*/
s32 i2c_smbus_read_block_data(const struct i2c_client *client,u8 command, u8 *values);
s32 i2c_smbus_write_block_data(const struct i2c_client *client,u8 command, u8 length, const u8 *values);

s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client,u8 command, u8 length, u8 *values);
s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client,u8 command, u8 length, const u8 *values);

举例:

/* 其中client中会保存slave的I2C地址
 * 0x03为寄存器地址
 * write_buf是一个u8类型的数组
 * 4为长度
*/
static int write_reg(struct i2c_client *client, int addr,u8* data, int len)
{
    
    
	return  i2c_smbus_write_i2c_block_data(client,addr,len,data);
}

void func()
{
    
    
    u8 write_buf[4];
	write_buf[0]=0x01;
	write_buf[1]=0x02;
	write_buf[2]=0x05;
	write_buf[3]=0x04
	write_reg(client,0x03,write_buf,4);
}

/* client中保存slave的I2C地址
*  0x20为寄存器地址
*  read_buf是一个u8类型的数组
*  63为读取的长度
*/
static int read_register(struct i2c_client *client, int addr,u8* u8_val, int len)
{
    
    
	return i2c_smbus_read_i2c_block_data(client,addr,len,u8_val);
}
void func()
{
    
    
	u8 read_buf[80];
	read_register(client, 0x20, read_buf ,80);
}

2.i2c_master_send ()和 i2c_master_recv()

在设备驱动中通常调用 i2c-core 定义的接口 i2c_master_send() 和 i2c_master_recv() 来发送或接收一次数据。

/*
* client:I2C从机
* buf   :要发送的buf指针
* count :发送的数据长度
*/
int i2c_master_send(struct i2c_client *client,const char *buf ,int count) 
{
    
     
    int ret; 
    struct i2c_adapter *adap=client->adapter;  // 获取adapter信息 
    struct i2c_msg msg;                        // 定义一个临时的数据包 
 
    msg.addr = client->addr;                   // 将从机地址写入数据包 
    msg.flags = client->flags & I2C_M_TEN;     // 将从机标志并入数据包 
    msg.len = count;                           // 将此次发送的数据字节数写入数据包 
    msg.buf = (char *)buf;                     // 将发送数据指针写入数据包 
 
    ret = i2c_transfer(adap, &msg, 1);         // 调用平台接口发送数据 
 
    // If everything went ok (eg: 1 msg transmitted), return bytes number transmitted, else error code. 
    return (ret == 1) ? count : ret;           // 如果发送成功就返回字节数 
} 
EXPORT_SYMBOL(i2c_master_send); 

/*
* client:I2C从机
* buf   :要接收的buf指针
* count :发送的数据长度
*/
int i2c_master_recv(struct i2c_client *client, char *buf ,int count) 
{
    
     
    struct i2c_adapter *adap=client->adapter;  // 获取adapter信息 
    struct i2c_msg msg;                        // 定义一个临时的数据包 
    int ret; 
 
    msg.addr = client->addr;                   // 将从机地址写入数据包 
    msg.flags = client->flags & I2C_M_TEN;     // 将从机标志并入数据包 
    msg.flags |= I2C_M_RD;                     // 将此次通信的标志并入数据包 
    msg.len = count;                           // 将此次接收的数据字节数写入数据包 
    msg.buf = buf; 
 
    ret = i2c_transfer(adap, &msg, 1);         // 调用平台接口接收数据 
 
    /* If everything went ok , return number of bytes transmitted, else error code. */ 
    return (ret == 1) ? count : ret;           // 如果接收成功就返回字节数 
} 
EXPORT_SYMBOL(i2c_master_recv); 

1.举例:

写寄存器

//写8位寄存器
static inline int xxx_reg_write(struct data *pdata,int index,unsigned char reg, unsigned char val)
{
    
    
	unsigned char u8_buf[2] = {
    
     0 };
	unsigned int buf_len = 2;
	int retry, timeout = 5;

	u8_buf[0] = reg;
	u8_buf[1] = val; 
    
	pdata->client->addr = ADDR + index;
	for (retry = 0; retry < timeout; retry++) 
    {
    
    
		if (i2c_master_send(pdata->client, u8_buf, buf_len) < 0) 
        {
    
    
			printk("%s:write reg error: reg=0x%x, val=0x%x, retry = %d.\n", __func__, reg, val, retry);
			msleep(5);
			continue;
		}
		else
        {
    
          
			printk("%s:write reg ok: reg=0x%x, val=0x%x, retry = %d.\n", __func__, reg, val, retry);
            break;
        }
	}
	return 0;
}

//写16位寄存器
static inline int xxx_reg_write(struct data *pdata,int index,unsigned short reg, unsigned char val)
{
    
    
	unsigned char u8_buf[3] = {
    
     0 };
	unsigned int buf_len = 3;
	int retry, timeout = 5;

	u8_buf[0] = (reg >> 8) & 0xFF;//寄存器地址高位
	u8_buf[1] = reg & 0xFF;  //寄存器地址低位
	u8_buf[2] = val; //要发送的数据

	pdata->client->addr = ADDR + index;
	for (retry = 0; retry < timeout; retry++) 
    {
    
    
		if (i2c_master_send(pdata->client, u8_buf, buf_len) < 0) 
        {
    
    
			printk("%s:write reg error: reg=0x%x, val=0x%x, retry = %d.\n", __func__, reg, val, retry);
			msleep(5);
			continue;
		}
		else
        {
    
          
			printk("%s:write reg ok: reg=0x%x, val=0x%x, retry = %d.\n", __func__, reg, val, retry);
            break;
        }
	}
	return 0;
}

读:

//8位读
static inline int xxx_reg_read(struct data *pdata, int index, unsigned short reg)
{
    
    
	unsigned char u8_buf[2] = {
    
     0 };
	unsigned int buf_len = 1;
	int retry, timeout = 5;
	unsigned char u8_val = 0;

	u8_buf[0] = reg;


	pdata->client->addr = ADDR + index;
	for (retry = 0; retry < timeout; retry++) 
    {
    
    
		if (i2c_master_send(pdata->client, u8_buf, buf_len) < 0) 
        {
    
    
			printk("%s:read reg error on send: reg=0x%x, retry = %d.\n", __func__, reg, retry);
			msleep(5);
			continue;
		}
		if (i2c_master_recv(pdata->client, &u8_val, 1) != 1) {
    
    
			printk("%s:read reg error on recv: reg=0x%x, retry = %d.\n", __func__, reg, retry);
			msleep(5);
			continue;
		}
		break;
	}

	if (retry >= timeout) {
    
    
		printk("%s:read reg error: reg=0x%x.\n", __func__, reg);
		return -1;
	}

	return u8_val;
}

//16位读
static inline int xxx_reg_read(struct data *pdata, int index, unsigned short reg)
{
    
    
	unsigned char u8_buf[2] = {
    
     0 };
	unsigned int buf_len = 2;
	int retry, timeout = 5;
	unsigned char u8_val = 0;

	u8_buf[0] = (reg >> 8) & 0xFF;//寄存器地址高位
	u8_buf[1] = reg & 0xFF;//寄存器地址低位

	pdata->client->addr = ADDR + index;
	for (retry = 0; retry < timeout; retry++) 
    {
    
    
		if (i2c_master_send(pdata->client, u8_buf, buf_len) < 0) 
        {
    
    
			printk("%s:read reg error on send: reg=0x%x, retry = %d.\n", __func__, reg, retry);
			msleep(5);
			continue;
		}
		if (i2c_master_recv(pdata->client, &u8_val, 1) != 1) {
    
    
			printk("%s:read reg error on recv: reg=0x%x, retry = %d.\n", __func__, reg, retry);
			msleep(5);
			continue;
		}
		break;
	}

	if (retry >= timeout) {
    
    
		printk("%s:read reg error: reg=0x%x.\n", __func__, reg);
		return -1;
	}

	return u8_val;
}

3.i2c_transfer 接口

8位读

static int xxx_read_regs(struct i2c_client *client, u8 addr,u8 reg, void *val,int len)
 {
    
    
	int ret;
	struct i2c_msg msg[2];

	/* msg[0],第一条写消息,发送要读取的寄存器首地址 */
	msg[0].addr = addr; /* I2C 器件地址 */
	msg[0].flags = 0; /* 标记为发送数据 */
	msg[0].buf = &reg; /* 读取的首地址 */
	msg[0].len = 1; /* reg 长度 */

	/* msg[1],第二条读消息,读取寄存器数据 */
	msg[1].addr = 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;
 }

16位寄存器,地址可能不是这种格式,需要自己构造

static i2c_read_16bit (struct i2c_client *client, u8 slave_addr, const u16 *reg_addr)
{
    
    
	int value = 0;
	struct i2c_msg msgs[2];
	int rc = 0;
	memset(msgs, 0, sizeof(msgs));

	if (!client) {
    
    
		pr_err("%s: Invalid params\n", __func__);
		return -EINVAL;
	}

	msgs[0].addr = slave_addr; /*I2C器件地址*/
	msgs[0].len  = 2;          //寄存器的地址长度
	msgs[0].buf  = (void *)reg_addr;//寄存器地址,比如0x0010
	
    msgs[1].addr = slave_addr;
	msgs[1].flags |= I2C_M_RD;
	msgs[1].len    = 1;
	msgs[1].buf    = (void *)&value;

	rc = i2c_transfer(client->adapter, msgs, 2);
	if (rc != 2) {
    
    
		printk(KERN_ERR "HDMI : %s: i2c_transfer adapter[%s] i2c read addr[0x%02x] failed(%d)\n", __func__,
			client->adapter->name, slave_addr,rc);
		return rc;
	}
	
	return value;
}

或者:
static int i2c_read_16bit(struct i2c_client *client,
				   u16 reg, u16 len, void *val)
{
    
    
	struct i2c_msg msg[2];
	u8 buf[2];
	int ret;

	buf[0] = (reg >> 8) & 0xff;
	buf[1] = reg & 0xff;

	/* Write register */
	msg[0].addr = client->addr;
	msg[0].flags = 0;
	msg[0].len = 2;
	msg[0].buf = buf;

	/* Read data */
	msg[1].addr = client->addr;
	msg[1].flags = I2C_M_RD;
	msg[1].len = len;
	msg[1].buf = val;

	ret = i2c_transfer(client->adapter, msg, 2);
	if (ret == 2) {
    
    
		ret = 0;
	} else {
    
    
		if (ret >= 0)
			ret = -EIO;
		dev_err(&client->dev, "%s: i2c transfer failed (%d)\n",
			__func__, ret);
	}

	return ret;
}

8位写:

static s32 xxx_write_regs(struct i2c_client *client, u8 reg, u8 data,u8 len)
 {
    
    
	u8 b[2];
	struct i2c_msg msg;

	b[0] = reg; /* 寄存器首地址 */
	b[1] = data; /* 将要发送的数据拷贝到数组 b 里面 */

	msg.addr = addr; /* I2C 器件地址 */
	msg.flags = 0; /* 标记为写数据 */
	msg.buf = (char *)b; /* 要发送的数据缓冲区 */
	msg.len = 2//len + 1; /* 要发送的数据长度 */

	return i2c_transfer(client->adapter, &msg, 1);
 }

16位写:

static int i2c_write_16bit (struct i2c_client *client, unsigned char slave_addr, u16 reg,u8 data)
{
    
    
	struct i2c_msg msgs[1];
    u8 b[3];
    
	int rc = 0;
	memset(msgs, 0, sizeof(msgs));

	if (!client) {
    
    
		pr_err("%s: Invalid params\n", __func__);
		return -EINVAL;
	}
	
    b[0] =(reg >> 8) & 0xff; /* 寄存器首地址 */
    b[1] = reg & 0xff;
	b[2] = data; /* 将要发送的数据拷贝到数组 b 里面 */

	msgs[0].addr = slave_addr;
	//msgs[0].buf = (void *)Pcmd;
    msgs[0].buf = (void *)b;
    msgs[0].len = 3;//len = 数据长度(1)+寄存器地址长度(2)

	rc = i2c_transfer(client->adapter, msgs, 1);
	if (rc != 1) {
    
    
		pr_err("HDMI : %s: adapter[%s] i2c write addr[0x%02x] failed(%d)\n", __func__,
			client->adapter->name, slave_addr,rc);
		return rc;
	}
	return rc;
}
--------------------------------------------------------------------------------------------------------------------------------

或者:
struct cmd_16bit{
    
    
	u16 reg_addr;
	u8 reg_value;
};

#define HL_TO_LH(addr16bit) 	((addr16bit&0xff00)>>8 | (addr16bit&0xff)<<8)

static const struct cmd_16bit reg02[] = {
    
    
	{
    
    HL_TO_LH(0x02),0x63},
};

调用:
i2c_write_16bit(client, slave_addr, &reg02[0]);

static int i2c_write_16bit (struct i2c_client *client, unsigned char slave_addr, const struct cmd_16bit *Pcmd)
{
    
    
	struct i2c_msg msgs[1];
	int rc = 0;
	memset(msgs, 0, sizeof(msgs));

	if (!client) {
    
    
		pr_err("HDMI: %s: Invalid params\n", __func__);
		return -EINVAL;
	}

	msgs[0].addr = slave_addr;
	msgs[0].len = 3;
	msgs[0].buf = (void *)Pcmd;

	rc = i2c_transfer(client->adapter, msgs, 1);
	if (rc != 1) {
    
    
		pr_err("HDMI : %s: adapter[%s] i2c write addr[0x%02x] failed(%d)\n", __func__,
			client->adapter->name, slave_addr,rc);
		return rc;
	}
	return rc;
}

猜你喜欢

转载自blog.csdn.net/weixin_43824344/article/details/120168578