引言
在下面这篇博文中:
利用Linux的Platform总线设备驱动实现对多个LED的驱动【只是假想对LED进行驱动,并没有实际的硬件操作】
我们利用Platform总线设备驱动的思想实现了对多个LED的驱动。
Platform总线设备驱动以及其它的总线设备驱动都将驱动分成了三个部分,即总线 (Bus)、设备 (Device) 和 驱动 (Driver)。
- 设备(硬件资源描述): 代表具体的硬件资源,例如一个 LED,同时描述了它的相关硬件信息(如寄存器地址、IRQ 等)。
- 驱动: 实现了操作该设备的具体逻辑代码。
- 总线: 负责在设备和驱动之间建立匹配关系,并调用驱动程序对设备进行初始化。
在下面这篇博文中:
利用Linux的Platform总线设备驱动实现对多个LED的驱动【只是假想对LED进行驱动,并没有实际的硬件操作】
总线部分就是Platform总线,Linux内核源码已经为我们写好了,我们只需写设备(硬件资源描述)和驱动部分。
对于设备(硬件资源描述)部分,我们是写在C文件board_A_led.c
中的,并将其信息存储在结构体platform_device
中的,驱动程序部分根据结构体platform_device
来获取硬件资源信息,进行相应的设备类、设备文件的生成,当然还有具体对硬件的初始化和实际操作。但这样描述硬件资源的办法很麻烦,也很不统一,不利于驱动程序的标准化。
有没有一种方法能把系统中用到的设备资源进行集中且规范的描述呢?
有…那就是设备树文件。
本篇博文我们就使用设备树文件来把之前在博文“利用Linux的Platform总线设备驱动实现对多个LED的驱动【只是假想对LED进行驱动,并没有实际的硬件操作】”的驱动程序进行改进。
显然改进的重点在于对驱动总线中硬件资源描述的部分用设备树进行替换,当然由于硬件资源描述的方式变了,相应的,驱动部分获取硬件资源信息的方式也要改变。
阅读下面内容前建议先行阅读的博文
Platform总线设备驱动是如何把设备资源描述结构体(platform_device)与驱动结构体(platform_driver)匹配起来的
利用Linux的Platform总线设备驱动实现对多个LED的驱动【只是假想对LED进行驱动,并没有实际的硬件操作】
完整源代码
设备树文件swh_led.dts
#define GROUP_PIN(g,p) ((g<<16) | (p))
/ {
swh_led@0 {
compatible = "swh_leddrv";
pin = <GROUP_PIN(3, 1)>;
};
swh_led@1 {
compatible = "swh_leddrv";
pin = <GROUP_PIN(5, 8)>;
};
};
Platform总线设备驱动的驱动部分(chip_demo_gpio.c)
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include "led_opr.h"
#include "leddrv.h"
#include "led_resource.h"
static int g_ledpins[100];
static int g_ledcnt = 0;
static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */
{
//printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which);
printk("init gpio: group %d, pin %d\n", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));
switch(GROUP(g_ledpins[which]))
{
case 0:
{
printk("init pin of group 0 ...\n");
break;
}
case 1:
{
printk("init pin of group 1 ...\n");
break;
}
case 2:
{
printk("init pin of group 2 ...\n");
break;
}
case 3:
{
printk("init pin of group 3 ...\n");
break;
}
}
return 0;
}
static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
{
//printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off");
printk("set led %s: group %d, pin %d\n", status ? "on" : "off", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));
switch(GROUP(g_ledpins[which]))
{
case 0:
{
printk("set pin of group 0 ...\n");
break;
}
case 1:
{
printk("set pin of group 1 ...\n");
break;
}
case 2:
{
printk("set pin of group 2 ...\n");
break;
}
case 3:
{
printk("set pin of group 3 ...\n");
break;
}
}
return 0;
}
static struct led_operations board_demo_led_opr = {
.init = board_demo_led_init,
.ctl = board_demo_led_ctl,
};
static int chip_demo_gpio_probe(struct platform_device *pdev)
{
struct device_node *np;