海思I2C总线操作
1.使用I2C命令:
i2c_write <i2c_num> <device_addr> <reg_addr> <value> <reg_width> <data_width>
i2c_read <i2c_num> <device_addr> <reg_addr> <end_reg_addr>
<reg_width> <data_width> <reg_step>

实例:
i2c_write 2 0x56 0xff 0x80 0x1 0x1   	I2C写命令, 往总线2,地址为0x56的设备的寄存器
0xff里面写0x80, 寄存器位宽为1byte,数据位宽也为1byte

i2c_read  2 0x57 0x0  0x1  0x1 0x1		I2C读命令,从总线2,地址为0x56(读地址是写地址
+1),从这个设备0 1, 也就是读了0x0寄存器和0x1寄存器,读了两个寄存器。寄存器位宽为1byte,数据位宽也为1byte
reg_step:连续读外围设备寄存器操作时递增幅值, 默认为 1

2.关于I2C总线上面检测设备和查看设备的寄存器:
./i2cdetect -y -r 2   检测i2c总线2上面有哪些设备(海思的这个工具好像读取的地址不准)
./i2cdump -f -y 2 0x56  查看总线2,设备地址0x56上的设备的I2C寄存器的值
./i2cset -f -y 2 0x56 0x23 5 总线2,设备地址为0x56的设备,设置寄存器0x23的值为0x5
./i2cget -f -y 2 0x56 0x0  总线2,设备地址为0x56的设备,读取寄存器0x0的值

3.内核态 I2C 读写程序示例:
//I2C 外围设备信息列表
static struct i2c_board_info hi_info = {
//一项 I2C_BOARD_INFO 代表一个支持的 I2C 外围设备, 它的名字叫做"hi_test”, 设备地址是 0x72
I2C_BOARD_INFO("hi_test", 0x39),
};

step1: 调用 I2C 核心层的函数, 获得描述一个 I2C 控制器的结构体 i2c_adap
struct i2c_adapter * i2c_adap = i2c_get_adapter(0);

step2:
struct i2c_client * client = i2c_new_device(i2c_adap, &hi_info);
在exit函数中,要记得使用如下的函数进行注销:
i2c_unregister_device(&hi_info);

step3:
在非中断上下文中, 调用 I2C 核心层提供的标准读写函数对外围器件进行读写
ret = i2c_master_send(client, buf, count);  写函数
ret = i2c_transfer(client->adapter, msg, 2); 读函数
在中断上下文中, 调用 I2C 驱动层的读写函数对外围器件进行读写
ret = hi_i2c_master_send(client, buf, count);  写函数
ret = hi_i2c_transfer (client->adapter, msg, 2);  读函数

参数 client 为步骤 2 得到的描述 I2C 外围设备的客户端结构体 client。
参数 buf 为需要读写的寄存器和数据。
参数 count 为 buf 的长度。
参数 msg 为读操作时的两个 i2c_msg 的首地址。

//data 代表数据首地址,size代表数据长度
int hi_i2c_write(uint8_t addr, uint8_t reg, uint8_t size, uint8_t *data)
{
    int ret;
    struct i2c_client * client = step2中获得的client;
    uint8_t * write_buf = kmalloc(size + 1, GFP_KERNEL); // +1 代表的是reg
    memset(write_buf, 0, size + 1);
    write_buf[0] = reg; //第一个字节是reg
    memcpy(&write_buf[1], data, size);  //后面的是数据的长度
	
	//在非中断上下文中, 调用内核提供的 I2C 标准写函数进行写操作
    ret = i2c_master_send(client, write_buf, size + 1);
	//在中断上下文中, 调用驱动层提供的写函数进行写操作
	ret = hi_i2c_master_send(client, write_buf, size + 1);
	
    kfree(write_buf);

    return ret;
}

int hi_i2c_read(uint8_t addr, uint8_t reg, uint8_t size, uint8_t *data)
{
    int ret;
    struct i2c_msg msg[2];
    struct i2c_client *client = step2中获得的client;
	
	memset(msg, 0x0, sizeof(struct i2c_msg) * 2);
    msg[0].addr = client->addr;
    msg[0].flags = client->flags;
    msg[0].len = 1;
    msg[0].buf = ®
    msg[1].addr = client->addr;
    msg[1].flags = I2C_M_RD;
    msg[1].len = size;
    msg[1].buf = data;
	
	//在非中断上下文中, 需要调内核提供的 i2c_transfer 传两个 msg 进行先写后读
    ret = i2c_transfer(client->adapter, msg, 2);
	//在中断上下文中, 需要调内核提供的 hi_i2c_transfer 传两个 msg 进行先写后读
	ret = hi_i2c_transfer(client->adapter, msg, 2);

    return ret;
}

static int hi_dev_init(void)
{ 
	//分配一个I2C控制器指针
	struct i2c_adapter *i2c_adap;
	//调用core层的函数, 获得描述一个I2C控制器的结构体i2c_adap。 假设我们已经知道新增的外
	围设备挂载在编号为I2C控制器2上
	i2c_adap = i2c_get_adapter(2);
	//把I2C控制器和新增的I2C外围设备关联起来, I2C外围设备挂载在I2C控制器2, 地址是0x72,
	就组成了一个客户端hi_client。
	hi_client = i2c_new_device(i2c_adap, &hi_info);
	i2c_put_adapter(i2c_adap);
	return 0;
}
 
static void hi_dev_exit(void)
{
	i2c_unregister_device(hi_client);
}

i2c_msg一些标志的解释:来源:http://blog.chinaunix.net/uid-31087949-id-5752092.html
I2C_M_IGNORE_NAK:
      设置这个标志意味当前i2c_msg忽略I2C器件的ack和nack信号。
I2C_M_NOSTART:      
      设置这个标志意味当前i2c_msg不发送start信号。注意,其实调用bit_xfer的一开始就已经发了start信号了(程序第10 行),这个标记无非就是标志是否发送地址第18行。其次,如果一个i2c_msg没有定义I2C_M_NOSTART而且又不是msgs序列里的第一个 i2c_msg,则回发送重复start信号,我想这就是这个标志起这个名的原因。我们可以猜想,
      1.msgs序列第一个数据必须是地址,同时必须不定义这个标志位
      2.在进行读数据,要从写操作转变为读操作时,会发重复start信号和器件地址时,必须不定义这个标志位
      3.其它情况下一的i2c_msg必须定义这个标志
      以上只是我看完这个函数的理解,不一定正确。同时1和2总结下来就是发器件地址(注意,是器件地址,不是像EEPROM那样的EEPROM地 址,这个地址是当数据发的)时会不设置I2C_M_NOSTART, 发数据时就设置I2C_M_NOSTART这个标志。
I2C_M_NO_RD_ACK:
      这个标识表示在正行读操作时不去ACK,我不知道其它芯片如果,如果是AT24C04则一定不能设这个标志位了。
(下面三个标志为均为bit_doAddress函数使用,结合上面的说明,也就是这时I2C_M_NOSTART一定没有设置。)
I2C_M_RD:
      表示这是一个读操作,默认是把相应的位置1
I2C_M_REV_DIR_ADDR:
      表示把读写标志位反转,也就是读是把相应位置0
I2C_M_TEN:
     表示这个器件的器件地址是10Bit的。一定要搞清,这是器件地址。一般有10bit和7bit

4.用户态 I2C 读写程序示例
step1: 打开 I2C 总线对应的设备文件, 获取文件描述符
		fd = open("/dev/i2c-0", O_RDWR);
step2: 进行数据读写
		write(fd, buf, (reg_width + data_width));

用户态I2C读写函数实现:		
int i2c_write(int fd, unsigned int dev, unsigned int reg_addr,
              unsigned int data, unsigned int reg_width,
              unsigned int data_width)
{
    int retval = 0;
    unsigned char buf[4];
    int index = 0;

    unsigned int dev_addr = dev >> 1;

    retval = ioctl(fd, I2C_SLAVE_FORCE, dev_addr);
    if(retval < 0) {
        printf("address error!\n");
        retval = -1;
        goto exit;
    }

    if (reg_width == 2) {
        buf[index] = (reg_addr >> 8) & 0xff;
        index++;
        buf[index] = reg_addr & 0xff;
        index++;
    } else {
        buf[index] = reg_addr & 0xff;
        index++;
    }

    if (data_width == 2) {
        buf[index] = (data >> 8) & 0xff;
        index++;
        buf[index] = data & 0xff;
        index++;
    } else {
        buf[index] = data & 0xff;
        index++;
    }

    retval = write(fd, buf, (reg_width + data_width));
    if(retval < 0) {
        printf("i2c write fail!\n");
        retval = -1;
        goto exit;
    }

    retval = 0;

exit:
    return retval;


}

int i2c_read(int fd, unsigned int dev, unsigned int reg_addr, unsigned int reg_width, unsigned int data_width, unsigned char *val)
{
    int retval;
    unsigned char buf[4];
    static struct i2c_rdwr_ioctl_data rdwr;
    static struct i2c_msg msg[2];
    unsigned int data;

    unsigned int dev_addr = dev >> 1;

    retval = ioctl(fd, I2C_SLAVE_FORCE, dev_addr);
    if (retval < 0) {
        printf("addr error!\n");
        return -1;
    }

    msg[0].addr = dev_addr;
    msg[0].flags = 0;
    msg[0].len = reg_width;
    msg[0].buf = buf;

    msg[1].addr = dev_addr;
    msg[1].flags = 0;
    msg[1].flags |= I2C_M_RD;
    msg[1].len = data_width;
    msg[1].buf = buf;

    rdwr.msgs = &msg[0];
    rdwr.nmsgs = (__u32)2;
//	for (cur_addr = reg_addr; cur_addr <= reg_addr_end; cur_addr +=
//			reg_step)  我们如果不用step的话,这个for循环就不必了
    {
        if (reg_width == 2) {
            buf[0] = (reg_addr >> 8) & 0xff;
            buf[1] = reg_addr & 0xff;
        } else {
            buf[0] = reg_addr & 0xff;
        }

        retval = ioctl(fd, I2C_RDWR, &rdwr);
        if (retval != 2) {
            printf("CMD_I2C_READ error!\n");
            return -1;
        }

        if (data_width == 2) {
            data = buf[1] | (buf[0] << 8);
        } else {
            data = buf[0];
        }
    }

    *val = (unsigned char)(data & 0xff);
    retval = 0;

    return retval;
}