linux驱动获取dts属性

引入:

设备树描述了设备的详细信息,这些信息包括数字类型的、字符串类型的、数组类型的,我们在编写驱动的时候需要获取到这些信息。

Linux 内核给我们提供了一系列的函数来获取设备树中的节点或者属性信息,这一系列的函数都有一个统一的前缀“of_”,所以在很多资料里面也被叫做 OF 函数。这些 OF 函数原型都定义在 include/linux/of.h 文件中。

一、查找结点函数:

1.of_find_node_by_name函数通过节点名字查找指定的节点,函数原型如下:

struct device_node *of_find_node_by_name(struct device_node *from,const char *name);

from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
name:要查找的节点名字。
返回值:找到的节点,如果为 NULL 表示查找失败。

2.of_find_node_by_type 函数通过 device_type 属性查找指定的节点,函数原型如下

struct device_node *of_find_node_by_type(struct device_node *from, const char *type)

from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
type:要查找的节点对应的 type 字符串,也就是 device_type 属性值。
返回值:找到的节点,如果为 NULL 表示查找失败。

3.of_find_matching_node_and_match 函数通过 of_device_id 匹配表来查找指定的节点,函数原型如下

struct device_node *of_find_matching_node_and_match(struct device_node *from,
                                                                                           const struct of_device_id *matches,
                                                                                           const struct of_device_id **match)

from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
matches:of_device_id 匹配表,也就是在此匹配表里面查找节点。
match :找到的匹配的 of_device_id。
返回值:找到的节点,如果为 NULL 表示查找失败

4.of_find_compatible_node 函数根据 device_type 和 compatible 这两个属性查找指定的节点

struct device_node *of_find_compatible_node(struct device_node *from,
                                                                          const char *type,
                                                                          const char *compatible)

from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
type:要查找的节点对应的 type 字符串,也就是 device_type 属性值,可以为 NULL,表示
忽略掉 device_type 属性。
compatible :要查找的节点所对应的 compatible 属性列表。

5.of_find_node_by_path 函数通过路径来查找指定的节点,函数原型如下:

inline struct device_node *of_find_node_by_path(const char *path)
函数参数和返回值含义如下:
path:带有全路径的节点名,可以使用节点的别名,比如“/backlight”就是 backlight 这个
节点的全路径。
返回值:找到的节点,如果为 NULL 表示查找失败

二、查找父/ 子节点的 OF  函数

1.of_get_parent 

用于获取指定节点的父节点(如果有父节点的话),函数原型如下:

struct device_node *of_get_parent(const struct device_node *node)

node:要查找的父节点的节点。
返回值:找到的父节点

2.of_get_next_child  

用迭代的查找子节点,函数原型如下:

struct device_node *of_get_next_child(const struct device_node *node,struct device_node *prev)

node:父节点。
prev:前一个子节点,也就是从哪一个子节点开始迭代的查找下一个子节点。可以设置为
NULL,表示从第一个子节点开始。
返回值:找到的下一个子节点。

三、提取属性值的 OF 

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;
 };

1.of_find_property

用于查找指定的属性

property *of_find_property(const struct device_node *np,
                                           const char *name,
                                           int *lenp)

np:设备节点。
name: 属性名字。
lenp:属性值的字节数
返回值:找到的属性。

2.of_property_count_elems_of_size

用于获取属性中元素的数量,比如 reg 属性值是一个数组,那么使用此函数可以获取到这个数组的大小,此函数原型如下:

int of_property_count_elems_of_size(const struct device_node *np,
                                                            const char *propname,

                                                             int elem_size)

np:设备节点。
proname: 需要统计元素数量的属性名字。
elem_size:元素长度。

3.of_property_read_u32_index

用于从属性中获取指定标号的 u32 类型数据值(无符号 32位),比如某个属性有多个 u32 类型的值,那么就可以使用此函数来获取指定标号的数据值,此函数原型如下:

int of_property_read_u32_index(const struct device_node *np,
                                                    const char *propname,
                                                    u32  index,
                                                    u32 *out_value)

np:设备节点。
proname: 要读取的属性名字。
index:要读取的值标号。
out_value:读取到的值
返回值:0 读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有
要读取的数据,-EOVERFLOW 表示属性值列表太小。

4.of_property_read_u8_array  
of_property_read_u16_array  
of_property_read_u32_array  
of_property_read_u64_array  

这 4 个函数分别是读取属性中 u8、u16、u32 和 u64 类型的数组数据,比如大多数的 reg 属性都是数组数据,可以使用这 4 个函数一次读取出 reg 属性中的所有数据。这四个函数的原型如下:

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_value:读取到的数组值,分别为 u8、u16、u32 和 u64。
sz :要读取的数组元素数量。
返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没
有要读取的数据,-EOVERFLOW 表示属性值列表太小。

5.of_property_read_u8 
of_property_read_u16 
of_property_read_u32  
of_property_read_u64 

有些属性只有一个整形值,这四个函数就是用于读取这种只有一个整形值的属性,分别用于读取 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_value:读取到的数组值。
返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没
有要读取的数据,-EOVERFLOW 表示属性值列表太小。

6.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,读取成功,负值,读取失败。

7.of_n_addr_cells

用于获取#address-cells 属性值,函数原型如下:

int of_n_addr_cells(struct device_node *np)
np:设备节点。
返回值:获取到的#address-cells 属性值。

8.of_n_size_cells

 函数用于获取#size-cells 属性值,函数原型如下:

int of_n_size_cells(struct device_node *np)

np:设备节点。
返回值:获取到的#size-cells 属性值。

四、其他常用的 OF 函数

1.of_device_is_compatible

用于查看节点的 compatible 属性是否有包含 compat 指定的字符串,也就是检查设备节点的兼容性,函数原型如下:

int of_device_is_compatible(const struct device_node *device,
                                              const char *compat)

device:设备节点。
compat:要查看的字符串。
返回值:0,节点的 compatible 属性中包含 compat 指定的字符串;其他值,节点的 compatible
属性中不包含 compat 指定的字符串。

2.of_get_address

用于获取地址相关属性,主要是“reg”或者“assigned-addresses”属性值,函数属性如下:

const __be32 *of_get_address(struct device_node *dev,
                                                  int index,
                                                  u64 *size,
                                                  unsigned int *flags)

dev:设备节点。
index:要读取的地址标号。
size:地址长度。
flags:参数,比如 IORESOURCE_IO、IORESOURCE_MEM 等
返回值:读取到的地址数据首地址,为 NULL 的话表示读取失败。

3.of_translate_address

负责将从设备树读取到的地址转换为物理地址,函数原型如下:

u64 of_translate_address(struct device_node *dev,const __be32 *in_addr)

dev:设备节点。
in_addr:要转换的地址。
返回值:得到的物理地址,如果为 OF_BAD_ADDR 的话表示转换失败。

4.of_address_to_resource

IIC、SPI、GPIO 等这些外设都有对应的寄存器,这些寄存器其实就是一组内存空间,Linux内核使用 resource 结构体来描述一段内存空间, “resource”翻译出来就是“资源”,因此用 resource结构体描述的都是设备资源信息,resource 结构体定义在文件 include/linux/ioport.h 中,定义如下:

struct resource {
    resource_size_t start;
    resource_size_t end;
    const char *name;
    unsigned long flags;
    struct resource *parent, *sibling, *child;

};

对于 32 位的 SOC 来说,resource_size_t 是 u32 类型的。其中 start 表示开始地址,end 表示结束地址,name 是这个资源的名字,flags 是资源标志位,一般表示资源类型,可选的资源标志定义在文件 include/linux/ioport.h 中,如下所示:

大 家 一 般 最 常 见 的 资 源 标 志 就 是 IORESOURCE_MEM 、 IORESOURCE_REG 和IORESOURCE_IRQ 等。接下来我们回到 of_address_to_resource 函数,此函数看名字像是从设备树里面提取资源值,但是本质上就是将 reg 属性值,然后将其转换为 resource 结构体类型,函数原型如下所示

int of_address_to_resource(struct device_node  *dev,int index,struct resource *r)

dev:设备节点。
index:地址资源标号。
r:得到的 resource 类型的资源值。
返回值:0,成功;负值,失败。

5.of_iomap

of_iomap 函数用于直接内存映射,以前我们会通过 ioremap 函数来完成物理地址到虚拟地址的映射,采用设备树以后就可以直接通过 of_iomap 函数来获取内存地址所对应的虚拟地址,不需要使用 ioremap 函数了。当然了,你也可以使用 ioremap 函数来完成物理地址到虚拟地址的内存映射,只是在采用设备树以后,大部分的驱动都使用 of_iomap 函数了。of_iomap 函数本质上也是将 reg 属性中地址信息转换为虚拟地址,如果 reg 属性有多段的话,可以通过 index 参数指定要完成内存映射的是那一段,of_iomap 函数原型如下:

void __iomem *of_iomap(struct device_node *np,int index)

np:设备节点。
index:reg 属性中要完成内存映射的段,如果 reg 属性只有一段的话 index 就设置为 0。
返回值:经过内存映射后的虚拟内存首地址,如果为 NULL 的话表示内存映射失败。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,可以了解到在Linux驱动程序中,需要读取Linux内核中附带的dts文件,并操作设备树DTS的相关节点。同时,还提到了在MTK平台上分析Linux的i2c框架。 对于Linux的i2c设备树(DTS)操作,可以按照以下步骤进行: 1. 首先,需要在设备树中定义i2c控制器和i2c设备节点。在设备树中,使用`i2c`关键字来定义i2c控制器,使用`i2c_device`关键字来定义i2c设备。例如: ```dts i2c { compatible = "i2c"; #address-cells = <1>; #size-cells = <0>; i2c@0 { compatible = "i2c-device"; reg = <0>; // 其他属性 }; }; ``` 2. 在驱动程序中,可以使用`of_find_node_by_name()`函数来查找设备树中的节点。该函数接受一个参数,即节点名称,返回一个指向节点的指针。例如: ```c struct device_node *node; node = of_find_node_by_name(NULL, "i2c"); if (node) { // 找到了i2c节点 // 进行其他操作 } ``` 3. 通过节点指针,可以使用`of_property_read_u32()`函数来读取节点的属性值。该函数接受三个参数,分别是节点指针、属性名称和一个指向变量的指针,用于存储属性值。例如: ```c u32 value; if (of_property_read_u32(node, "reg", &value) == 0) { // 读取成功,可以使用value进行其他操作 } ``` 4. 可以使用`of_get_child_by_name()`函数来获取节点的子节点。该函数接受两个参数,分别是父节点指针和子节点名称,返回一个指向子节点的指针。例如: ```c struct device_node *child; child = of_get_child_by_name(node, "i2c@0"); if (child) { // 找到了子节点 // 进行其他操作 } ``` 5. 最后,记得在驱动程序中使用`of_node_put()`函数来释放节点指针。例如: ```c of_node_put(node); ``` 这样,就可以在Linux驱动程序中进行设备树节点的操作了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值