简易测温系统IIC设备的驱动编写

本篇文章主要用于自己巩固IIC设备驱动编写的步骤和知识点。

自己做的简易测温系统所使用的传感器为GY906,其探头尺寸大小是16.8mm(长)*11.46mm(宽)*6.2mm(高),探头的直径为8.2mm。测温范围在-70℃~382℃,分辨率为0.02℃,工作电压3.3V~5V。

首先需要在设备树中添加节点:5a为IIC设备器件的地址

&i2c4{
        status = "okay";
        clock-frequency = <30000>;
        gy906:gy906@5a{
                status = "okay";
                compatible = "embeded,gy906";
                reg = <0x5A>;
                };
};

编写GY906设备的驱动如下,下面的代码是需要使用到的头文件和宏定义:

#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/platform_device.h>
#include<linux/i2c.h>
#include<linux/err.h>
#include<linux/regmap.h>
#include<linux/slab.h>
#include<linux/fs.h>
#include<asm/uaccess.h>
#include<linux/cdev.h>
#include<linux/device.h>
#include<linux/of_device.h>

#define I2C_NAME "gy906"

初始化i2c设备结构体以及定义注册驱动字符设备驱动需要的变量:

static struct i2c_client *iic_client = NULL;//初始化iic设备结构体

static dev_t devid; /*设备号*/
static struct cdev cdev; /*字符设备cdev*/
static struct class *class; /*类结构体*/
static struct device *device; /*设备*/

在写好所需要的变量之后,需要写将设备树中gy906IIC设备和IIC驱动匹配起来的命令,设备和驱动匹配的方式一般有两种,分别是传统ID列表匹配方式和添加设备树节点之后的设备树匹配方式:

/*传统id列表匹配方式*/
static const struct i2c_device_id gy906_id[] = {
    {I2C_NAME,0},
    {}
};
/*设备树节点匹配方式*/
static struct of_device_id gy906_ids[] = {
    {.compatible = "embeded,gy906"}.
    {}
};

有了设备和驱动的匹配方法之后,需要初始化IIC驱动结构体:

static struct i2c_driver gy906_driver = {
    .driver = {
        .name = I2C_NAME;,
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(gy906_ids),
    },
    .probe = gy906_probe,
    .remove = gy906_remove,
};

驱动和设备匹配上之后就会执行probe函数,完善probe函数,probe函数里面就是字符设备驱动注册的那一套流程:

static int gy906_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
    int ret = 0;
    printk("gy906_probe\n");
    ret = alloc_chrdev_region(&devid,0,1,I2C_NAME);/*构建设备号*/
    if(ret < 0 ){
        printk("gy906 alloc_chrdev_region err!\r\n");
        goto fail_devid;
    }
    
    cdev_init(&cdev,&iic_fops);/*注册设备*/
    ret = cdev_add(&cdev,devid,1);
    if(ret < 0){
        goto fail_cdev;
    }

    class = class_create(THIS_MODULE,I2C_NAME);/*创建类*/
    if(IS_ERR(class)){
        ret = PTR_ERR(class);
        goto fail_class;
    }
    
    device = device_create(class,NULL,MKDEV(major,0),NULL,I2C_NAME);/*创建设备*/
    if(IS_ERR(device)){
        ret = PTR_ERR(device);
        goto fail_device;
    }

    iic_client = client;
    return 0;

fail_device:
    class_destroy(class);
fail_class:
    cdev_del(&cdev);
fail_cdev:
    unregister_chrdev_region(devid,1);
fail_devid:
    return ret;
}

移除i2c驱动时会执行remove函数,remove函数如下,里面是一些注销操作的集合:

static int gy906_remove(struct i2c_client *client)
{
    printk("gy906_remove\n");
    /*删除字符设备*/
    cdev_dev(&cdev);
    /*释放字符设备号*/
    unregister_chrdev_region(devid,1);
    /*摧毁设备*/
    device_destroy(class,MKDEV(major,0));
    /*摧毁类*/
    class_destroy(class);
    return 0;
}

接下来编写设备操作结构体file_operations里面的函数集合:

static struct file_operations iic_fops = {
    .owner = THIS_MODULE,
    .read = gy906_read,
    .open = gy906_open,
};

static int gy906_open(struct inode *inode,struct file *fd){
    fd->private_data = (void*)iic_client;
    return 0;
}

static ssize_t gy906_read(struct file *filp,char __user *buf,size_t size,lofft_t *offset){
    int ret;
    int timecount = 0;
    printk("gy906 i2c read %d\n",iic_client->addr);
    struct i2c_msg msg[2];
    unsigned char write_buf[1] = {0x07};
    unsigned char read_buf[3];
    
    //创建消息
    //写指令码,0x07为访问RAM的007地址寄存器
    msg[0].addr = iic_client->addr;   /*gy906地址*/
    msg[0].len = 1;                   /*reg长度*/
    msg[0].buf = &write_buf[0];       /*读取的首地址*/
    msg[0].flags = 0;                 /*标志为发送数据*/
    //读数据,⻓度2个字节
    msg[1].addr = iic_client->addr;   /*gy906地址*/
    msg[1].len = 2;                   /*要读取的数据⻓度*/
    msg[1].buf = &read_buf[0];        /*读取数据缓冲区*/
    msg[1].flags = I2C_M_RD;          /*标志为读取数据*/
    while(1){
        timecount ++;
        if(timecount >= 50)
            break;
        ret = i2c_transfer(iic_client->adapter, msg, 2);
        if(ret==2){
            printk("gy906 i2c_transfer sussess %d %d %d %!\r\n",read_buf[0],read_buf[1],read_buf[2];
            break;
        }
    }
    ret = copy_to_user(buf, read_buf, sizeof(read_buf));  
    if(ret){
        printk("copy_to_user fail\r\n");
        return -EINVAL;
    }
    return 0;
}

最后是驱动入口函数和驱动出口函数以及驱动的注册等:

static int __init gy906_init(void){
    return i2c_add_driver(&gy906_driver);
}

static void __exit gy906_exit(void){
    i2c_del_driver(&gy906_driver);
}
module_init(gy906_init);
module_exit(gy906_exit);
MODULE_AUTHOR("KMX");
MODULE_LICENSE("GPL");

至此,关于gy906传感器的IIC设备驱动已经编写完成。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值