linux设备树常用of操作函数

本文详细介绍了Linux设备树中常用的GPIO相关及节点查找、属性提取等操作函数,包括of_gpio_count、of_get_named_gpio、of_find_node_by_name、of_property_read_u32等,这些函数对于理解和操作设备树至关重要。

linux设备树常用of操作函数

设备树描述了设备的详细信息,这些信息包括数字类型的、字符串类型的、数组类型的,这些信息一般通过of函数获取,这些of函数的原型大部分定义在include/linux/of.h文件中,其中GPIO相关的定义在include/inux/of_gpio.h中。

1、 GPIO相关

int of_gpio_named_count(struct device_node *np, const char *propname)

函数用于获取设备树某个属性里面定义了几个 GPIO信息,要注意的是空的 GPIO信息也会被统计到。
@np:设备节点。
@propname:要统计的 GPIO属性。
@返回值: 正值,统计到的 GPIO数量;负值,失败。

static inline int of_gpio_count(struct device_node *np)
{
	return of_gpio_named_count(np, "gpios");
}

和 of_gpio_named_count函数一样,但是不同的地方在于,此函数统计的是“ gpios”这个属性的 GPIO数量,而 of_gpio_named_count函数可以统计任意属性的 GPIO信息,
@np:设备节点。
@返回值: 正值,统计到的 GPIO数量;负值,失败。

static inline int of_get_named_gpio(struct device_node *np, const char *propname, int index)

@np: gpio所在的设备节点
@propname: gpio属性的名字
@index:gpio定义时的索引
@返回值:为用于gpio相关API的gpio号。

2、 查找节点

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

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

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

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

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

函数根据 device_type和 compatible这两个属性查找指定的节点,
@from:开始查找的节点,如果为 NULL表示从根节点开始查找整个设备树。
@type:要查找的节点对应的 type字符串,也就是 device_type属性值,可以为 NULL,表示忽略掉 device_type属性。
@compatible 要查找的节点所对应的 compatible属性列表。
@返回值: 找到的节点,如果为 NULL表示查找失败

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)

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

inline struct device_node *of_find_node_by_path(const char *path)

函数通过路径来查找指定的节点,函数原型如下:
@path:带有全路径的节点名,可以使用节点的别名,比如 “/backlight”就是 backlight这个
节点的全路径。
@返回值: 找到的节点,如果为 NULL表示查找失败

3、 查找父/子节点

struct device_node *of_get_parent(const struct device_node *node)

函数用于获取指定节点的父节点 (如果有父节点的话 )
@node:要查找的父节点的节点。
@返回值: 找到的父节点。

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

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

4、 提取属性值

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

函数用于查找指定的属性
@np:设备节点。
@name 属性名字。
@lenp:属性值的字节数
@返回值: 找到的属性。

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

函数用于从属性中获取指定标号的 u32类型数据值 (无符号 32位 ),比如某个属性有多个 u32类型的值,那么就可以使用此函数来获取指定标号的数据值。
@np:设备节点。
@proname 要读取的属性名字。
@index:要读取的值标号。
@out_value:读取到的值
@返回值: 0读取成功,负值,读取 失败, ,-EINVAL表示属性不存在, ,-ENODATA表示没有要读取的数据, -EOVERFLOW表示属性值列表太小。

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)

这 4个函数分别是读取属性中 u8、 u16、 u32和 u64类型的数组数据,比如大多数的 reg属性都是数组数据,可以使用这4个函数一次读取出 reg属性中的所有数据。
@np:设备节点。
@proname 要读取的属性名字。
@out_value:读取到的数组值,分别为 u8、 u16、 u32和 u64。
@sz 要读取的数组元素数量。
@返回值: 0,读取成功,负值,读取失败 ,-EINVAL表示属性不存在,-ENODATA表示没有要读取的数据,-EOVERFLOW表示属性值列表太小。

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)

有些属性只有一个整形值,这四个函数就是用于读取这种只有一个整形值的属性,分别用
于读取 u8、 u16、 u32和 u64类型属性值。
@np:设备节点。
@proname 要读取的属性名字。
@out_value:读取到的数组值。
@返回值:0,读取成功,负值,读取失败,-EINVAL表示属性不存在, -ENODATA表示没有要读取的数据,-EOVERFLOW表示属性值列表太小。

int of_property_read_string(struct device_node *np, const char *propname, const char **out_string)

函数用于读取属性中字符串值
@np:设备节点。
@proname 要读取的属性名字。
@out_string:读取到的字符串值。
@返回值: 0,读取成功,负值,读取失败。

int of_n_addr_cells(struct device_node *np)

函数用于获取 #address-cells属性值。
@np:设备节点。
@返回值:获取到的 #address-cells属性值。

int of_n_size_cells(struct device_node *np)

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

Linux 内核通过设备树(Device Tree)描述硬件配置,对于 GPIO 的获取也是基于这种机制完成初始化和引用的。下面将为你介绍如何从 Linux 设备树中获取 GPIO 节点信息。 ### 获取设备树节点的GPIO #### 主要API: 1. **`of_get_named_gpio()`** 这是一个常用的辅助宏,在驱动程序需要访问特定命名属性所指向的 GPIO 引脚时非常有用。它可以从给定的 device_node 中找到指定名字对应的 gpio,并将其转换为平台本地编号形式返回。 - 宏原型:`#define of_get_named_gpio(np, propname, index) ...` - `np`: 指向目标设备的 struct device_node * 类型指针; - `propname`: 字符串类型的属性名称,在 dts 文件里通常是 "gpios" 或者其他自定义的名字; - `index`: 当有多个同名项存在时用于索引的具体位置;如果只有一个则通常传入0即可。 2. **`devm_gpiod_get_from_of_node()`** 推荐使用的现代方法之一,能够帮助管理生命周期并且支持 devres 自动释放资源特性。此 API 可以直接接收 OF node 参数并解析出相应的 gpiod 描述符供后续操作使用。 - 函数原型: `struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev, struct device_node *node, const char *con_id, unsigned long flags, const char *label)` 3. **`of_property_read_u32_index()` + 手工映射** 对于一些较为简单的场景或是旧版兼容性考虑下可以选择这种方式读取原始数值再做额外处理得到实际可用的结果。 4. 示例代码片段: ```c #include <linux/of.h> #include <linux/gpio/consumer.h> static int my_driver_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; // 使用新推荐的方式 struct gpio_desc *desc; desc = devm_gpiod_get_from_of_node(dev, pdev->dev.of_node, NULL, 0 /* index */, GPIOD_IN, "my-gpio"); if (IS_ERR(desc)) { return PTR_ERR(desc); } } ``` 以上就是几种常见的 Linux 下根据 DeviceTree 来定位和控制 GPIO 的手段概述了。希望对您有所帮助!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值