zynq linux驱动之使用设备树开发

2 篇文章 0 订阅
2 篇文章 0 订阅

PC:Windows 10

虚拟机:ubuntu 16.04

vivado:2017.04

PetaLinux:2017.04

开发板:黑金AX7010

根文件系统:debian8

-------------------------------------------------- --------------------传说中的分割线------------------------- -------------------------------------------------- ------

在  zynq linux驱动之传统开发   基础上,实现用设备树开发驱动:

首先回到的的PetaLinux的工程目录下:

find -name "system-top.dts"

cd ./components/plnx_workspace/device-tree/device-tree-generation/

进入该目录 

ls

首先打开系统top.dts看一下

发现包涵了一个系统user.dtsi

回到工程根目录,然后查找一下系统user.dtsi

cd -
find -name "system-user.dtsi"

直接打开./project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi编辑

/include/ "system-conf.dtsi"
/ {
        amba_pl: amba_pl{
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "simple-bus";
                ranges;
                leds: leds@41200000{
                        compatible = "hello,leds";
                        reg = <0x41200000 0x1>;
                };
        };

};

使用的的PetaLinux编译一下工程

petalinux-build

编译完成后回到开发板

挂接NFS文件系统

把生成的system.dts文件拷贝到SD的fat分区里

过程略....

重启开发板

接下来编写驱动:

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/of.h>
#include <linux/delay.h>

#include <linux/dma-mapping.h>

#include <linux/pm.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/gfp.h>
#include <linux/mm.h>
#include <linux/dma-buf.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/dmaengine.h>
#include <linux/completion.h>
#include <linux/wait.h>
#include <linux/init.h>

#include <linux/sched.h>
#include <linux/pagemap.h>
#include <linux/errno.h>	/* error codes */
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>

#include <linux/moduleparam.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/notifier.h>
#include <linux/init.h>
#include <linux/pci.h>


//  定义设备文件名
#define DEVICE_NAME "leds_drv"




//
static char 			devname[16];
static int 				major;
static int             	mijor;
static struct class*	cls;
static void __iomem*	base_address;	
static resource_size_t  remap_size;  
static int	            irq;
static struct device*	dev;           

//



typedef struct{
	volatile unsigned int ODR;
}LEDS_T;

LEDS_T* leds;


static int leds_drv_open(struct inode *Inode, struct file *File)
{
	leds->ODR = 0xf;
	return 0;
}


static ssize_t leds_drv_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	return 0;
}

static ssize_t leds_drv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
	unsigned int ret = 0;
	unsigned int tmp_val;
	
	ret = copy_from_user(&tmp_val, buf, count);
	
	leds->ODR = (~tmp_val) & 0xf;
	
	return ret;
}


//  描述与设备文件触发的事件对应的回调函数指针
static struct file_operations dev_fops =
{ 
	.owner = THIS_MODULE, 
	.open = leds_drv_open,
	.read = leds_drv_read, 
	.write = leds_drv_write,
};


static int leds_drv_probe(struct platform_device *pdev)
{
	struct resource 	*res;
	struct device *tmp_dev;
	
	memset(devname,0,16);
	strcpy(devname, DEVICE_NAME);
	
	major = register_chrdev(0, devname, &dev_fops);
	
	cls = class_create(THIS_MODULE, devname);
	mijor = 0;
	
	tmp_dev = device_create(cls, &pdev->dev, MKDEV(major, mijor), NULL, devname);
	if (IS_ERR(tmp_dev)) {
		class_destroy(cls);
		unregister_chrdev(major, devname);
		return 0;
	}
	


	//获取资源
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if(res == NULL)
	{
		printk(KERN_ALERT "leds_drv_probe res error!\n");
		return -ENOENT;
	}

	
	base_address = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(base_address))
		return PTR_ERR(base_address);

	printk("base_address = 0x%08x\n", (unsigned int)base_address);


	remap_size = resource_size(res);
	printk("remap_size = 0x%08x\n", remap_size);


	dev = &pdev->dev;


	//保存dev数据
	//platform_set_drvdata(pdev, &xxx);	

	
	leds = (LEDS_T*)base_address;
	
	return 0;
}

static int leds_drv_remove(struct platform_device *pdev)
{
	device_destroy(cls, MKDEV(major, mijor));	
	class_destroy(cls);
	unregister_chrdev(major, devname);
	devm_iounmap(&pdev->dev, base_address);
	return 0;
}

static int leds_drv_suspend(struct device *dev)
{

	return 0;
}

static int leds_drv_resume(struct device *dev)
{
 
	return 0;
}

static const struct dev_pm_ops leds_drv_pm_ops = {
	.suspend = leds_drv_suspend,
	.resume  = leds_drv_resume,
};



static const struct of_device_id leds_drv_of_match[] = {
	{.compatible = "hello,leds" },
	{ }
};
MODULE_DEVICE_TABLE(of, leds_drv_of_match);


static struct platform_driver leds_drv_driver = {
	.probe = leds_drv_probe,
	.remove	= leds_drv_remove,
	.driver = {
		.owner   		= THIS_MODULE,
		.name	 		= "leds@41200000",
		.pm    			= &leds_drv_pm_ops,
		.of_match_table	= leds_drv_of_match,		
	},
};

module_platform_driver(leds_drv_driver);


MODULE_LICENSE("GPL v2");



Makefile文件:

export ARCH=arm

KERN_DIR = /home/zynq/work/kernel/linux-4.9 



all:
	make -C $(KERN_DIR) M=`pwd` modules



clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order

obj-m  += leds_drv.o


执行一下

make

换到开发板,加载驱动:

编写测试程序:

#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>



int main(int argc, char** argv)
{
        int fd;
        fd = open("/dev/leds_drv", O_RDWR);
        if(fd < 0)
        {
                printf("fd = %d open fialed!\n", fd);
        }

        unsigned int leds = 0;

        while(1)
        {
                                write(fd, &leds, 4);

                                leds++;
                                leds %= 0xf;
                                sleep(1);
        }

        close(fd);

        return 0;
}

编译测试程序:

arm-linux-gnueabihf-gcc -o leds leds.c

最后回到开发板

执行./leds

又一次看到4个led做加法了

 

 

 

 

 

上一篇:zynq linux驱动之传统开发

下一篇:zynq linux驱动之PL-PS中断

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值