驱动程序实现i2c通讯-39

Posted 杨斌并

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了驱动程序实现i2c通讯-39相关的知识,希望对你有一定的参考价值。

驱动程序实现i2c通讯

i2c对寄存器的读写

​ 在 I2C 设备驱动中首先要完成 i2c_driver 结构体的创建、初始化和注册,当设备和驱动匹配成功后,就会执行 probe 函数,probe 函数中就是执行字符设备驱动的一套流程。

​ 一般需要在 probe 函数里面初始化 I2C 设备,要初始化 I2C 设备就必须能够对 I2C 设备寄存器进行读写操作,这里就要用到 i2c_transfer 函数了。i2c_transfer 函数最终会调用 I2C 适配器中 i2c_algorithm 里面的 master_xfer 函数,对于 I.MX6U 而言就是 i2c_imx_xfer 这个函数。

  • i2c_transfer 函数

原型如下

  int i2c_transfer(struct i2c_adapter *adap,struct i2c_msg *msgs,int  num)  

作用:

能够对 I2C 设备寄存器进行读写操作

参数:

函数int i2c_transfer(struct i2c_adapter *adap,struct i2c_msg *msgs,int num)
adap所使用的 I2C 适配器,i2c_client 会保存其对应的 i2c_adapter。
msgsI2C 要发送的一个或多个消息
num消息数量,也就是 msgs 的数量
返回值负值,失败,其他非负值,发送的 msgs 数量

i2c传递树据的数据包

  • 我们重点来看一下 msgs 这个参数,这是一个 i2c_msg 类型的指针参数,I2C 进行数据收发说白了就是消息的传递,Linux内核使用i2c_msg 结构体来描述一个消息。
  • i2c_msg 结构体定义在include/uapi/linux/i2c.h 文件中,结构体内容如下
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_STOP		0x8000	/* if I2C_FUNC_PROTOCOL_MANGLING */
        #define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_NOSTART */
        #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 */
            __u16 len;		/* msg length				*/
            __u8 *buf;		/* pointer to msg data			*/
};

代码

  • i2c_client.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>


static struct i2c_client * ft5x06_client;


static void ft5x06_write_reg(u8 reg_addr, u8 data, u8 len);

static void ft5x06_write_reg(u8 reg_addr, u8 data, u8 len){

    u8 buff[256];
     struct i2c_msg msgs[] = {
        [0] = {
            .addr   = ft5x06_client->addr,
            .flags  = 0,
            .len    = len + 1,
            .buf    = buff,
        },

        // [1] = {
        //     .addr   = ft5x06_client->addr,
        //     .flags  = 1,
        //     .len    = sizeof(data),
        //     .buf    = &data,
        // }
    };

    buff[0] = reg_addr;
    memcpy(&buff[1], &data, len);

    i2c_transfer(ft5x06_client->adapter, msgs, 1);

}

static int ft5x06_read_reg(u8 reg_addr);
static int ft5x06_read_reg(u8 reg_addr){

    u8 data;
    struct i2c_msg msgs[] = {
        [0] = {
            .addr   = ft5x06_client->addr,
            .flags  = 0,
            .len    = sizeof(reg_addr),
            .buf    = &reg_addr,
        },

        [1] = {
            .addr   = ft5x06_client->addr,
            .flags  = 1,
            .len    = sizeof(data),
            .buf    = &data,
        }
    };

    i2c_transfer(ft5x06_client->adapter, msgs, 2);

    return  data;

}

struct of_device_id  ft5x06_id[] = {
    {.compatible = "edt,ft5x0x_ts", 0},
    {.compatible = "edt,ft5x0x_ts", 0},
    {.compatible = "edt,ft5x0x_ts", 0},
    {}
};

struct i2c_device_id  ft5x06_id_ts[] = {
    {"xxxxx", 0},
    {},
};

int ft5x06_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id){

    int ret;

    printk("this is  ft5x06_probe \\n ");
    ft5x06_client = i2c_client;//因为我们要在别的函数里面用到这个client,所以我们要把他们复制进来

    //地址为0x80的寄存器里面写入0x4b的数据
    ft5x06_write_reg(0x80, 0x4a, 1);

    ret = ft5x06_read_reg(0x80);
    printk("ret is %#x \\n", ret);

    return 0;
}

int ft5x06_remove(struct i2c_client *i2c_client){
    printk("ft5x06_remove \\n ");
    return 0;
}


static struct i2c_driver ft5x06_driver = {
    .probe = ft5x06_probe,
    .remove = ft5x06_remove,
    .id_table = ft5x06_id_ts,
    .driver = {
        .owner = THIS_MODULE,
        .name = "ft5x06_test",
        .of_match_table = ft5x06_id,
    },
};


static int ft5x06_driver_init(void){

    int ret;

    printk("ft5x06_driver_init \\n");

    ret = i2c_add_driver(&ft5x06_driver);
    if (ret < 0)
    {
        printk("i2c_add_driver is error \\n ");
        return  ret ;
    }

    printk("i2c_add_driver is success \\n");

    return 0;

}

static void ft5x06_driver_exit(void){

    printk("ft5x06_driver_exit \\n");
    i2c_del_driver(&ft5x06_driver);

}

module_init(ft5x06_driver_init);
module_exit(ft5x06_driver_exit);
MODULE_LICENSE("GPL");

以上是关于驱动程序实现i2c通讯-39的主要内容,如果未能解决你的问题,请参考以下文章

两个51单片机如何通过i2c通讯?

stm32103C8T6通过I2C接口实现温湿度(AHT20)的采集与OLED显示

RT-Thread 设备驱动I2C浅析及使用

I2C通信时序图解析

求助STM32 I2C主机与一个从机通讯成功 与多个从机通讯失败

STM32 i2c通讯失败复位方法