02、pinctrl子系统驱动代码
Linux的引脚控制系统(pinctrl)是管理硬件输入输出接口的工具。它让系统能统一设置、分配和操作硬件上的物理引脚,这样不同设备的输入输出控制就能更简单、统一。
一、pinctrl 设备树
设备树的pinctrl功能分为两部分:
客户端: 硬件驱动可以直接指定需要的引脚、引脚组以及配置参数(比如电平方向、电平强度等),就像点餐时选择具体需求一样。所有厂商的这种写法格式都统一,不需要改动。
服务端: 这是设备树里专门管理GPIO引脚的配置节点,类似于硬件的"配置手册"。它记录了每个引脚能实现哪些功能(比如普通IO、时钟信号等),以及对应的电气参数设置(如驱动电流、上下拉模式等)。硬件驱动调用时,系统会根据这里定义的规则来实际配置物理引脚。
简单来说:客户端提出需求,服务端提供具体实现方案。
目录:kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi
设备树中的pinctrl配置部分定义了RK3568芯片的5个GPIO控制器:gpio0、gpio1、gpio2、gpio3和gpio4。这些设置允许开发者在设备树文件中直接配置芯片的物理引脚功能,比如设置引脚的工作模式或配置中断功能。通过这些GPIO控制器节点,可以方便地控制芯片引脚的输入输出行为。
在设备树的最下方通过 include 包含了 rk3568-pinctrl.dtsi 设备树, 该设备树中包含了所有复用功能的配置, 具体内容如下所示:
设备树中与引脚控制相关的部分(如rk3568.dtsi里的pinctrl节点,以及rk3568-pinctrl.dtsi里的引脚复用配置)都是瑞芯微公司工程师预先编写好的,我们只需要学会如何调用这些配置即可。而针对具体硬件设备的引脚设置(比如某个芯片的GPIO功能定义),则需要根据实际需求自行编写对应的设备树节点。
设备树文件本身只是记录硬件信息的"说明书",具体功能实现需要依赖对应的驱动程序。通过查看rk3568设备树中pinctrl节点的compatible属性,可以在Linux内核源码中找到对应的驱动文件,路径通常是: drivers/pinctrl/pinctrl-rockchip.c
::: 简单来说:
硬件厂商提供基础引脚配置模板(类似 Lego 的标准积木)
开发者根据实际硬件需求,调用这些模板并补充自定义配置(像拼装 Lego 造出具体模型)
最终功能实现由内核中的驱动程序(相当于 Lego 的组装规则手册)来完成 :::
二、pinctrl 驱动
首先进入到内核源码目录下的“/drivers/pinctrl/pinctrl-rockchip.c” 驱动文件中, 找到驱动的入口函数, 具体内容如下所示:
可以看到 pinctrl 驱动使用的是 platform 总线, 当设备和驱动匹配成功之后会进入rockchip_pinctrl_probe 函数进行初始化, probe 函数的具体内容如下所示:
static int rockchip_pinctrl_probe(struct platform_device *pdev)
{
struct rockchip_pinctrl *info; // Rockchip GPIO 控制器的信息结构体指针
struct device *dev = &pdev->dev; // 设备结构体指针
struct rockchip_pin_ctrl *ctrl; // Rockchip GPIO 控制器的配置结构体指针
struct device_node *np = pdev->dev.of_node, *node; // 设备节点指针
struct resource *res;
void __iomem *base;
int ret;
if (!dev->of_node) {
dev_err(dev, "device tree node not found\n");
return -ENODEV;
}
// 分配并初始化一个 rockchip_pinctrl 结构体
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->dev = dev;
// 获取并设置与 pdev 相关的 rockchip_pin_ctrl 结构体
ctrl = rockchip_pinctrl_get_soc_data(info, pdev);
if (!ctrl) {
dev_err(dev, "driver data not available\n");
return -EINVAL;
}
info->ctrl = ctrl;
// 解析设备树中的"rockchip,grf"节点, 获取寄存器映射基地址
node = of_parse_phandle(np, "rockchip,grf", 0);
if (node) {
info->regmap_base = syscon_node_to_regmap(node);
if (IS_ERR(info->regmap_base))
return PTR_ERR(info->regmap_base);
} else {
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
rockchip_regmap_config.max_register = resource_size(res) - 4;
rockchip_regmap_config.name = "rockchip,pinctrl";
info->regmap_base = devm_regmap_init_mmio(&pdev->dev, base,
&rockchip_regmap_config);
/* to check for the old dt-bindings */
info->reg_size = resource_size(res);
/* Honor the old binding, with pull registers as 2nd resource */
if (ctrl->type == RK3188 && info->reg_size < 0x200) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
rockchip_regmap_config.max_register =
resource_size(res) - 4;
rockchip_regmap_config.name = "rockchip,pinctrl-pull";
info->regmap_pull = devm_regmap_init_mmio(&pdev->dev,
base,
&rockchip_regmap_config);
}
}
/* try to find the optional reference to the pmu syscon */
node = of_parse_phandle(np, "rockchip,pmu", 0);
if (node) {
info->regmap_pmu = syscon_node_to_regmap(node);
if (IS_ERR(info->regmap_pmu))
return PTR_ERR(info->regmap_pmu);
}
/* Special handle for some Socs */
if (ctrl->soc_data_init) {
ret = ctrl->soc_data_init(info);
if (ret)
return ret;
}
ret = rockchip_pinctrl_register(pdev, info);
if (ret)
return ret;
platform_set_drvdata(pdev, info);
ret = of_platform_populate(np, rockchip_bank_match, NULL, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to register gpio device\n");
return ret;
}
dev_info(dev, "probed %s\n", dev_name(dev));
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
上面 Probe 函数的作用是初始化和配置 Rockchip GPIO 控制器, 并将相关信息存储在rockchip_pinctrl 结构体中, 最后注册相关设备和GPIO 接口。