文章目录
一、pinctrl的概念
pinctrl
是 “Pin Control”(引脚控制)的缩写,是设备树(Device Tree)中的一个重要概念,主要用于配置硬件平台上的引脚(Pin)复用、功能设置和电气配置。引脚控制机制通过在设备树中设置各个引脚的功能、配置和行为,确保硬件资源的正确使用。
pinctrl
的作用
在大多数嵌入式系统和处理器中,许多引脚具有多种功能(例如 GPIO、串口、I2C、SPI、PWM 等)。pinctrl
的任务就是配置这些引脚的功能,确保它们在不同硬件模块之间能够正确地复用和控制。
具体来说,pinctrl
提供了以下几个功能:
引脚复用(Pin Multiplexing):
- 许多硬件平台的引脚可以复用为不同的功能,例如一个引脚既可以作为 UART 的 RX,也可以作为 GPIO,具体功能取决于引脚控制的配置。
pinctrl
允许你配置每个引脚的复用功能,以适应不同的硬件需求。
电气配置(Electrical Configuration):
- 引脚可能需要配置为输入或输出,还可能需要设置上下拉电阻(pull-up 或 pull-down)来满足电气特性。
pinctrl
允许配置引脚的电气特性,比如是否启用上拉电阻、下拉电阻或禁用它们。
中断配置(Interrupt Configuration):
- 对于支持中断的引脚,
pinctrl
也配置中断类型(如上升沿、下降沿或双边沿触发)以及中断优先级。
- 对于支持中断的引脚,
时钟和电源控制:
- 有些引脚需要特定的时钟或电源配置才能工作。例如,GPIO 控制器可能需要启用时钟,才能使引脚的功能正常工作。
设备树中的 pinctrl
节点
在设备树中,pinctrl
节点定义了引脚的配置,包括引脚的复用功能、输入输出配置和电气特性等。它通常会引用其他硬件节点,如 GPIO、UART、SPI 等模块,来确保每个模块的引脚都配置正确。
典型的 pinctrl
节点结构
pinctrl {
/* 配置一个引脚组 */
group_name {
rockchip,pins = <引脚组 引脚物理地址 复用功能 配置>;
};
};
rockchip,pins
:这个属性用于定义具体的引脚配置,描述引脚的物理地址、复用功能以及电气配置。引脚组
:指定引脚属于哪个组。引脚物理地址
:具体的引脚地址,如RK_PA0
,这表示物理引脚的编号。复用功能
:指定引脚的复用功能,例如可以是 GPIO、SPI、UART 等功能。配置
:指定引脚的电气配置,比如上下拉电阻配置(如pcfg_pull_up
,pcfg_pull_down
等)。
例子
pinctrl {
/* 配置一个 UART 功能的引脚 */
uart_pins: uart-pins {
rockchip,pins = <1 RK_PA0 1 &pcfg_pull_none>, /* UART TX */
<1 RK_PA1 1 &pcfg_pull_none>; /* UART RX */
};
};
这段代码表示:
- 配置
RK_PA0
和RK_PA1
引脚用于 UART 功能,其中1
表示复用功能为 UART,&pcfg_pull_none
表示不使用上下拉电阻。
pinctrl
的重要性
- 资源管理:它帮助开发者在多个硬件模块(如 UART、SPI、GPIO 等)之间共享硬件资源(引脚),避免引脚冲突。
- 灵活性:通过配置引脚的功能,系统可以根据需求灵活地切换不同的外设功能。
- 硬件抽象:通过设备树中的
pinctrl
配置,硬件的引脚功能和电气特性被抽象化,开发者不需要直接操作硬件寄存器,简化了硬件控制的复杂性。
总结
pinctrl
机制通过在设备树中配置引脚的功能、复用、输入输出模式、电气特性等,确保系统中的硬件引脚得到合理的管理和使用。它在嵌入式系统中尤其重要,帮助开发者正确配置硬件引脚,避免引脚冲突,提高硬件资源的利用效率。
二、RK3568的pinctrl讲解
RK3568中rk3568.dtsi文件中的pinctrl:
这部分设备树定义了 pinctrl
节点及其包含的多个 GPIO 控制器(gpio0
至 gpio4
)。这些 GPIO 控制器分别代表了 5 个 GPIO bank(GPIO 管脚组),每个 bank 包含多个 GPIO 引脚,并提供了相关的硬件信息和配置。
1. pinctrl
节点
pinctrl: pinctrl {
compatible = "rockchip,rk3568-pinctrl";
rockchip,grf = <&grf>;
rockchip,pmu = <&pmugrf>;
#address-cells = <2>;
#size-cells = <2>;
ranges;
compatible = "rockchip,rk3568-pinctrl"
:指定设备树节点使用的是 Rockchip RK3568 处理器的引脚控制器。compatible
字段表示该节点与 Rockchip RK3568 平台的引脚控制器兼容。rockchip,grf = <&grf>
:指向grf
(General Register File)节点的引用,GRF 是 Rockchip 处理器的一个模块,负责控制许多硬件寄存器。它与pinctrl
有关,可能涉及对 GPIO 控制器的访问或状态更新。rockchip,pmu = <&pmugrf>
:指向 PMU(Power Management Unit)寄存器的引用,可能与电源管理和引脚状态有关。#address-cells = <2>
和#size-cells = <2>
:这些属性定义了子节点中reg
属性的地址和大小的单元数。在这里,address-cells
和size-cells
都是 2,表示每个子节点的reg
属性包含一个地址(2 个单元)和大小(2 个单元)的信息。ranges
:用于配置地址范围,通常用于支持虚拟地址和物理地址映射的场景,但在这段代码中未做进一步说明。
2. gpio0
至 gpio4
子节点
这些子节点定义了 5 个 GPIO 引脚组(gpio0
到 gpio4
),每个 GPIO 引脚组对应一个控制器 bank,每个 bank 控制一组物理 GPIO 引脚。
每个 gpioX
子节点的结构和作用
我们以 gpio0
为例进行讲解,其它 gpio1
、gpio2
等节点的结构与之类似,区别在于它们的地址、时钟和中断信息不同。
gpio0: gpio@fdd60000 {
compatible = "rockchip,gpio-bank";
reg = <0x0 0xfdd60000 0x0 0x100>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&pmucru PCLK_GPIO0>, <&pmucru DBCLK_GPIO0>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 0 32>;
interrupt-controller;
#interrupt-cells = <2>;
};
gpio0: gpio@fdd60000
:这是gpio0
控制器的节点,gpio0
管理一个 GPIO 引脚组,gpio@fdd60000
表示该控制器的物理地址为0xfdd60000
。compatible = "rockchip,gpio-bank"
:表示这是一个 Rockchip GPIO bank,gpio-bank
是该硬件控制器的兼容标识。reg = <0x0 0xfdd60000 0x0 0x100>
:reg
属性定义了该 GPIO 控制器的地址范围。地址0xfdd60000
是 GPIO 控制器的基地址,0x100
是内存的大小(控制器的寄存器空间)。interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>
:配置该 GPIO 控制器的中断,GIC_SPI 33
表示中断的编号(SPI 33),IRQ_TYPE_LEVEL_HIGH
表示中断触发类型为高电平触发。clocks = <&pmucru PCLK_GPIO0>, <&pmucru DBCLK_GPIO0>
:指定 GPIO 控制器所依赖的时钟源,PCLK_GPIO0
和DBCLK_GPIO0
是时钟源,用于驱动 GPIO 控制器。gpio-controller
:声明该节点是一个 GPIO 控制器。它指示此节点具有处理 GPIO 操作的能力。#gpio-cells = <2>
:指定 GPIO 控制器的#gpio-cells
数量,通常该值为 2,表示每个 GPIO 引脚需要两个参数:引脚编号和引脚配置。gpio-ranges = <&pinctrl 0 0 32>
:指定 GPIO 引脚的范围。&pinctrl
是一个引用,表示这些 GPIO 引脚与pinctrl
中的引脚配置有关;0 0 32
表示该控制器有 32 个 GPIO 引脚。interrupt-controller
:声明该节点为中断控制器。它意味着该 GPIO 控制器也可以处理中断。#interrupt-cells = <2>
:指定中断控制器的参数数量。通常为 2,表示每个中断源需要两个参数:中断编号和触发方式。
3. gpio1
到 gpio4
子节点
这些节点与 gpio0
节点类似,只是地址、时钟和中断编号不同:
gpio1
:地址0xfe740000
,时钟源为PCLK_GPIO1
和DBCLK_GPIO1
,中断为GIC_SPI 34
。gpio2
:地址0xfe750000
,时钟源为PCLK_GPIO2
和DBCLK_GPIO2
,中断为GIC_SPI 35
。gpio3
:地址0xfe760000
,时钟源为PCLK_GPIO3
和DBCLK_GPIO3
,中断为GIC_SPI 36
。gpio4
:地址0xfe770000
,时钟源为PCLK_GPIO4
和DBCLK_GPIO4
,中断为GIC_SPI 37
。
总结
这段设备树定义了 5 个 GPIO 控制器,每个控制器管理一组 GPIO 引脚。每个 GPIO 控制器的配置包括:
- 控制器的基地址和大小。
- 相关时钟源和中断配置。
- 配置每个控制器的引脚数量和中断管理。
通过这些配置,系统可以正确地控制 GPIO 引脚,处理中断事件,并确保硬件时钟的正常运行。这些 GPIO 控制器通常用于与外部设备交互,如按键输入、LED 输出等。
pinctrl: pinctrl {
compatible = "rockchip,rk3568-pinctrl";
rockchip,grf = <&grf>;
rockchip,pmu = <&pmugrf>;
#address-cells = <2>;
#size-cells = <2>;
ranges;
gpio0: gpio@fdd60000 {
compatible = "rockchip,gpio-bank";
reg = <0x0 0xfdd60000 0x0 0x100>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&pmucru PCLK_GPIO0>, <&pmucru DBCLK_GPIO0>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 0 32>;
interrupt-controller;
#interrupt-cells = <2>;
};
gpio1: gpio@fe740000 {
compatible = "rockchip,gpio-bank";
reg = <0x0 0xfe740000 0x0 0x100>;
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru PCLK_GPIO1>, <&cru DBCLK_GPIO1>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 32 32>;
interrupt-controller;
#interrupt-cells = <2>;
};
gpio2: gpio@fe750000 {
compatible = "rockchip,gpio-bank";
reg = <0x0 0xfe750000 0x0 0x100>;
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru PCLK_GPIO2>, <&cru DBCLK_GPIO2>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 64 32>;
interrupt-controller;
#interrupt-cells = <2>;
};
gpio3: gpio@fe760000 {
compatible = "rockchip,gpio-bank";
reg = <0x0 0xfe760000 0x0 0x100>;
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru PCLK_GPIO3>, <&cru DBCLK_GPIO3>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 96 32>;
interrupt-controller;
#interrupt-cells = <2>;
};
gpio4: gpio@fe770000 {
compatible = "rockchip,gpio-bank";
reg = <0x0 0xfe770000 0x0 0x100>;
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru PCLK_GPIO4>, <&cru DBCLK_GPIO4>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 128 32>;
interrupt-controller;
#interrupt-cells = <2>;
};
};
RK3568中的rk3568-pinctrl.dtsi文件:
对pinctrl的引用:
&pinctrl {
acodec {
/omit-if-no-ref/
acodec_pins: acodec-pins {
rockchip,pins =
/* acodec_adc_sync */
<1 RK_PB1 5 &pcfg_pull_none>,
/* acodec_adcclk */
<1 RK_PA1 5 &pcfg_pull_none>,
/* acodec_adcdata */
<1 RK_PA0 5 &pcfg_pull_none>,
/* acodec_dac_datal */
<1 RK_PA7 5 &pcfg_pull_none>,
/* acodec_dac_datar */
<1 RK_PB0 5 &pcfg_pull_none>,
/* acodec_dacclk */
<1 RK_PA3 5 &pcfg_pull_none>,
/* acodec_dacsync */
<1 RK_PA5 5 &pcfg_pull_none>;
};
};
audiopwm {
/omit-if-no-ref/
audiopwm_lout: audiopwm-lout {
rockchip,pins =
/* audiopwm_lout */
<1 RK_PA0 4 &pcfg_pull_none>;
};
/omit-if-no-ref/
audiopwm_loutn: audiopwm-loutn {
rockchip,pins =
/* audiopwm_loutn */
<1 RK_PA1 6 &pcfg_pull_none>;
};
/omit-if-no-ref/
audiopwm_loutp: audiopwm-loutp {
rockchip,pins =
/* audiopwm_loutp */
<1 RK_PA0 6 &pcfg_pull_none>;
};
/omit-if-no-ref/
audiopwm_rout: audiopwm-rout {
rockchip,pins =
/* audiopwm_rout */
<1 RK_PA1 4 &pcfg_pull_none>;
};
/omit-if-no-ref/
audiopwm_routn: audiopwm-routn {
rockchip,pins =
/* audiopwm_routn */
<1 RK_PA7 4 &pcfg_pull_none>;
};
/omit-if-no-ref/
audiopwm_routp: audiopwm-routp {
rockchip,pins =
/* audiopwm_routp */
<1 RK_PA6 4 &pcfg_pull_none>;
};
};
bt656 {
/omit-if-no-ref/
bt656m0_pins: bt656m0-pins {
rockchip,pins =
/* bt656_clkm0 */
<3 RK_PA0 2 &pcfg_pull_none>,
/* bt656_d0m0 */
<2 RK_PD0 2 &pcfg_pull_none>,
/* bt656_d1m0 */
<2 RK_PD1 2 &pcfg_pull_none>,
/* bt656_d2m0 */
<2 RK_PD2 2 &pcfg_pull_none>,
/* bt656_d3m0 */
<2 RK_PD3 2 &pcfg_pull_none>,
/* bt656_d4m0 */
<2 RK_PD4 2 &pcfg_pull_none>,
/* bt656_d5m0 */
<2 RK_PD5 2 &pcfg_pull_none>,
/* bt656_d6m0 */
<2 RK_PD6 2 &pcfg_pull_none>,
/* bt656_d7m0 */
<2 RK_PD7 2 &pcfg_pull_none>;
};
/omit-if-no-ref/
bt656m1_pins: bt656m1-pins {
rockchip,pins =
/* bt656_clkm1 */
<4 RK_PB4 5 &pcfg_pull_none>,
/* bt656_d0m1 */
<3 RK_PC6 5 &pcfg_pull_none>,
/* bt656_d1m1 */
<3 RK_PC7 5 &pcfg_pull_none>,
/* bt656_d2m1 */
<3 RK_PD0 5 &pcfg_pull_none>,
/* bt656_d3m1 */
<3 RK_PD1 5 &pcfg_pull_none>,
/* bt656_d4m1 */
<3 RK_PD2 5 &pcfg_pull_none>,
/* bt656_d5m1 */
<3 RK_PD3 5 &pcfg_pull_none>,
/* bt656_d6m1 */
<3 RK_PD4 5 &pcfg_pull_none>,
/* bt656_d7m1 */
<3 RK_PD5 5 &pcfg_pull_none>;
};
};
这部分代码展示了如何在 pinctrl
中配置与音频、视频接口相关的引脚。主要包括 acodec
(音频编解码器)、audiopwm
(音频 PWM)、bt656
(BT.656 视频接口)等不同模块的引脚配置。
下面是对每一部分的详细讲解:
1. acodec
部分
acodec {
/omit-if-no-ref/
acodec_pins: acodec-pins {
rockchip,pins =
/* acodec_adc_sync */
<1 RK_PB1 5 &pcfg_pull_none>,
/* acodec_adcclk */
<1 RK_PA1 5 &pcfg_pull_none>,
/* acodec_adcdata */
<1 RK_PA0 5 &pcfg_pull_none>,
/* acodec_dac_datal */
<1 RK_PA7 5 &pcfg_pull_none>,
/* acodec_dac_datar */
<1 RK_PB0 5 &pcfg_pull_none>,
/* acodec_dacclk */
<1 RK_PA3 5 &pcfg_pull_none>,
/* acodec_dacsync */
<1 RK_PA5 5 &pcfg_pull_none>;
};
};
acodec
:表示音频编解码器的引脚配置。acodec_pins
:为音频编解码器定义一组引脚。rockchip,pins
:后面的每一项配置了具体的引脚功能,格式为<设备编号 引脚 名称 配置>
。- 每一项的格式
<1 RK_PB1 5 &pcfg_pull_none>
表示:1
:表示该引脚的控制器编号。RK_PB1
:引脚名称(例如RK_PB1
是 Rockchip 的特定引脚标识)。5
:表示该引脚的功能模式(例如:数字音频的功能模式)。&pcfg_pull_none
:引脚的配置(这里表示没有上拉/下拉电阻)。
- 每一项的格式
这些引脚的功能主要用于音频编解码器(acodec
)的输入/输出,包括音频数据、时钟和同步信号等。
2. audiopwm
部分
audiopwm {
/omit-if-no-ref/
audiopwm_lout: audiopwm-lout {
rockchip,pins =
/* audiopwm_lout */
<1 RK_PA0 4 &pcfg_pull_none>;
};
/omit-if-no-ref/
audiopwm_loutn: audiopwm-loutn {
rockchip,pins =
/* audiopwm_loutn */
<1 RK_PA1 6 &pcfg_pull_none>;
};
/omit-if-no-ref/
audiopwm_loutp: audiopwm-loutp {
rockchip,pins =
/* audiopwm_loutp */
<1 RK_PA0 6 &pcfg_pull_none>;
};
/omit-if-no-ref/
audiopwm_rout: audiopwm-rout {
rockchip,pins =
/* audiopwm_rout */
<1 RK_PA1 4 &pcfg_pull_none>;
};
/omit-if-no-ref/
audiopwm_routn: audiopwm-routn {
rockchip,pins =
/* audiopwm_routn */
<1 RK_PA7 4 &pcfg_pull_none>;
};
/omit-if-no-ref/
audiopwm_routp: audiopwm-routp {
rockchip,pins =
/* audiopwm_routp */
<1 RK_PA6 4 &pcfg_pull_none>;
};
};
audiopwm
:表示音频 PWM(脉冲宽度调制)输出的引脚配置。- 每个子节点(如
audiopwm_lout
、audiopwm_loutn
等)分别配置了左声道和右声道的输出引脚。audiopwm_lout
:配置左声道输出引脚。audiopwm_loutn
和audiopwm_loutp
:配置左声道的负极和正极输出引脚。audiopwm_rout
、audiopwm_routn
和audiopwm_routp
:配置右声道的输出引脚。
这些引脚配置用于音频输出,可能用于外部音频设备的控制,如扬声器或耳机。PWM 输出用于调节音频的幅度和频率。
3. bt656
部分
bt656 {
/omit-if-no-ref/
bt656m0_pins: bt656m0-pins {
rockchip,pins =
/* bt656_clkm0 */
<3 RK_PA0 2 &pcfg_pull_none>,
/* bt656_d0m0 */
<2 RK_PD0 2 &pcfg_pull_none>,
/* bt656_d1m0 */
<2 RK_PD1 2 &pcfg_pull_none>,
/* bt656_d2m0 */
<2 RK_PD2 2 &pcfg_pull_none>,
/* bt656_d3m0 */
<2 RK_PD3 2 &pcfg_pull_none>,
/* bt656_d4m0 */
<2 RK_PD4 2 &pcfg_pull_none>,
/* bt656_d5m0 */
<2 RK_PD5 2 &pcfg_pull_none>,
/* bt656_d6m0 */
<2 RK_PD6 2 &pcfg_pull_none>,
/* bt656_d7m0 */
<2 RK_PD7 2 &pcfg_pull_none>;
};
/omit-if-no-ref/
bt656m1_pins: bt656m1-pins {
rockchip,pins =
/* bt656_clkm1 */
<4 RK_PB4 5 &pcfg_pull_none>,
/* bt656_d0m1 */
<3 RK_PC6 5 &pcfg_pull_none>,
/* bt656_d1m1 */
<3 RK_PC7 5 &pcfg_pull_none>,
/* bt656_d2m1 */
<3 RK_PD0 5 &pcfg_pull_none>,
/* bt656_d3m1 */
<3 RK_PD1 5 &pcfg_pull_none>,
/* bt656_d4m1 */
<3 RK_PD2 5 &pcfg_pull_none>,
/* bt656_d5m1 */
<3 RK_PD3 5 &pcfg_pull_none>,
/* bt656_d6m1 */
<3 RK_PD4 5 &pcfg_pull_none>,
/* bt656_d7m1 */
<3 RK_PD5 5 &pcfg_pull_none>;
};
};
bt656
:表示 BT.656 视频接口的引脚配置。bt656m0_pins
和bt656m1_pins
:分别定义了两个 BT.656 视频接口的引脚。BT.656 是一种视频传输标准,常用于摄像头或视频显示模块。- 每个引脚的配置
<3 RK_PA0 2 &pcfg_pull_none>
说明:3
:引脚所在的控制器编号。RK_PA0
、RK_PD0
等是 Rockchip 特定的引脚名称。2
:表示引脚的功能模式(通常表示视频信号的传输模式)。&pcfg_pull_none
:表示引脚没有配置上拉或下拉电阻。
总结
这段代码通过 pinctrl
配置了与音频和视频相关的引脚:
acodec
配置了音频编解码器的时钟、数据和同步引脚。audiopwm
配置了音频 PWM 输出的引脚,用于音频信号的调制和输出。bt656
配置了 BT.656 视频接口的信号传输引脚。
每个模块的引脚都通过特定的功能模式进行配置,确保各个模块的引脚按照预期的功能工作,支持音视频信号的处理和传输。