设备树模型例子
嵌入式平台采用RK的,交叉编译工具链采用官方提供的交叉编译工具链。
1. 设备树文件
/ {
fake_device {
compatible = "fake_device";
data = <0x20>;
reg = <0x4a064000 0x800>;
reg-names = "fake_reg";
interrupts = <0 30 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "fake_interrput";
string-property = "i am string";
int-property = <0x33>;
bool-property;
fake_child {
read_only;
myname = "private";
offset = <0>;
size = <1024>;
};
};
};
2. 驱动文件
device_tree.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
static int my_pdrv_probe (struct platform_device *pdev)
{
int data = 0;
struct resource *res;
int irq = 0;
char my_string[64] = {0};
const char *ps = my_string;
int my_int = 0,size,offset;
bool my_bool = false;
struct device_node *np, *sub_np;
/* registor */
res = platform_get_resource_byname(pdev,IORESOURCE_MEM, "fake_reg");
of_property_read_s32(pdev->dev.of_node, "data", &data);
pr_info("data 0x%02x reg_name[%s] reg_start[%x] reg_end[%x]\n", data, res->name,res->start,res->end);
/* interrput */
irq = platform_get_irq_byname(pdev, "fake_interrput");
pr_info("irq %d \n",irq);
/* property */
of_property_read_string(pdev->dev.of_node,"string-property", &ps);
pr_info("string %s \n",my_string);
of_property_read_s32(pdev->dev.of_node, "int-property", &my_int);
pr_info("int 0x%02x \n",my_int);
my_bool = of_property_read_bool(pdev->dev.of_node, "bool-property");
if (my_bool)
{
pr_info("bool-property is true \n");
}
else
{
pr_info("bool-property is false \n");
}
/* sub_node */
np = pdev->dev.of_node;
for_each_child_of_node(np, sub_np)
{
of_property_read_s32(sub_np, "size", &size);
of_property_read_s32(sub_np, "offset", &offset);
pr_info("sub_node size = %d offset = %d\n",size,offset);
}
pr_info("module loaded\n");
return 0;
}
static int my_pdrv_remove(struct platform_device *pdev)
{
pr_info("module Unloaded\n");
return 0;
}
static const struct of_device_id of_match_mypdrvs[] = {
{ .compatible = "fake_device", .data = NULL },
{ /* sentinel */ }
};
static struct platform_driver mypdrv = {
.probe = my_pdrv_probe,
.remove = my_pdrv_remove,
.driver = {
.name = "fake_device",
.owner = THIS_MODULE,
.of_match_table = of_match_mypdrvs,
},
};
module_platform_driver(mypdrv);
MODULE_AUTHOR("kingkim180");
MODULE_LICENSE("GPL");
3. Makefile
KERN_DIR = /opt/RV1126/kernel
all:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C $(KERN_DIR) M=$(shell pwd) modules
clean:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C $(KERN_DIR) M=$(shell pwd) clean
rm -rf modules.order ./*.ko ./*.o
obj-m += device_tree.o
4. 测试输出
root# insmod device_tree.ko
data 0x20 reg_name[fake_reg] reg_start[4a064000] reg_end[4a0647ff]
irq 75
string
int 0x33
bool-property is true
module loaded
sub_node size = 1024 offset = 0
加载驱动后内核自动识别到对应的compatible
值后调用probe函数,输出对应的打印信息,这里的string没有识别到,查看源码发现这个内核不支持解析设备树字符串类型这个接口,没有输出,中断的值也有些问题,暂时没有看是什么导致的,hexdump /proc/device_tree/fake_device/interrupts
查看值应该是对的,其他的值设置是正常的,通过设备树的方式就把用户自己设置的参数传递到驱动内部,从而同一厂商的多个芯片或者平台使用同一套的驱动程序。