目录
在设备树中如何获取到寄存器的值呢,linux提供了几个函数,在 include/linux/of.h 中
都是以 of 开头的
device_node结构体
设备都是以节点的形式“挂”到设备树上的,因此要想获取这个设备的其他属性信息,必须先获取到这个设备的节点。Linux 内核使用 device_node 结构体来描述一个节点,此结构体定义在文件 include/linux/of.h 中,定义如下
struct device_node{
const char *name;//节点名字
const char *type;//设备类型
phandle phandle;
const char *full_name;//节点全名
struct fwnode_handle fwnode;
struct property *properties;//属性
struct property *deadprops;//removed属性
struct device_node *parent;//父节点
struct device_node *child;//子节点
struct device_node *sibling;
struct kobject kobj;
unsigned long_flags;
void *data;
#if defined(CONFIG_SPACE)
const char *path_component_name;
unsigned int unique_id;
struct of_irg_controller *irg_trans;
#endif
}
property结构体
节点的属性信息里面保存了驱动所需要的内容,因此对于属性值的提取非常重要,Linux内核中使用结构体 property 表示属性,此结构体同样定义在文件 include/linux/of.h 中,内容如下:
struct property{
char *name;//属性名字
int length;//属性长度
void *value;//属性值
struct property *next;//下一个属性
unsigned long_flags;
unsigned int unique_id;
struct bin_attribute attr;
}
获取设备树节点里面的资源步骤
- 查找我们要找的节点
- 获取我们需要的属性
函数
of_find_node_by_path函数
- 作用:函数通过路径来查找指定的节点
- 原型
inline struct device_node *of_find_node_by_path(const char *path)
- 参数
- path:带有全路径的节点名,可以使用节点的别名
- 返回值:返回找到的节点,失败返回NULL
of_get_parent函数
- 作用:用于获取指定节点的父节点
- 原型
struct device_node *of_get_parent(const struct device_node *node)
- 参数
- node:要查找的父节点的节点
- 返回值:找到的父节点
of_get_next_child函数
- 作用:用迭代的方式查找子节点
- 原型
struct device_node *of_get_next_child(const struct device_node *node,struct device_node *prev)
- 参数
- node:要查找的父节点的节点
- prev:前一个子节点,
- 返回值:找到的父节点
of_property_read_uX函数
X可以为8,16,32,64
- 作用:分别读取u8,u16,u32,u64类型的属性值
- 原型
int of_property_read_u8(const struct device_node *np,const char *propname,u8 *out_value)
int of_property_read_u16(const struct device_node *np,const char *propname,u16 *out_value)
int of_property_read_u32(const struct device_node *np,const char *propname,u32 *out_value)
int of_property_read_u64(const struct device_node *np,const char *propname,u64 *out_value)
- 参数
- np:设备节点
- proname:要读取的属性名字
- out_vlaue:读取到的数组值
- 返回值:0读取成功,负数读取失败
of_property_read_uX_array函数
X可以为8,16,32,64
- 作用:分别读取属性中的数组数据
- 原型
int of_property_read_u8_array(const struct device_node *np,const char *propname,u8 *out_values,size_t sz) int of_property_read_u16_array(const struct device_node *np,const char *propname,u16 *out_values,size_t sz) int of_property_read_u32_array(const struct device_node *np,const char *propname,u32 *out_values,size_t sz) int of_property_read_u64_array(const struct device_node *np,const char *propname,u64 *out_values,size_t sz)
- 参数
- np:设备节点
- proname:要读取的属性名字
- out_vlaue:读取到的数组值
- sz:读取数组的元素数量
- 返回值:0读取成功,负数读取失败
of_property_read_string函数
- 作用:获取属性中字符串值
- 原型
int of_property_read_string(struct device_node *np,const char *propname,const char **out_string)
- 参数
- np:设备节点
- proname:读取的属性名字
- out_string:读取到的字符串
- 返回值:0读取成功,负数读取失败
of_get_named_gpio函数
- 作用:此函数获取 GPIO 编号,因为 Linux 内核中关于 GPIO 的 API函数都要使用 GPIO 编号,此函数会将设备树中类似<&gpio1 3 GPIO_ACTIVE_LOW>的属性信息转换为对应的GPIO 编号(后面第19章节会用到)
- 原型
int of_get_named_gpio(struct device_node *np,const char *propname,int index)
- 参数
- np:设备节点
- propname:包含要获取 GPIO 信息的属性名
- index:因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个 GPIO 的编号,如果只有一个 GPIO 信息的话此参数为 0。
- 返回值:成功返回到的 GPIO 编号,失败返回一个负数。
实例
在linux驱动:(16)在设备树添加自定义节点中我们写了一个自定义节点
读取节点的名称
- 新建一个结构体指针来存放我们获取到的节点信息
- 用of_find_node_by_path函数查找路径下的节点保存到结构体里
- 输出出来
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
struct device_node *test_device_node;
static int driver_inti(void)
{
printk("driver hello \n");
//获取节点的名称
test_device_node = of_find_node_by_path("/test");
if (test_device_node==NULL)
{
printk("of_find_node_by_path error \n");
return -1;
}
printk("test_device_node is %s\n",test_device_node->name);
return 0;
}
static void driver_exit(void)
{
printk("byb byb \n");
}
module_init(driver_inti);
module_init(driver_exit);
MODULE_LICENSE("GPL");
编译成ko,然后放到开发板中加载,就可以打印出test节点的名称
读取节点的compatible属性(u32)
- 定义属性结构体
- 调用函数获取
- 打印属性的名字和数据
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
int size;
struct device_node *test_device_node;
struct property *test_node_property;
static int driver_inti(void)
{
printk("driver hello \n");
//获取节点的名称
test_device_node = of_find_node_by_path("/test");
if (test_device_node==NULL)
{
printk("of_find_node_by_path error \n");
return -1;
}
printk("test_device_node is %s\n",test_device_node->name);
//读取节点的compatible属性
test_node_property = of_find_property(test_device_node,"compatible",&size);
if (test_node_property==NULL)
{
printk("of_find_property error \n");
return -1;
}
printk("of_find_property is %s\n",test_node_property->name);
printk("compatible is %s\n",(char *)test_node_property->value);
return 0;
}
static void driver_exit(void)
{
printk("byb byb \n");
}
module_init(driver_inti);
module_init(driver_exit);
MODULE_LICENSE("GPL");
编译成ko,然后放到开发板中加载,就可以打印出test节点的名称和compatible属性和compatible属性的值
读取节点的reg属性(u32数组)
- 定义u32位的数组,因为reg属性我们定义的是32位,数组长度为2
- 调用函数来获取到数据放到数组中
- 打印
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
int size;
u32 out_value[2]={0};
struct device_node *test_device_node;
struct property *test_node_property;
static int driver_inti(void)
{
printk("driver hello \n");
//获取节点的名称
test_device_node = of_find_node_by_path("/test");
if (test_device_node==NULL)
{
printk("of_find_node_by_path error \n");
return -1;
}
printk("test_device_node is %s\n",test_device_node->name);
//读取节点的compatible属性
test_node_property = of_find_property(test_device_node,"compatible",&size);
if (test_node_property==NULL)
{
printk("of_find_property error \n");
return -1;
}
printk("of_find_property is %s\n",test_node_property->name);
printk("compatible is %s\n",(char *)test_node_property->value);
//读取节点的 reg 属性
int ret;
ret = of_property_read_u32_array(test_device_node,"reg",out_value,2);
if (ret < 0)
{
printk("of_property_read_u32_array error \n");
return -1;
}
printk("out_value[0] is 0x%08x\n",out_value[0]);
printk("out_value[1] is 0x%08x\n",out_value[1]);
return 0;
}
static void driver_exit(void)
{
printk("byb byb \n");
}
module_init(driver_inti);
module_init(driver_exit);
MODULE_LICENSE("GPL");
编译成ko,然后放到开发板中加载,就可以打印出test节点的名称和compatible属性和compatible属性的值,并输出reg中的两个值
读取节点的ststus属性(字符串)
- 定义字符串指针
- 调用函数获取属性的值放到指针里
- 打印
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
int size;
u32 out_value[2]={0};
const char* str;
struct device_node *test_device_node;
struct property *test_node_property;
static int driver_inti(void)
{
printk("driver hello \n");
//获取节点的名称
test_device_node = of_find_node_by_path("/test");
if (test_device_node==NULL)
{
printk("of_find_node_by_path error \n");
return -1;
}
printk("test_device_node is %s\n",test_device_node->name);
//读取节点的compatible属性
test_node_property = of_find_property(test_device_node,"compatible",&size);
if (test_node_property==NULL)
{
printk("of_find_property error \n");
return -1;
}
printk("of_find_property is %s\n",test_node_property->name);
printk("compatible is %s\n",(char *)test_node_property->value);
//读取节点的 reg 属性
int ret;
ret = of_property_read_u32_array(test_device_node,"reg",out_value,2);
if (ret < 0)
{
printk("of_property_read_u32_array error \n");
return -1;
}
printk("out_value[0] is 0x%08x\n",out_value[0]);
printk("out_value[1] is 0x%08x\n",out_value[1]);
//读取节点的 status 属性
ret = of_property_read_string(test_device_node,"status",&str);
if (ret < 0)
{
printk("of_property_read_string error \n");
return -1;
}
printk("of_property_read_string is &s\n",str);
return 0;
}
static void driver_exit(void)
{
printk("byb byb \n");
}
module_init(driver_inti);
module_init(driver_exit);
MODULE_LICENSE("GPL");
编译成ko,然后放到开发板中加载,就可以打印出test节点的名称和compatible属性和compatible属性的值,并输出reg中的两个值,并输出status属性的值