01、pinctrl 子系统介绍
Linux的引脚控制子系统(pinctrl)是一个管理通用输入输出(GPIO)引脚的工具。它的主要作用是在系统中统一配置、分配和操作这些引脚,让不同硬件设备的GPIO功能能在内核里标准化地使用。这样既方便了硬件适配,也简化了开发者对硬件接口的控制流程。
一、什么是pinctrl 子系统
传统方法配置引脚需要手动调整寄存器设置,这种方式既繁琐又容易出错(比如引脚功能冲突)。为此,Linux内核专门开发了pinctrl子系统来简化操作。它的主要功能包括:
- 自动读取设备树中的引脚配置信息
- 根据配置信息自动设置引脚的复用功能(比如将GPIO设置为SPI模式)
- 自动配置引脚的电气参数(如电流强度、驱动能力等)
对于开发者来说,只需要在设备树文件里写好引脚的配置参数,剩下的所有初始化工作(如寄存器设置)都会由pinctrl子系统自动完成。该子系统的源代码位于Linux内核的drivers/pinctrl目录中。
这样改动后,开发者不用再直接操作硬件寄存器,配置过程变得更简单安全。
在 Pinctrl 子系统中, 有两个关键概念: 引脚组(groups) 和功能(function)。
1.1、引脚组(Groups)
引脚组是一组具有相似功能、 约束条件或共同工作的引脚的集合。 每个引脚组通常与特定的硬件功能或外设相关联。 例如, 一个引脚组可以用于控制串行通信接口(如 UART 或 SPI) ,另一个引脚组可以用于驱动 GPIO。
1.2、功能(Function)
定义了芯片上具有外设功能的功能。 每个功能节点对应于一个或多个 IO 组(group) 的配置信息。 这些功能可以是串口、 SPI、 I2C 等外设功能。
如下i2c3m0_xfer: I2C控制器的第一个引脚组, 用于配置I2C3 的引脚。
二、pinctrl 子系统目录结构
重点文件:
Makefile
pinconf.c: 对驱动能力、上下拉(底层就是SOC物理寄存器的操作)
pinmux.c:复用功能进行操作(底层就是SOC物理寄存器的操作)
三、rk3568 的 pinctrl 子系统驱动
设备树的 pinctrl可以分为生产者和消费者两个部分:
3.1、生产者
生产者:pinctrl 对 GPIO(复用功能、配置设置)
生产者是设备树中一个提供 GPIO 引脚配置的节点。它的作用是:
- 告诉系统每个 GPIO 引脚的具体用途
- 说明这个引脚需要切换成什么功能(比如是用作普通输入输出,还是连接摄像头、LED 等外设)
- 设置引脚的电气特性(比如电平高低、驱动电流大小等)
在 rk3568-pinctrl.dtsi
文件中,每个 GPIO 的配置会有三个核心内容:
- 哪个 GPIO 引脚被使用?(例如:GPIO3_7)
- 这个 GPIO 要切换成什么功能?(例如:复用为摄像头时钟信号,或普通输入功能)
- 这个 GPIO 的具体参数如何设置?(例如:输出模式、电压 3.3V、高电平有效)
3.2、消费者
在设备驱动配置中,pinctrl客户端可以通过指定引脚设置、引脚组合和功能配置来满足硬件需求。不同芯片厂商提供的配置文件虽然具体参数不同,但基本编写格式是统一的。例如对于I2C3控制器的配置,开发者只需按照标准格式填写需要使用的物理引脚、引脚组合以及工作模式等信息即可完成配置。
四、pinctrl 设备树
3532 pinctrl: pinctrl {
3533 compatible = "rockchip,rk3568-pinctrl";
3534 rockchip,grf = <&grf>;
3535 rockchip,pmu = <&pmugrf>;
3536 #address-cells = <2>;
3537 #size-cells = <2>;
3538 ranges;
3539
3540 gpio0: gpio@fdd60000 {
3541 compatible = "rockchip,gpio-bank";
3542 reg = <0x0 0xfdd60000 0x0 0x100>;
3543 interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
3544 clocks = <&pmucru PCLK_GPIO0>, <&pmucru DBCLK_GPIO0>;
3545
3546 gpio-controller;
3547 #gpio-cells = <2>;
3548 gpio-ranges = <&pinctrl 0 0 32>;
3549 interrupt-controller;
3550 #interrupt-cells = <2>;
3551 };
......
3604 };
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
在上面的 pinctrl 节点中, 描述了 RK3568 GPIO 控制器的配置和使用方式, pinctrl 节点总共描述了五个 GPIO 控制器, 分别是 gpio0、 gpio1、 gpio2、 gpio3 和 gpio4。 通过这些 GPIO 控制器节点, 可以在设备树中配置和控制 RK3568 芯片上的 GPIO 引脚, 包括设置引脚功能、 中断处理等。
在设备树的最下方通过 include 包含了 rk3568-pinctrl.dtsi 设备树, 该设备树中包含了所有复用功能的配置, 具体内容如下所示
13 &pinctrl {
14 acodec {
15 /omit-if-no-ref/
16 acodec_pins: acodec-pins {
17 rockchip,pins =
18 /* acodec_adc_sync */
19 <1 RK_PB1 5 &pcfg_pull_none>,
20 /* acodec_adcclk */
21 <1 RK_PA1 5 &pcfg_pull_none>,
22 /* acodec_adcdata */
23 <1 RK_PA0 5 &pcfg_pull_none>,
24 /* acodec_dac_datal */
25 <1 RK_PA7 5 &pcfg_pull_none>,
26 /* acodec_dac_datar */
27 <1 RK_PB0 5 &pcfg_pull_none>,
28 /* acodec_dacclk */
29 <1 RK_PA3 5 &pcfg_pull_none>,
30 /* acodec_dacsync */
31 <1 RK_PA5 5 &pcfg_pull_none>;
32 };
33 };
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
无论是 rk3568.dtsi 设备树中的 pinctrl 节点, 还是上面 rk3568-pinctrl.dtsi 设备树中的一系列复用关系都是由瑞芯微原厂 BSP 工程师编写的, 我们只需知道如何使用即可, 而 pinctrl 客户端设备树是由我们自己根据特定需求来编写的:
rockchip,pins = <PIN_BANK PIN_BANK_IDX MUX &phandle
4.1、PIN_BANK
PIN_BANK 就是 PIN 所属的组,RK3568 一共有 5 组 PIN:GPIO0~GPIO4
,分别对应 0~4,所以如果你要设置 GPIO0_C0
这个 PIN,那么 PIN_BANK 就是 0。
4.2、PIN_BANK_IDX
PIN_BANK_IDX
是组内的编号,以 GPIO0
组为例,一共有 A0~A7
、B0~B7
、C0~C7
、D0~D7
,这 32
个 PIN。瑞芯微已经给这些 PIN
编了号,打开 include/dt-bindings/pinctrl/rockchip.h
文件,有如下定义
28 #define RK_PA0 0
29 #define RK_PA1 1
30 #define RK_PA2 2
31 #define RK_PA3 3
32 #define RK_PA4 4
33 #define RK_PA5 5
......
54 #define RK_PD2 26
55 #define RK_PD3 27
56 #define RK_PD4 28
57 #define RK_PD5 29
58 #define RK_PD6 30
59 #define RK_PD7 31
2
3
4
5
6
7
8
9
10
11
12
13
如果要设置 GPIO0_C0,那么 PIN_BANK_IDX 就要设置为 RK_PC0。
4.3、MUX
MUX 就是设置 PIN 的复用功能,一个 PIN 最多有 16 个复用功能,include/dtbindings/pinctrl/rockchip.h 文件中有如下内容:
61 #define RK_FUNC_GPIO 0
62 #define RK_FUNC_0 0
63 #define RK_FUNC_1 1
64 #define RK_FUNC_2 2
65 #define RK_FUNC_3 3
66 #define RK_FUNC_4 4
67 #define RK_FUNC_5 5
68 #define RK_FUNC_6 6
69 #define RK_FUNC_7 7
70 #define RK_FUNC_8 8
71 #define RK_FUNC_9 9
72 #define RK_FUNC_10 10
73 #define RK_FUNC_11 11
74 #define RK_FUNC_12 12
75 #define RK_FUNC_13 13
76 #define RK_FUNC_14 14
77 #define RK_FUNC_15 15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
上面就是 16 个复用功能编号,以 GPIO0_C0 为例,查看 RK3568 数据手册,可以得到GPIO0_C0 复用情况如图:
从图 可以看出 GPIO3_D4 有 4 个复用功能: 0:GPIO0_C0 1:PWM1_M0 2:GPU_AVS 3:UART0_RX
如果要将 GPIO0_C0 设置为 GPIO 功能,那么 MUX 就设置 0,或者 RK_FUNC_GPIO。如果要设置为 PWM1_M0,那么 MUX 就设置为 1。
4.4、phandle
最后一个就是 phandle,用来描述一些引脚的通用配置信息,打开 scripts/dtc/includeprefixes/arm/rockchip-pinconf.dtsi 文件,此文件就是 phandle 可选的配置项,如下所示:
5 &pinctrl {
6
7 /omit-if-no-ref/
8 pcfg_pull_up: pcfg-pull-up {
9 bias-pull-up;
10 };
11
12 /omit-if-no-ref/
13 pcfg_pull_down: pcfg-pull-down {
14 bias-pull-down;
15 };
16
17 /omit-if-no-ref/
18 pcfg_pull_none: pcfg-pull-none {
19 bias-disable;
20 };
21
22 /omit-if-no-ref/
23 pcfg_pull_none_drv_level_0: pcfg-pull-none-drv-level-0 {
24 bias-disable;
25 drive-strength = <0>;
26 };
......
344 };
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
上面的 pcfg_pull_up、pcfg_pull_down、pcfg_pull_none 和 pcfg_pull_none_drv_level_0 就是可使用的配置项。比如 GPIO0_C0 这个 PIN 用作普通的 GPIO,不需要配置驱动能力,那么就可以使用 pcfg_pull_none,也就是不设置上下拉。rockchip-pinconf.dtsi 里面还有很多其他的配置项,大家自行查阅。
最总,如果要将 GPIO0_C0 设置为 GPIO 功能,那么配置就是:
rockchip,pins =<0 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none;