2.关于zynq+qt+ov5640摄像头在LCD屏上显示驱动部分

        首先,在驱动部分,我们从简单一步一步来写。本文的驱动采用的是设备树获取信息方式。

        1)简单些的,比如led灯,beep,采用的是paltform总线,gpio子系统。这里我以beep举例

         gpio子系统:gpio子系统是内核中用来管理gpio资源的一套系统,它提供了很多关于GPIO的API函数。驱动程序中使用GPIO之前,我们需要先向gpio子系统先申请gpio,申请成功后才可以使用这个gpio,这样的话防止了gpio被复用。gpio子系统提供了关于一个gpio口的设置,如输入,输出方向,输出高或低电平。

        platform总线:Linux系统要考虑到驱动的可重用行,因此提出了分层和分离得软件思路。由此platform总线应运而生。

        分离

对于每个平台(SOC),我们都需要编写相应的I2C主机驱动,这个不能省略。但是,对于MPU6050,它仅是通过I2C进行通信的,所以,对于不同的平台,MPU6050这个设备驱动是可以进行重用的。所以,可以形成下面这样的思路。

(1)而对于不同平台的MPU6050驱动,可能MPU6050所挂载的I2C不同(2)一个SOC有多个MPU6050。那此时我们会需要改变这个驱动程序以此来适应SOC。你想想,对应(1),我们是不是需要改变驱动程序中的硬件信息。对应(2),我们是不是得根据挂载的MPU6050不同,改变硬件信息,有几个MPU6050,我们就需要几个对应的驱动程序。这是不是是的驱动程序变得繁琐且多。因此,为了驱动程序的重用性,提出了驱动分离的想法。即驱动和设备信息分离开来,通过一种总线连接,总线充当月老的角色,将设备和驱动连接起来。这个总线就是platform总线。使用了总线后,对于(1),我们只需要改变设备树中的硬件信息即可。对于(2),我们不需要多个驱动程序了,只需要一个驱动程序,在设备树中,用到的硬件信息去匹配这个驱动程序即可,减少了代码的冗余。

 分层的话这里还没用到,后面用到我会讲。下面是关于beep的驱动代码和设备树文件。

beeper{
    compatible = "alientek,beeper";
    status = "okay";
    default-state = "off";
    beeper-gpio = <&gpio0 58 GPIO_ACTIVE_HIGH>;
 };
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define  GPIOBEEP_NAME  "beep"
#define  GPIOBEEP_CNT    1

struct beep_dev {
	dev_t devid;
	struct cdev cdev;
	struct class *class;
	struct device *device;
	int gpio_beep;
}; 

static struct beep_dev beep;

static int beep_open(struct inode *inode,struct file *filp){
	filp->private_data = &beep;  // 使得在初始化后的结构体信息能被使用
	return 0;
}

static ssize_t beep_read(struct file *filp,char __user *buf,size_t cnt,loff_t *offt){
	return 0;
}

static ssize_t beep_write(struct file *filp,const char __user *buf,size_t cnt,loff_t *offt){
	int ret;
	char ker_buf[1];
	ret = copy_from_user(ker_buf,buf,cnt);
	if(ret < 0){
		printk(KERN_ERR"Get from user data failed!\n");
		return -EFAULT;
	}
	
	if(ker_buf[0] == 1){
		gpio_set_value(beep.gpio_beep,1);
	}else if(ker_buf[0] == 0){
		gpio_set_value(beep.gpio_beep,0);
	}
	return 0;
}

static int beep_release(struct inode *inode,struct file *filp){
	return 0;
}

static struct file_operations beep_fops = {
	.owner   = THIS_MODULE,
	.open    = beep_open,
	.read    = beep_read,
	.write   = beep_write,
	.release = beep_release,
};

static int beep_init(struct platform_device *pdev){
	struct device dev = pdev->dev;
	int ret;
	beep.gpio_beep= of_get_named_gpio(dev.of_node, "beep-gpio", 0);
	if(!gpio_is_valid(beep.gpio_beep)){
		printk(KERN_ERR"Get gpio num is %d\n",beep.gpio_beep);
		return -1;
	}
	
	ret = gpio_request(beep.gpio_beep,"BEEP-GPIO");
	if(ret < 0){
		printk(KERN_ERR"Request gpio is failed!\n");
		return ret;
	}
	
	gpio_direction_output(beep.gpio_beep,0);
	
	return 0;
}

static int beep_probe(struct platform_device *pdev){
	int ret;
	ret = beep_init(pdev);
	if(ret < 0){
		return ret;
	}
	
	ret = alloc_chrdev_region(&beep.devid, 0, GPIOBEEP_CNT, GPIOBEEP_NAME);
	if (ret)
		goto out1;
	
	beep.cdev.owner = THIS_MODULE;
	cdev_init(&beep.cdev, &beep_fops);

	 /* 添加一个cdev */
	ret = cdev_add(&beep.cdev, beep.devid, GPIOBEEP_CNT);
	if (ret)
		goto out2;

	 /* 创建类 */
	beep.class = class_create(THIS_MODULE, GPIOBEEP_NAME);
	if (IS_ERR(beep.class)) {
		ret = PTR_ERR(beep.class);
		goto out3;
	}

	 /* 创建设备 */
	beep.device = device_create(beep.class, NULL,
				beep.devid, NULL, GPIOBEEP_NAME);
	if (IS_ERR(beep.device)) {
		ret = PTR_ERR(beep.device);
		goto out4;
	}

	return 0;

out4:
	class_destroy(beep.class);

out3:
	cdev_del(&beep.cdev);

out2:
	unregister_chrdev_region(beep.devid, GPIOBEEP_CNT);

out1:
	gpio_free(beep.gpio_beep);

	return ret;
}
static int beep_remove(struct platform_device *pdev)
{
	/* 注销设备 */
	device_destroy(beep.class, beep.devid);

	/* 注销类 */
	class_destroy(beep.class);

	/* 删除cdev */
	cdev_del(&beep.cdev);

	/* 注销设备号 */
	unregister_chrdev_region(beep.devid, GPIOBEEP_CNT);
	
	/* 释放GPIO */
	gpio_free(beep.gpio_beep);
	
	
	return 0;

}

static const struct of_device_id beep_of_match[] = {
	{.compatible = "alientek,beep"},
	{         }
};
MODULE_DEVICE_TABLE(of, beep_of_match);
static struct platform_driver beep_driver = {
	.driver = {
		.name = "stm32mp1-beep", /* 驱动名字,用于和设备匹配 */
		.of_match_table = beep_of_match, /* 设备树匹配表 */
},
	.probe  = beep_probe,
	.remove = beep_remove,
};

module_platform_driver(beep_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ALIENTEK");
MODULE_INFO(intree, "Y");

 2)dht11温湿度模块

        关于该模块,前面的硬件信息,我也讲过了。需要一个gpio口,根据官方给的时序进行传输,最后得到数据。具体的驱动代码我放在下面了。

dht11{
    compatible = "alientek,dht11";
    status = "okay";
    default-state = "off";
    dht11-gpio = <&gpio0 59 GPIO_ACTIVE_HIGH>;
 };
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#define  DHT11_NAME     "dht11io"
#define  DHT11_CNT       1
 
struct dht11_dev {
    dev_t devid;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    int    dht11_gpio;
};
struct dht11_data {
    unsigned char hmod_data;
    unsigned char lmod_data;
    unsigned char htem_data;
    unsigned char ltem_data;
};
static struct dht11_dev dht11;
static struct dht11_data mtdata;
 
static void dht11_start(struct dht11_dev *dev){
    gpio_direction_output(dev->dht11_gpio,1);
    mdelay(30);
    gpio_set_value(dev->dht11_gpio,0);
    mdelay(20);
    gpio_set_value(dev->dht11_gpio,1);
    udelay(30);
    gpio_direction_input(dev->dht11_gpio);
    udelay(2);
 
}
 
static int dht11_reply(struct dht11_dev *dev){
    unsigned char rey = 0;
    while((gpio_get_value(dev->dht11_gpio) == 1) && rey < 100){
        rey++;
        udelay(1);
    }
    if(rey >= 100){
        return -1;
    }else{
        rey = 0;
    }
    while((gpio_get_value(dev->dht11_gpio) == 0) && rey < 100){
        rey++;
        udelay(1);
    }
    if(rey >= 100){
        return -1;
    }else{
        return 0;
    }
}
 
static int dht11_read_bit(struct dht11_dev *dev){
    unsigned char rey = 0;
    while((gpio_get_value(dev->dht11_gpio) == 1) && rey < 100){
        rey++;
        udelay(1);
    }
    rey = 0;
    while((gpio_get_value(dev->dht11_gpio) == 0) && rey < 100){
        rey++;
        udelay(1);
    }
    udelay(40);
    if(gpio_get_value(dev->dht11_gpio) == 1){
        return 1;
    }else{
        return 0;
    }
}
static unsigned char dht11_read_byte(struct dht11_dev *dev){
    unsigned char i,dat;
    dat = 0;
    for(i = 0;i < 8;i++){
        dat <<= 1;
        dat |= dht11_read_bit(dev);
    }
    return dat;
}
static int dht11_open(struct inode *inode,struct file *filp){
    filp->private_data = &dht11;
    return 0;
}
 
static ssize_t dht11_write(struct file *filp,const char __user *buf,size_t cnt,loff_t *offt){
    return 0;
}
 
static ssize_t dht11_read(struct file *filp,char __user *buf,size_t cnt,loff_t *offt){
    struct dht11_dev *dev = filp->private_data;
    u8 kernel_buf[5];
    int ret,i;
    dht11_start(dev);
    ret = dht11_reply(dev);
    if(ret < 0){
        return ret;
    }
    
    for(i = 0;i < 5;i++){
        kernel_buf[4 - i] = dht11_read_byte(dev);
    }
 
    if(kernel_buf[4] + kernel_buf[3] + kernel_buf[2] + kernel_buf[1] == kernel_buf[0]){
        mtdata.hmod_data = kernel_buf[4];
        mtdata.lmod_data = kernel_buf[3];
        mtdata.htem_data = kernel_buf[2];
        mtdata.ltem_data = kernel_buf[1];
    }
    pr_info("DHT11: kernel_buf = [%u, %u, %u, %u]\n",
           mtdata.hmod_data,mtdata.lmod_data,mtdata.htem_data,mtdata.ltem_data);
    ret = copy_to_user(buf,&mtdata,sizeof(struct dht11_data));
    if(ret){
        return ret;
    }    
}
static int dht11_release(struct inode *inode,struct file *filp){
    return 0;
}
 
static struct file_operations dht11_ops = {
    .owner   = THIS_MODULE,
    .open    = dht11_open,
    .write   = dht11_write,
    .read    = dht11_read,
    .release = dht11_release,
};
 
static int dht11_probe(struct platform_device *pdev){
     int ret;
    //获得gpio编号
    dht11.dht11_gpio = of_get_named_gpio(pdev->dev.of_node,"dht11-gpio",0);
    if(!gpio_is_valid(dht11.dht11_gpio)){
        printk(KERN_ERR"Gipo number id invalid!\r\n");
        return -EINVAL;
    }
    //向系统申请gpio
    ret = gpio_request(dht11.dht11_gpio,"DHT11");
    if(ret){
        printk(KERN_ERR"Gipo request failed!\r\n");
        return -EINVAL;
    }
     //设备号
    ret = alloc_chrdev_region(&dht11.devid,0,DHT11_CNT,DHT11_NAME);
    if(ret)
        goto out1;
    //cdev
    dht11.cdev.owner = THIS_MODULE;
    cdev_init(&dht11.cdev,&dht11_ops);
    ret = cdev_add(&dht11.cdev,dht11.devid,DHT11_CNT);
    if(ret)
        goto out2;
    //创建类
    dht11.class = class_create(THIS_MODULE,DHT11_NAME);
    if(IS_ERR(dht11.class)){
        ret = PTR_ERR(dht11.class);
        goto out3;
    }
    //创建设备
    dht11.device = device_create(dht11.class,&pdev->dev,dht11.devid,NULL,DHT11_NAME);
    if(IS_ERR(dht11.device)){
        ret = PTR_ERR(dht11.device);
        goto out4;
    }
    return 0;
    out4:
        class_destroy(dht11.class);
 
    out3:
        cdev_del(&dht11.cdev);
 
    out2:
        unregister_chrdev_region(dht11.devid,DHT11_CNT);
    
    out1:
        gpio_free(dht11.dht11_gpio);
 
        return ret;
}
 
static int dht11_remove(struct platform_device *pdev){
    //注销设备
    device_destroy(dht11.class,dht11.devid);
 
    //注销类
    class_destroy(dht11.class);
 
    //注销字符设备
    cdev_del(&dht11.cdev);
 
    //注销设备号
    unregister_chrdev_region(dht11.devid,DHT11_CNT);
 
    //释放gpio
    gpio_free(dht11.dht11_gpio);
}
 
//匹配列表
static const struct of_device_id dht11_of_match[] = {
    {.compatible = "alientek,dht11"},
    {/*Sentinel*/}
};
 
 
static struct platform_driver dht11_driver = {
    .driver = {
        .name               = "zynq-dht11",
        .of_match_table     = dht11_of_match,
    },
    .probe         = dht11_probe,
    .remove        = dht11_remove,
};
 
module_platform_driver(dht11_driver);
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FUSU");
MODULE_INFO(intree, "Y");

 

        

        

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值