GPIO - Pinctrl 控制器
Linux Pinctrl(引脚控制)子系统是 Linux 内核中用于管理和控制硬件引脚(GPIO、I2C、SPI等)的一个子系统。它允许 Linux 内核与底层硬件交互,配置和控制系统中的各种引脚以实现特定的功能。
模块配置
驱动配置
Allwinner BSP --->
Device Drivers --->
Pinctrl Drivers --->
<*> Pinctrl Support for Allwinner SoCs
<*> {CHIP_PLATFORM} PIO
<*> {CHIP_PLATFORM} RTC_PIO
提示
{CHIP_PLATFORM} 为对应芯片平台的标识符(如 V821 对应 SUN300IW1),具体名称请参考对应芯片的 SDK 驱动配置菜单。
:::

设备树配置
对于 Pinctrl,设备树公共配置如下,这部分是定义控制器资源,中断,时钟,开发一般无需修改
pio: pinctrl@42000000 {
compatible = "allwinner,{chip_platform}-pinctrl";
reg = <0x0 0x42000000 0x0 0x500>;
interrupts-extended = <&plic0 68 IRQ_TYPE_LEVEL_HIGH>,
<&plic0 72 IRQ_TYPE_LEVEL_HIGH>,
<&plic0 74 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&aon_ccu CLK_APB0>, <&aon_ccu CLK_DCXO>, <&losc>;
clock-names = "apb", "hosc", "losc";
device_type = "pio";
gpio-controller;
interrupt-controller;
#interrupt-cells = <3>;
#address-cells = <0>;
#gpio-cells = <3>;
};
提示
{chip_platform} 为对应芯片平台的标识符(如 V821 对应 sun300iw1),具体 compatible 字符串请参考对应芯片的 SDK 设备树配置。
:::
部分芯片平台存在两个 GPIO 域,一般来说 GPIO L 前的是 PIO 域,从 GPIO L 开始之后的是 RPIO 域,配置如下。开发一般无需修改
rtc_pio: pinctrl@42000540 {
#address-cells = <1>;
compatible = "allwinner,{chip_platform}-rtc-pinctrl";
reg = <0x0 0x42000540 0x0 0x100>;
interrupts-extended = <&plic0 84 IRQ_TYPE_LEVEL_HIGH>; /* GPIOL */
clocks = <&dcxo24M>;
clock-names = "hosc";
gpio-controller;
#gpio-cells = <3>;
interrupt-controller;
#interrupt-cells = <3>;
};
提示
具体芯片平台是否存在 RTC PIO 域以及 compatible 字符串,请参考对应芯片的 SDK 设备树配置。
:::
配置通用GPIO功能/中断功能
这里以在 Linux 中配置一个按键为示例,讲解如何配置单个 IO 的功能与中断功能
soc{
gpiokey {
device_type = "gpiokey";
compatible = "gpio-keys";
key_in_pio {
device_type = "key_in_pio";
label = "key_in_pio";
gpios = <&pio PA 4 GPIO_ACTIVE_HIGH>; // PL 前的 GPIO 使用 &pio
linux,code = <0x1c>;
};
key_in_rtc {
device_type = "key_in_rtc";
label = "key_in_rtc";
gpios = <&rtc_pio PL 3 GPIO_ACTIVE_HIGH>; // PL 后的 GPIO 使用 &rtc_pio
linux,code = <0x1d>;
};
};
};
以下是这段设备树定义的内容:
| 字段 | 说明 |
|---|---|
device_type | "gpiokey":定义设备类型为 GPIO 按键设备。 |
compatible | "gpio-keys":表示设备与 gpio-keys 驱动兼容,适用于 Linux 内核中的 GPIO 按键驱动。 |
key_in_pio(按键配置) | |
device_type | "key_in_pio":该按键设备的类型是 "key_in_pio"。 |
label | "key_in_pio":按键的标签,用于标识该按键。 |
gpios | <&pio PA 4 GPIO_ACTIVE_HIGH>:该按键连接到 PIO 的 PA 4 引脚,且引脚在按键按下时电平为高 (GPIO_ACTIVE_HIGH)。 |
linux,code | <0x1c>:按键的扫描码为 0x1c,对应于某个键值(如 "OK" 按键)。 |
key_in_rtc(按键配置) | |
device_type | "key_in_rtc":该按键设备的类型是 "key_in_rtc"。 |
label | "key_in_rtc":按键的标签,用于标识该按键。 |
gpios | <&rtc_pio PL 3 GPIO_ACTIVE_HIGH>;:该按键连接到RTC PIO的 PL 3 引脚,且引脚在按键按下时电平为高 (GPIO_ACTIVE_HIGH)。 |
linux,code | <0x1d>:按键的扫描码为 0x1d,对应于某个键值(如 "WAKE" 按键)。 |
gpios = <&pio PA 4 GPIO_ACTIVE_HIGH>;
| | |
| | `------------------- gpio active时状态,如果需要上下拉,还可以或上GPIO_PULL_UP、GPIO_PULL_DOWN标志
| `----------------------- 哪个bank,这里是 bank PA
`--------------------------- 指向哪个pio,这里是 PL 前的 GPIO,使用 &pio
gpios = <&rtc_pio PL 4 GPIO_ACTIVE_HIGH>;
| | |
| | `------------------- gpio active时状态,如果需要上下拉,还可以或上GPIO_PULL_UP、GPIO_PULL_DOWN标志
| `----------------------- 哪个bank,这里是 bank PL
`--------------------------- 指向哪个pio,这里是 PL 后的 GPIO,使用 &rtc_pio
配置设备引脚
&pio {
uart0_pins_default: uart0_pins@0 {
pins = "PD22", "PD23";
function = "uart0";
};
uart0_pins_sleep: uart0_pins@1 {
pins = "PD22", "PD23";
function = "io_disabled";
};
};
&uart0 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&uart0_pins_default>;
pinctrl-1 = <&uart0_pins_sleep>;
status = "okay";
};
这段设备树配置主要是为 UART0(串口0)配置两个不同的引脚状态:默认状态和睡眠状态。它描述了如何配置引脚复用功能和串口的状态。
uart0_pins_default:默认状态uart0_pins_sleep:睡眠状态
PIO 节点用于配置引脚实际IO,功能:
| 字段 | 说明 |
|---|---|
uart0_pins_default | uart0_pins@0:定义了默认状态下 UART0 引脚的配置。 |
pins | "PD22", "PD23":指定引脚 PD22 和 PD23 用作 UART0 的 TX/RX 引脚。 |
function | "uart0":指定这两个引脚的功能为 UART0,允许它们用于串行通信。 |
uart0_pins_sleep | uart0_pins@1:定义了睡眠状态下 UART0 引脚的配置。 |
pins | "PD22", "PD23":同样指定引脚 PD22 和 PD23,但在睡眠模式下这些引脚的功能被禁用 。 |
function | "io_disabled":表示在睡眠状态下禁用这两个引脚的功能。 |
UART 节点引用配置的引脚,提供给驱动操作
| 字段 | 说明 |
|---|---|
pinctrl-names | "default", "sleep":定义了两种引脚配置名称,分别为默认配置和睡眠配置。 |
pinctrl-0 | <&uart0_pins_default>:指定默认状态下使用 uart0_pins_default 配置。 |
pinctrl-1 | <&uart0_pins_sleep>:指定睡眠状态下使用 uart0_pins_sleep 配置。 |
status | "okay":启用 UART0 控制器,表示 UART0 处于工作状态。 |
- 默认状态 (
uart0_pins_default): 在默认工作状态下,引脚PD22和PD23被配置为 UART0 的 TX 和 RX 引脚,支持串行通信功能。 - 睡眠状态 (
uart0_pins_sleep): 在睡眠模式下,引脚PD22和PD23的功能被禁用 (io_disabled),以节省电能。 &uart0节点: 定义了 UART0 控制器的引脚配置,使用default和sleep两种模式。
计算 GPIO 编号
GPIO 号转换器
源码定义
全志的GPIO号在 sunxi-gpio.h 中定义
sunxi-gpio.h
GPIO号定义
每个 BANK 有 32 组 GPIO,BANK A 作为 0,则 BANK B 为 32,以此类推。
#define SUNXI_PA_BASE 0
#define SUNXI_PB_BASE 32
#define SUNXI_PC_BASE 64
#define SUNXI_PD_BASE 96
#define SUNXI_PE_BASE 128
#define SUNXI_PF_BASE 160
#define SUNXI_PG_BASE 192
#define SUNXI_PH_BASE 224
#define SUNXI_PI_BASE 256
#define SUNXI_PJ_BASE 288
#define SUNXI_PK_BASE 320
#define SUNXI_PL_BASE 352
#define SUNXI_PM_BASE 384
#define SUNXI_PN_BASE 416
#define SUNXI_PO_BASE 448
#define AXP_PIN_BASE 1024
计算方式
举两个例子
1、PA13
PA 是从0开始定义的,那么就是: 0 +13 = 13
那么 PA13 的GPIO号 就是 GPIO13
2、PE10
PE 是从128开始定义的,那么就是:128 + 10 = 138
那么 PE10 的GPIO号 就是 GPIO138
模块 SYS 接口
模块支持通过用户层调用,启用方法如下:
make kernel_menuconfig
Device Drivers --->
GPIO Support --->
[*] /sys/class/gpio/... (sysfs interface)

这里以 PD16 为例,其 GPIO 号为 PD16,先检查是否被其他设备使用。
确认该 GPIO 没有被其他模块复用
cat /sys/kernel/debug/pinctrl/42000000.pinctrl/pinmux-pins
可以看到 PIN PD16 是 UNCLAIMED 的状态,PIN 号是 112 号,表示该 GPIO 没有被其他设备使用,其 IO 号是 112 号

导出该 GPIO
echo 112 > /sys/class/gpio/export
cd /sys/class/gpio/gpio112

然后再将该 IO 置为输出状态,即可操作其电平:
echo out > direction
echo 1 > value # 拉高
echo 0 > value # 拉低