// 遍历每个子节点,解析函数信息
for_each_child_of_node(np, child) {
// 如果节点不是函数节点,则继续下一个节点
if (!is_function_node(child))
continue;
// 解析函数信息并存储到 info 结构体中
ret = rockchip_pinctrl_parse_functions(child, info, i++);
if (ret) {
dev_err(&pdev->dev, "failed to parse function\n");
of_node_put(child);
return ret;
}
}
这段代码是 Linux 内核中 pinctrl 驱动解析设备树(Device Tree)函数节点的典型实现,用于提取硬件引脚功能配置。以下是逐层解析:
1. 代码功能概述
- 目标:遍历设备树中 pinctrl 控制器的子节点,识别并解析所有定义引脚功能的节点(如 UART、SPI、I2C 等)。
- 核心操作:
- 跳过非函数节点。
- 解析函数节点配置(如引脚组、复用设置)。
- 存储解析结果到驱动私有数据结构
info。 - 错误处理(如节点解析失败)。
2. 关键代码逻辑
2.1 遍历子节点
for_each_child_of_node(np, child) {
// ...
}
- 作用:遍历设备树节点
np的所有子节点(child)。 - 典型场景:
np是 pinctrl 控制器的设备树节点(如rockchip,pinctrl),其子节点定义具体功能(如uart0_pins、spi1_pins)。
2.2 过滤函数节点
if (!is_function_node(child))
continue;
is_function_node函数:- 判断子节点是否为函数节点(Function Node)。
- 常见实现:检查节点名称是否以
"functions"开头,或是否有特定属性(如function = "uart")。 - 示例设备树片段:
pinctrl_example: pinctrl@ff770000 { compatible = "rockchip,pinctrl"; // 子节点定义具体功能 uart0_pins: uart0-pins { rockchip,function = "uart0"; rockchip,pins = <PINMUX_GPIO0_A0>; }; };
2.3 解析函数节点
ret = rockchip_pinctrl_parse_functions(child, info, i++);
rockchip_pinctrl_parse_functions函数:- 输入:当前子节点
child、驱动私有数据info、当前函数索引i。 - 操作:
- 读取节点属性(如
rockchip,function、rockchip,pins)。 - 解析引脚组(Pin Group)和复用配置。
- 将配置存储到
info->functions[i]数组中。
- 读取节点属性(如
- 示例解析逻辑:
// 解析函数名称 of_property_read_string(child, "rockchip,function", &func_name); // 解析关联的引脚组 of_property_read_u32_array(child, "rockchip,pins", pins, num_pins); // 存储到 info 结构体 info->functions[i].name = func_name; info->functions[i].pins = pins;
- 输入:当前子节点
2.4 错误处理
if (ret) {
dev_err(&pdev->dev, "failed to parse function\n");
of_node_put(child);
return ret;
}
- 释放资源:
of_node_put(child)减少设备树节点的引用计数,避免内存泄漏。 - 错误传播:返回错误码,终止驱动初始化。
3. 数据结构关联
3.1 info 结构体
- 定义:存储 pinctrl 控制器的配置信息(如支持的功能、引脚组)。
- 典型字段:
struct rockchip_pinctrl_info { struct pinctrl_desc pctl_desc; struct rockchip_pin_bank *banks; struct rockchip_pin_function *functions; int num_functions; // ... }; functions数组:存储解析后的所有函数配置,索引由i指定。
3.2 函数节点与驱动的关联
- 设备树到驱动的映射:
- 设备树中的每个函数节点(如
uart0_pins)对应驱动中的一个struct rockchip_pin_function。 - 驱动通过
info->functions数组管理所有可用功能,供后续引脚复用配置使用。
- 设备树中的每个函数节点(如
4. 实际应用场景
4.1 驱动初始化阶段
probe函数:在设备绑定时调用,完成硬件配置的初始化。- 流程示例:
- 解析设备树根节点(
np)。 - 遍历子节点,提取所有函数配置。
- 注册 pinctrl 设备(
pinctrl_register)。
- 解析设备树根节点(
4.2 运行时配置
- 引脚复用:通过
pinctrl_select_state选择预定义的函数配置。// 选择 uart0 功能 pinctrl_state = pinctrl_lookup_state(pctldev, "uart0"); pinctrl_select_state(pctldev, pinctrl_state);
5. 代码设计意图
- 硬件抽象:通过设备树描述硬件功能,驱动代码与具体芯片解耦。
- 可扩展性:新增功能只需修改设备树,无需修改驱动代码。
- 错误安全:严格检查解析结果,避免无效配置导致系统不稳定。
总结
这段代码是 pinctrl 驱动中设备树解析的核心部分,通过遍历和解析函数节点,将硬件引脚功能配置抽象为驱动可用的数据结构,实现了:
- 硬件配置的灵活管理:通过设备树动态定义功能,适应不同硬件变体。
- 驱动与硬件的解耦:驱动代码不依赖具体芯片,提升可移植性。
- 错误早期发现:在初始化阶段验证配置有效性,减少运行时风险。
2474

被折叠的 条评论
为什么被折叠?



