这一章使用第五章的设备树知识来写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状态属性设置为okey
  • reg属性,设置了所要使用的寄存器物理地址。

添加完保存后使用命令

make dtbs

编译得到deb文件。

2.驱动程序

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

#define DTSLED_CNT           1           /* 设备号个数 */
#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,不过驱动仍然正常使用,此报错先搁置,遇到不能用的时候再探讨。

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

Linux驱动学习记录-6.设备树的LED驱动相关推荐

  1. Linux驱动_设备树下LED驱动

    前言 学习完设备树基础知识后,完成设备树下LED驱动实验 一.修改设备树文件 在设备书根/节点下添加子节点led信息: alphaled {status = "okay";comp ...

  2. 全志linux led驱动程序,芯灵思Sinlinx A64 linux通过设备树写LED驱动(附参考代码,未测试)...

    #include #include #include #include #include #include #include #include #include #include #include # ...

  3. iTOP-iMX6开发板-设备树内核-注册驱动例程

    本文档主要讲解在迅为iTOP-iMX6Q/D/PLUS 开发板的设备树内核(4.1.15)源码中,设备树注册 驱动和非设备树的类似. 1 注册驱动源码分析 设备树的内核驱动中,platform_dri ...

  4. 【基于Linux系统设备树的SPI驱动编写方法】

    文章目录 前言 一.SPI驱动编写 1.修改设备树  a.设备树文件是什么?  b.设备树怎么改? 2.编写驱动 二.完善和测试 1.编译和应用程序  a.编译 && 拷贝到开发板命令 ...

  5. Linux内核学习-字符设备驱动学习(二)

    在Linux内核学习-字符设备驱动学习(一)中编写字符设备驱动的一种方法,但是需要手动创建设备节点. 有没有能够自动的创建设备节点的呢? 有!使用class_create()和device_creat ...

  6. Android 驱动(12)---Linux DTS(Device Tree Source)设备树详解

    Linux DTS(Device Tree Source)设备树详解 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) Linux DTS(Device Tr ...

  7. Linux利用platform_driver和设备树实现PWM驱动

    Linux利用platform_driver和设备树实现PWM驱动 字符设备PWM驱动 一.PWM驱动的硬件资源 1.PWM工作原理 2.PWM电路原理 3.PWM内部结构 二.具体代码 1.设备树 ...

  8. linux设备和驱动匹配的方法,Linux使用设备树的i2c驱动与设备匹配方式

    Linux使用设备树的i2c驱动与设备匹配有3种方式: of_driver_match_device acpi_driver_match_device i2c_match_id 源码: static ...

  9. Linux dts设备树和platform驱动详解

    概念 小麦大叔 2019-05-06 22:56:31 12603 收藏 135 什么是设备树 dts(device tree)? 设备树(Device Tree)是描述计算机的特定硬件设备信息的数据 ...

最新文章

  1. 怎样快速学习html5,如何快速学习HTML5?带你了解HTML5学什么?
  2. 连接数据库版本不一致
  3. 11个实用jQuery日历插件
  4. C#LeetCode刷题-蓄水池抽样
  5. 马云谈区块链:不可能也不应该用来一夜暴富
  6. 错乱的 Windows 10
  7. 我发现了一个价值8500美元的 HackerOne 平台漏洞
  8. 【HDOJ6992】Lawn of the Dead(线段树×, 模拟大法好√)
  9. c语言新手的无奈,几个新手容易犯的错误
  10. ctf-web-sql注入
  11. c语言学生综合测评系统_学生综合评价系统
  12. 网络工程师--网络规划和设计案例分析(4)
  13. JimuReport积木报表 — SQL数据源报表制作
  14. HIVE厂牌艺人_北京音乐节-北京音乐节全攻略 - 马蜂窝
  15. 37.WLAN Qos介绍
  16. 【c++】——函数的堆栈调用详细过程
  17. 计算机考研面试自我介绍范文英语,研究生英语面试自我介绍范文三篇
  18. 综述:人类电生理的脑连接组学
  19. 证券公司信用风险管理体系—以平安证券为例-课后检验-满分
  20. 自我总结前端vue笔记

热门文章

  1. Remove Smallest
  2. 水仙花数是指一个N位正整数(N≥3),它的每个位上的数字的N次幂之和等于它本身。例如:153=1 3 +5 3 +3 3 。 本题要求编写两个函数,一个判断给定整数是否水仙花数,另一个按从
  3. Maven简介、下载、安装、配置以及使用
  4. hdu1181(dfs)变形记
  5. app 与服务器交互 token
  6. 观杨宁之《文学理论课程》
  7. html圆形图片怎么加白边框,带图片,带文字,有白边框的这种图片怎么制作的?...
  8. 代谢物表达值做关系网络图(cytoscape)
  9. 三菱、汇川plc用485通讯板和变频器通讯,实现正转、反转、运行过程改变频率实现调速
  10. db2数据库创建编目