700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Linux驱动学习记录-6.设备树的LED驱动

Linux驱动学习记录-6.设备树的LED驱动

时间:2020-08-04 09:41:01

相关推荐

Linux驱动学习记录-6.设备树的LED驱动

这一章使用第五章的设备树知识来写led驱动

1.修改设备树

在根节点下面添加子节点

alphaled {#address-cells = <1>;#size-cells = <1>;compatible = "atkalpha-led";status = "okay";reg = < 0X020C406C 0X04/* CCM_CCGR1_BASE */0X020E0068 0X04/* SW_MUX_GPIO1_IO03_BASE */0X020E02F4 0X04/* SW_PAD_GPIO1_IO03_BASE */0X0209C000 0X04/* GPIO1_DR_BASE */0X0209C004 0X04 >; /* GPIO1_GDIR_BASE */};

alphaled是节点名字#address和#size都是1,表示reg属性起始地址占用一个字节,地址长度也占用一个字节compatbile设置节点兼容性为"atkalpha-led"。status状态属性设置为okeyreg属性,设置了所要使用的寄存器物理地址。

添加完保存后使用命令

make dtbs

编译得到deb文件。

2.驱动程序

摘取正点原子/04_dtsled部分代码,代码在第五节新字符驱动上修改。

#define DTSLED_CNT1 /* 设备号个数 */#define DTSLED_NAME"dtsled"/* 名字 *//* dtsled设备结构体 */struct dtsled_dev{dev_t devid;/* 设备号 */struct cdev cdev;/* cdev */struct class *class;/* 类 */struct device *device;/* 设备 */int major;/* 主设备号 */int minor;/* 次设备号 */struct device_node*nd; /* 设备节点 */};struct dtsled_dev dtsled;/* led设备 */static int led_open(struct inode *inode, struct file *filp){filp->private_data = &dtsled; /* 设置私有数据 */return 0;}/* 设备操作函数 */static struct file_operations dtsled_fops = {.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release = led_release,};/** @description: 驱动入口函数* @param : 无* @return : 无*/static int __init led_init(void){u32 val = 0;int ret;u32 regdata[14];const char *str;struct property *proper;/* 获取设备树中的属性数据 *//* 1、获取设备节点:alphaled */dtsled.nd = of_find_node_by_path("/alphaled");if(dtsled.nd == NULL) {printk("alphaled node nost find!\r\n");return -EINVAL;} else {printk("alphaled node find!\r\n");}/* 2、获取compatible属性内容 */proper = of_find_property(dtsled.nd, "compatible", NULL);if(proper == NULL) {printk("compatible property find failed\r\n");} else {printk("compatible = %s\r\n", (char*)proper->value);}/* 3、获取status属性内容 */ret = of_property_read_string(dtsled.nd, "status", &str);if(ret < 0){printk("status read failed!\r\n");} else {printk("status = %s\r\n",str);}/* 4、获取reg属性内容 */ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10);if(ret < 0) {printk("reg property read failed!\r\n");} else {u8 i = 0;printk("reg data:\r\n");for(i = 0; i < 10; i++)printk("%#X ", regdata[i]);printk("\r\n");}/* 初始化LED */#if 0/* 1、寄存器地址映射 */IMX6U_CCM_CCGR1 = ioremap(regdata[0], regdata[1]);SW_MUX_GPIO1_IO03 = ioremap(regdata[2], regdata[3]);SW_PAD_GPIO1_IO03 = ioremap(regdata[4], regdata[5]);GPIO1_DR = ioremap(regdata[6], regdata[7]);GPIO1_GDIR = ioremap(regdata[8], regdata[9]);#elseIMX6U_CCM_CCGR1 = of_iomap(dtsled.nd, 0);SW_MUX_GPIO1_IO03 = of_iomap(dtsled.nd, 1);SW_PAD_GPIO1_IO03 = of_iomap(dtsled.nd, 2);GPIO1_DR = of_iomap(dtsled.nd, 3);GPIO1_GDIR = of_iomap(dtsled.nd, 4);#endif/* 注册字符设备驱动 *//* 1、创建设备号 */if (dtsled.major) {/* 定义了设备号 */dtsled.devid = MKDEV(dtsled.major, 0);register_chrdev_region(dtsled.devid, DTSLED_CNT, DTSLED_NAME);} else {/* 没有定义设备号 */alloc_chrdev_region(&dtsled.devid, 0, DTSLED_CNT, DTSLED_NAME);/* 申请设备号 */dtsled.major = MAJOR(dtsled.devid);/* 获取分配号的主设备号 */dtsled.minor = MINOR(dtsled.devid);/* 获取分配号的次设备号 */}printk("dtsled major=%d,minor=%d\r\n",dtsled.major, dtsled.minor);/* 2、初始化cdev */dtsled.cdev.owner = THIS_MODULE;cdev_init(&dtsled.cdev, &dtsled_fops);/* 3、添加一个cdev */cdev_add(&dtsled.cdev, dtsled.devid, DTSLED_CNT);/* 4、创建类 */dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);if (IS_ERR(dtsled.class)) {return PTR_ERR(dtsled.class);}/* 5、创建设备 */dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME);if (IS_ERR(dtsled.device)) {return PTR_ERR(dtsled.device);}return 0;}/** @description: 驱动出口函数* @param : 无* @return : 无*/static void __exit led_exit(void){/* 取消映射 */iounmap(IMX6U_CCM_CCGR1);iounmap(SW_MUX_GPIO1_IO03);iounmap(SW_PAD_GPIO1_IO03);iounmap(GPIO1_DR);iounmap(GPIO1_GDIR);/* 注销字符设备驱动 */cdev_del(&dtsled.cdev);/* 删除cdev */unregister_chrdev_region(dtsled.devid, DTSLED_CNT); /* 注销设备号 */device_destroy(dtsled.class, dtsled.devid);class_destroy(dtsled.class);}

代码关键在获取设备树中的属性数据:因为知道设备树的地址,可以直接通过地址查找"/alphaled",得到设备节点(在创建设备结构体,多加一个成员:struct device_node),得到节点后就要获取属性值,compatible、status、reg等。这里获取reg采用_read_u32_array(),因为我们的reg是一组32位数组。获取reg数组后,可以用ioremap()得到物理地址对应的虚拟地址,也可以通过of_iomap()直接获取虚拟地址。使用设备树推荐第二种。

其余部分和第五章一样。

3.测试

与前面一样。

4.设备树的编译更换运行

学习资料是用正点,但是开发板用的东山,设备树描述板级信息,所以我们用了东山的设备树文件。

东山用的是4.9.88版本源码,正点是4.1.15,都是4版本问题不大。板子到我手里时用的应该是正点的4.1.15版本,因为我下载正点的.ko驱动没有报错。因为要使用东山的设备树,设备树和源码的版本要一致,因此我把东山的4.9.88版本源码重新烧录安装。

进入东山资料下载的4.1.15源码\arch\arm\boot\dts,找到100ask_imx6ull-14x14.dts,可自行添加节点,完成后返回源码,执行make debs,产生100ask_imx6ull-14x14.dtb文件。此dtb就是要更换的设备树文件。

编译的设备树由两种更换方法:

第一,通过nfs从pc传文件至开发板,把dtb文件替换/boot里的dtb文件,开发板/boot里面应该有两个文件zImage和*.dtb,开发板启动要用的,缺少或者不匹配内核无法启动。Starting Kernel ...之后板子再无其他输出,启动失败!替换成功后可以reboot重新启动开发板,如果正常开机就可以使用新的设备树。

第二,通过东山的缮写工具,100ask_imx6ull_flashing_tool.exe,把Ubuntu的设备树通过FileZila传输到pc上,然后替换/files文件里的.dtb文件。打开.exe,开发板设置为USB启动方式,显示设备已连接,点击更新设备树,怎软件会把dtb文件替换开发板/boot目录下的dtb文件。换成emmc模式,重新启动,可以用新的设备树。

第二种比较麻烦,推荐第一种。

安装时遇到一系列问题,以下作为记录。在使用100ASK ToolV3.0工具烧写emmc.img后,emmc启动开发板,发现/boot目录下有三个dtb文件。

当我分别把100ask_imx6ull-14x14.dtb和100ask_myir_imx6ull_mini.dtb删除后,板子可以正常启动,但我把100ask_imx6ull_mini.dtb删除后,板子就启动不了,可以判断他用的是mini设备树。怪不得我修改14x14.dtb的时候重启板子节点没有改变。可我板子是全功能的pro板啊!然后我把14x14.dtb文件重命名为mini.dtb,启动不了。

r然后我使用mfgtool 烧写整个系统到 EMMC 上,启动发现是正常的,/boot里面有一个dtb文件,就是14x14的,之后替换也正常。

更新系统后,安装驱动文件显示版本不匹配,但我确实都是4.1.15,不过驱动仍然正常使用,此报错先搁置,遇到不能用的时候再探讨。

之后需要重点学学习系统移植篇,对内核系统还是不熟悉。捣腾两周才算解决。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。