【嵌入式Linux驱动开发】八、LED驱动尽善尽美 - 设备树点亮一盏假的LED

   如果我所做的每一件事都要对我的人生有用,那我的人生到底是什么呢?
  赚更多的钱?开更好的车?住更大的房子?
  这些鬼东西就是我的人生么?


一、回顾编写驱动的三种方法

1、资源和驱动在同一个文件里

在这里插入图片描述

2、资源用Platform_device指定,驱动在Platform_driver实现
在这里插入图片描述

3、资源用设备树指定,驱动在Platform_driver实现
在这里插入图片描述
核心永远是 file_operations 结构体。上述三种方法,只是指定“硬件资源”的方式不一样。

从上图可以知道, platform_device/platform_driver 只是编程的技巧,不涉及驱动的核心。

二、怎么使用设备树写驱动程序

2.1 设备树节点要与 platform_driver 能匹配

  在我们的工作中,驱动要求设备树节点提供什么,我们就得按这要求去编写设备树。但是,匹配过程所要求的东西是固定的。

  • ① 设备树要有 compatible 属性,它的值是一个字符串
  • ② platform_driver 中要有 of_match_table,其中一项的.compatible 成员设置为一个字符串
  • ③ 上述 2 个字符串要一致。

比如:
在这里插入图片描述

2.2 设备树节点指定资源, platform_driver 获得资源

  如果在设备树节点里使用 reg 属性,那么内核生成对应的 platform_device 时会用 reg属性来设置 IORESOURCE_MEM 类型的资源。
  如果在设备树节点里使用 interrupts 属性,那么内核生成对应的 platform_device 时会用reg 属性来设置 IORESOURCE_IRQ 类型的资源。对于 interrupts 属性,内核会检查它的有效性,所以不建议在设备树里使用该属性来表示其他资源。

  在我们的工作中,驱动要求设备树节点提供什么,我们就得按这要求去编写设备树。驱动程序中根据 pin 属性来确定引脚,那么我们就在设备树节点中添加 pin 属性。

比如:

设备树节点中有

#define GROUP_PIN(g,p) ((g<<16) | (p))
100ask_led0 {
	compatible =100ask,led”;
	pin = <GROUP_PIN(5, 3)>;
};

驱动程序中,可以从 platform_device 中得到 device_node,再用 of_property_read_u32
得到属性的值:

struct device_node* np = pdev->dev.of_node;
int led_pin;
int err = of_property_read_u32(np, “pin”, &led_pin);

三、编写程序

在本实验中,需要添加的设备节点代码是一样的,你需要找到你的单板所用的设备树文
件,在它的根节点下添加如下内容:

#define GROUP_PIN(g,p) ((g<<16) | (p))
100ask_led@0 {
	compatible = "100as,leddrv";
	pin = <GROUP_PIN(3, 1)>;
};
100ask_led@1 {
	compatible = "100as,leddrv";
	pin = <GROUP_PIN(5, 8)>;
};
  • 对于QEMU 模拟的 IMX6ULL 板子,我的设备树文件是在内核源码目录中/home/clay/linux/qemu/kernel/100ask_imx6ull-qemu/linux-4.9.88/arch/arm/boot/dts/100ask_imx6ul_qemu.dts

在这里插入图片描述

  • 修改、编译后得到arch/arm/boot/dts/100ask_imx6ul_qemu.dtb 文件

    • 注意需要在内核源码的根目录下,执行make dtbs
    • 我的内核源码目录是:/home/clay/linux/qemu/kernel/100ask_imx6ull-qemu/linux-4.9.88
  • 然后去覆盖qemu板旧的dtb文件,路径在qemu安装目录下的./imx6ull-system-image文件夹中,我的是/home/clay/linux/qemu/new/ubuntu-16.04_imx6ul_qemu_system/imx6ull-system-image目录

然后修改chipY_gpio.c,较上一节不同的是,主要修改了如下几个地方

  • 添加of_match_table属性,定义其中的compatible属性和设备树中的一致,做到Platform_device和Platform_driver匹配!
    在这里插入图片描述
  • 修改probe函数,通过of函数获取设备树中的定义的引脚,创建设备
    在这里插入图片描述
  • 修改remove函数,销毁设备
    在这里插入图片描述

删除了board_A_led.c因为由设备树指定资源!其他的内容几乎不变!

四、运行程序

编译程序没有问题后,运行qemu虚拟开发板,并做好准备工作!

  • 拷贝所有的.ko和ledtest到NFS中
cp *.ko ledtest ~/linux/qemu/NFS/
  • 在qemu终端,加载ko文件,需要注意的是,因为有依赖关系,所以顺序需要确定!chipY_gpio.ko依赖leddrv.ko,故需要先加载leddrv.ko!
insmod leddrv.ko
insmod chipY_gpio.ko

在qemu中加载最后一个模块时,会出现下面的提示信息,但是ctrl+c之后,似乎测试还是可以用的,不知道是怎么回事。知道的朋友,可以在下面留言一起探讨!
在这里插入图片描述

  • 查看LED对应的设备树节点是够加载成功

    • cd /sys/firmware/devicetree/base/,然后输入ls命令可以看到如下信息
      在这里插入图片描述
    • 其中就包含了我们在设备树中添加的两个LED节点!
    • 我们可以进入节点,查看节点的属性。
    • cd cd 100ask_led@0
      在这里插入图片描述
    • 属性值是字符串时,用 cat 命令可以打印出来;属性值是数值时,用 hexdump 命令可以打印出来。
      在这里插入图片描述
    • 除了可以看到设备树信息,我们当然也可以看到节点解析后生成的platform_device信息
    • cd /sys/devices/soc0,然后可以看到一堆的platform_device,当然也可以周到我们的led了.
      在这里插入图片描述
    • 继续进入led里,cd 100ask_led@0 ,可以看到Platform_divice的各种属性,需要注意的是其中的driver目录,这个是只有在platform_device和Platform_driver绑定后才会生成的!
      在这里插入图片描述
    • 当然我们可以查看driver的具体信息,ls -l driver,可以看到它指向/sys/bus/platform/drivers/100ask_led
      在这里插入图片描述
  • 在qemu终端,运行应用程序打开LED0

./ledtest /dev/100ask_led0 on

在这里插入图片描述

led0对应的就是GPIO3_IO1引脚,这个在设备树中指定的!

  • 在qemu终端,运行应用程序打开LED1
./ledtest /dev/100ask_led1 on

在这里插入图片描述

led1对应的就是GPIO5_IO8引脚


终于终于,将设备树的内容一口气输出完了,但是上面的程序我们并没有配置具体的硬件,为了更好的理解设备树思想嘛!所以,这还仅仅是一盏假的LED,别急别急,下一次我们真的LED就要来了!拭目以待~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章