云计算百科
云计算领域专业知识百科平台

设备树学习5--读写实操

实现一个驱动读取自己定义的设备树

1 设备树读写接口

头文件

#include <linux/of.h> //节点、属性基础接口
#include <linux/of_address.h> //reg物理地址
#include <linux/of_irq.h> //中断
#include <linux/of_gpio.h> //GPIO
#include <linux/of_clk.h> //时钟
#include <linux/of_pinctrl.h> //引脚配置
#include <linux/of_property.h>

查找/遍历设备节点

接口功能说明
of_find_node_by_path() 按照设备树全路径查找节点
of_find_node_by_name() 按节点 name 查找
of_find_node_by_type() 按 device‑type 属性查找
of_find_compatible_node() 根据 compatible 匹配节点
of_get_child_by_name() 获取指定名字的子节点
of_next_child_node() 循环遍历所有子节点
of_node_put() 节点引用计数释放(查到节点必须调用)
of_device_is_available() 判断节点 status = "okay" 是否启用

读取节点属性(最常用)

接口用途
of_property_read_bool(node, "xxx") 布尔属性,存在即返回 true
of_property_read_u8() 读取 uint8 属性
of_property_read_u16() 读取 uint16
of_property_read_u32() 读取单个 32 位整型
of_property_read_u64() 读取 64 位整型
of_property_read_u32_array() 读取 u32 数组
of_property_read_string() 读取字符串属性
of_property_read_string_array() 读取字符串数组
of_property_match_string() 匹配字符串列表索引
of_find_property() 获取 property 原始结构体

reg物理内存地址操作

接口作用
of_address_to_resource() reg 转为 struct‑resource
of_iomap() 物理地址映射成内核虚拟地址
of_iounmap() 解除地址映射
of_address_in_resource() 检查地址是否落在 reg 区间

中断资源

接口说明
irq_of_parse_and_map() 解析 interrupts 属性、映射中断号
of_irq_get() 获取节点第 n 个中断
of_irq_to_resource() 中断转为 resource 结构体

phandle引用节点

接口说明
of_parse_phandle() 解析 phandle,拿到被引用节点
of_parse_phandle_with_args() 解析带参数的 phandle(中断控制器常用)

此外还有一些,就不全部列了。。

2 一个例子

实验是基于树莓派,主要是环境方便。

2.1 设备树

/*
* Custom Device Tree Overlay for Raspberry Pi DT experiment
* Defines a platform device node "tom,mydevice" with various property
* types that a driver can parse: string, u32 array, u64, GPIO, IRQ, clock.
*/

/dts-v1/;
/plugin/;

/ {
compatible = "brcm,bcm2712";

fragment@0 {
target-path = "/";
__overlay__ {
tom_mydevice: tom,mydevice {
compatible = "tom,mydevice";
status = "okay";

/* string properties */
device-name = "tom-demo-device";
description = "A demo DT node for parsing practice";

/* u32 scalar */
version = <0x00010002>;

/* u32 array */
channel-ids = <1 2 3 4 8>;

/* u64 (as two 32-bit cells, big-endian) */
big-counter = <0x00000001 0x11223344>;

/* GPIO pin number (real BCM GPIO 17) */
led-gpio = <&gpio 17 0>;

/* GPIO handled via gpios prop */
gpios = <&gpio 22 0>, <&gpio 23 0>;

/* interrupts on a free IRQ line (10) */
interrupts = <10>;
interrupt-parent = <&gpio>;

/* clock reference: use the system's 108M clock */
clocks = <&clk_108MHz>;
clock-names = "sysclk";

/* child node for nested parsing demo */
child-config {
#address-cells = <1>;
#size-cells = <1>;
label = "child-1";
reg = <0x0 0x1000>;
};
};
};
};

__overrides__ {
mydevice-enabled = <&tom_mydevice>,"status";
};
};

2.2 驱动

// tom_device_driver.c
// Platform driver that parses properties from the "tom,mydevice"
// device tree node defined in tom-device.dts overlay.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/clk.h>
#include <linux/gpio/consumer.h>

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Tom");
MODULE_DESCRIPTION("Parse custom device tree properties");

static int tom_device_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
const char *name, *desc;
u32 version;
u32 channels[8];
int nch, i;
u64 big_counter;
u32 counter_hi, counter_lo;
int gpio_led, ret;
struct gpio_desc *led_gpio;
struct clk *clk;

dev_info(dev, "=== Tom Device DT probe ===\\n");
if (!np) {
dev_err(dev, "No OF node!\\n");
return -ENODEV;
}
dev_info(dev, "OF node full name: %s\\n", np->full_name);

/* 1. String properties */
ret = of_property_read_string(np, "device-name", &name);
if (!ret)
dev_info(dev, "device-name = %s\\n", name);
else
dev_err(dev, "read device-name failed: %d\\n", ret);

ret = of_property_read_string(np, "description", &desc);
if (!ret)
dev_info(dev, "description = %s\\n", desc);

/* 2. u32 scalar */
ret = of_property_read_u32(np, "version", &version);
if (!ret)
dev_info(dev, "version = 0x%08x (%u)\\n", version, version);

/* 3. u32 array */
nch = of_property_read_variable_u32_array(np, "channel-ids", channels,
0, ARRAY_SIZE(channels));
if (nch > 0) {
dev_info(dev, "channel-ids count = %d:", nch);
for (i = 0; i < nch; i++)
pr_cont(" %u", channels[i]);
pr_cont("\\n");
} else {
dev_err(dev, "read channel-ids failed: %d\\n", nch);
}

/* 4. u64 property (two cells) */
ret = of_property_read_u32_index(np, "big-counter", 0, &counter_hi);
if (ret == 0)
ret = of_property_read_u32_index(np, "big-counter", 1, &counter_lo);
if (!ret) {
big_counter = ((u64)counter_hi << 32) | counter_lo;
dev_info(dev, "big-counter = 0x%016llx\\n", big_counter);
} else {
dev_err(dev, "read big-counter failed: %d\\n", ret);
}

/* 5. GPIO via of_get_named_gpio */
gpio_led = of_get_named_gpio(np, "led-gpio", 0);
if (gpio_is_valid(gpio_led))
dev_info(dev, "led-gpio = GPIO %d\\n", gpio_led);
else
dev_err(dev, "led-gpio invalid: %d\\n", gpio_led);

/* 6. GPIO via devm_gpiod_get_optional (gpios property) */
led_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_ASIS);
if (IS_ERR(led_gpio)) {
dev_err(dev, "gpiod get failed: %ld\\n", PTR_ERR(led_gpio));
} else if (led_gpio) {
int gpionum = desc_to_gpio(led_gpio);
dev_info(dev, "gpios[0] desc -> GPIO %d\\n", gpionum);
} else {
dev_info(dev, "no gpios property found\\n");
}

/* 7. Interrupt */
{
int irq = of_irq_get(np, 0);
if (irq >= 0)
dev_info(dev, "interrupts[0] -> irq = %d\\n", irq);
else
dev_info(dev, "no irq (%d)\\n", irq);
}

/* 8. Clock */
clk = devm_clk_get(dev, "sysclk");
if (IS_ERR(clk)) {
dev_info(dev, "clock sysclk not available: %ld\\n", PTR_ERR(clk));
} else {
unsigned long rate = clk_get_rate(clk);
dev_info(dev, "clock sysclk rate = %lu Hz\\n", rate);
}

/* 9. Child node */
{
struct device_node *child;
child = of_get_child_by_name(np, "child-config");
if (child) {
const char *clabel;
u32 caddr;
if (!of_property_read_string(child, "label", &clabel))
dev_info(dev, "child-config label = %s\\n", clabel);
if (!of_property_read_u32_index(child, "reg", 1, &caddr))
dev_info(dev, "child-config reg[1] = 0x%x\\n", caddr);
of_node_put(child);
} else {
dev_info(dev, "no child-config node\\n");
}
}

/* 10. Show full raw property dump via /sys nodes */
dev_info(dev, "=== probe complete ===\\n");
return 0;
}

static void tom_device_remove(struct platform_device *pdev)
{
dev_info(&pdev->dev, "Tom device removed\\n");
}

static const struct of_device_id tom_device_of_match[] = {
{ .compatible = "tom,mydevice" },
{ }
};
MODULE_DEVICE_TABLE(of, tom_device_of_match);

static struct platform_driver tom_device_driver = {
.probe = tom_device_probe,
.remove = tom_device_remove,
.driver = {
.name = "tom_device",
.of_match_table = tom_device_of_match,
},
};

module_platform_driver(tom_device_driver);

2.3 运行

运行方法:

编译:dtc -@ -I dts -O dtb -o tom-device.dtbo tom-device.dts(-@ 保留符号)。

之后编译驱动并insmod。

运行结果:

tom_device tom,mydevice: device-name = tom-demo-device
tom_device tom,mydevice: description = A demo DT node for parsing practice
tom_device tom,mydevice: version = 0x00010002 (65538)
tom_device tom,mydevice: channel-ids count = 5:
tom_device tom,mydevice: big-counter = 0x0000000111223344
tom_device tom,mydevice: led-gpio = GPIO 588
tom_device tom,mydevice: gpios[0] desc -> GPIO 593
tom_device tom,mydevice: no irq (-75)
tom_device tom,mydevice: clock sysclk rate = 108000000 Hz
tom_device tom,mydevice: child-config label = child-1
tom_device tom,mydevice: child-config reg[1] = 0x1000

赞(0)
未经允许不得转载:网硕互联帮助中心 » 设备树学习5--读写实操
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!