# 配置 pinctrl 驱动程序

Qualcomm Linux 内核中的 Pinctrl 子系统可管理和配置用于通用输入/输出 (GPIO)、内部集成电路 (I2C)、串行外设接口 (SPI) 以及其他硬件接口的引脚。

Pinctrl 配置（例如**引脚复用**和**引脚分组**）在设备特定的 Pinctrl 驱动程序中进行管理，驱动程序列出了所有可用引脚和功能。

例如，对于 QCS6490，相应的驱动程序在 `kernel-src/drivers/pinctrl/qcom/pinctrl-sc7280.c` 文件中。

Note

有关其他 Qualcomm SoC pinctrl 驱动程序的更多信息，请参见 [Pinctrl 驱动程序](https://github.com/torvalds/linux/tree/master/drivers/pinctrl/qcom)。

以下是 pinctrl 数据对象：

表：Pinctrl 数据对象

| 变量 | 说明 |
| --- | --- |
| static const struct pinctrl_pin_desc sc7280_pins<br>    Copy to clipboard | 枚举所有引脚及其名称 |
| static const struct msm_pingroup sc7280_groups<br>    Copy to clipboard | 定义 GPIO 引脚组的可用复用功能 |
| enum sc7280_functions<br>    Copy to clipboard | 以枚举值形式列出所有可用功能 |

有关 QCS6490 各个 SoC pinctrl 绑定文档所支持功能的更多信息，请参见 [pinctrl 绑定文档](https://www.kernel.org/doc/Documentation/devicetree/bindings/pinctrl/qcom%2Csc7280-pinctrl.yaml)。

**功能选择**

对于 `sc7280_functions` 数据对象，一个或多个 GPIO 引脚用作功能，必须注册到设备树并传递给正确的设备节点。

在系统启动期间，内核 pinctrl 基础架构会注册这些功能。

以下示例展示了内核配置基础架构：

tlmm: pinctrl@f100000 {
        compatible = "qcom,sc7280-pinctrl";
        :
        :
        :
        :
        qup_spi0_data_clk: qup-spi0-data-clk-state {
            pins = "gpio0", "gpio1", "gpio2";
            function = "qup00";
        };
    
        qup_spi0_cs: qup-spi0-cs-state {
            pins = "gpio3";
            function = "qup00";
        };
    
        qup_spi1_data_clk: qup-spi1-data-clk-state {
            pins = "gpio4", "gpio5", "gpio6";
            function = "qup01";
        };
    
        qup_spi1_cs: qup-spi1-cs-state {
            pins = "gpio7";
            function = "qup01";
        };
        :
        :
        :
        :
    
    };

        spi0: spi@980000 {
            compatible = "qcom,geni-spi";
            reg = <0 0x00980000 0 0x4000>;
            clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>;
            clock-names = "se";
            pinctrl-names = "default";
            pinctrl-0 = <&qup_spi0_data_clk>, <&qup_spi0_cs>;
            interrupts = <GIC_SPI 601 IRQ_TYPE_LEVEL_HIGH>;
            #address-cells = <1>;
            #size-cells = <0>;
            power-domains = <&rpmhpd SC7280_CX>;
            operating-points-v2 = <&qup_opp_table>;
            interconnects = <&clk_virt MASTER_QUP_CORE_0 0 &clk_virt SLAVE_QUP_CORE_0 0>,
                    <&gem_noc MASTER_APPSS_PROC 0 &cnoc2 SLAVE_QUP_0 0>;
            interconnect-names = "qup-core", "qup-config";
            dmas = <&gpi_dma0 0 0 QCOM_GPI_SPI>,
                <&gpi_dma0 1 0 QCOM_GPI_SPI>;
            dma-names = "tx", "rx";
            status = "disabled";
        };
    Copy to clipboard

## 配置 GPIO 的使用

GPIO 引脚配置需要以下两项设置。这些设置会定义 GPIO 引脚状态，并使这些引脚可用于任何输入/输出活动。

- Mux：mux 设置需要选择从 SoC 特定的 pinctrl 驱动程序中的可用功能集中映射的功能名称。

    有关 pinctrl 的更多信息，请参见 [Pinctrl 配置](https://docs.qualcomm.com/doc/80-70020-3SC/topic/pinctrl-configuration.html#pinctrl-configuration)。
- 配置：配置方面需要设置驱动强度和偏置属性。

以下示例展示了这两项设置如何通过以下步骤定义 GPIO 引脚：

1. 在设备树中定义引脚配置：

bt_en: bt-en-state {
           pins = "gpio85";
           function = "gpio";
           output-low;
           bias-disable;
        };
        Copy to clipboard
2. 在设备树中配置设备节点或知识产权 (IP) 块：

bluetooth: bluetooth {
           compatible = "qcom,wcn6750-bt";
           pinctrl-names = "default";
           pinctrl-0 = <&bt_en>, <&sw_ctrl>;
           enable-gpios = <&tlmm 85 GPIO_ACTIVE_HIGH>;
           swctrl-gpios = <&tlmm 86 GPIO_ACTIVE_HIGH>;
           vddaon-supply = <&vreg_s7b_0p9>;
           vddbtcxmx-supply = <&vreg_s7b_0p9>;
           vddrfacmn-supply = <&vreg_s7b_0p9>;
           vddrfa0p8-supply = <&vreg_s7b_0p9>;
           vddrfa1p7-supply = <&vreg_s1b_1p8>;
           vddrfa1p2-supply = <&vreg_s8b_1p2>;
           vddrfa2p2-supply = <&vreg_s1c_2p2>;
           vddasd-supply = <&vreg_l11c_2p8>;
           max-speed = <3200000>;
        Copy to clipboard
3. 驱动程序代码必须使用通用 API 在 pinctrl 配置中选择和注册其 GPIO 配置。

    以下为可用 API 示例：

> 
> 
> devm_gpiod_get_optional(&serdev->dev, "enable", GPIOD_OUT_LOW);
>         
>         /**
>         * devm_gpiod_get_optional - Resource-managed gpiod_get_optional()
>         * @dev: GPIO consumer
>         * @con_id: function within the GPIO consumer
>         * @flags: optional GPIO initialization flags
>         *
>         * Managed gpiod_get_optional(). GPIO descriptors returned from this function
>         * are automatically disposed on driver detach. See gpiod_get_optional() for
>         * detailed information about behavior and return values. */
>         
>          gpiod_set_value_cansleep(qcadev->bt_en, 0);
>         
>         /**
>         * gpiod_set_value_cansleep() - assign a gpio's value
>         * @desc: gpio whose value will be assigned
>         * @value: value to assign
>         *
>         * Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into
>         * account
>         *
>         * This function is to be called from contexts that can sleep.
>         */
>         Copy to clipboard

**GPIO 作为中断请求 (IRQ)**

按照以下步骤操作，将 GPIO 设置为 IRQ：

1. 在 DTS 文件中配置 GPIO 引脚：

    1. 设置 GPIO 引脚的属性和功能。
    2. 使用以下配置将引脚设置为使用 GPIO 55 以实现 `qup_se_l3()` 功能：

qupv3_se3_rx: qupv3-se3-rx-state {
               pins = "gpio55";
               function = "qup03"; // To be taken from available from functions.
               drive-strength = <2>;
               bias-disable;
            };
            Copy to clipboard
2. 为要将 GPIO 配置为 IRQ 的设备节点创建一个与之前配置类似的 DT 条目。

    在以下示例中，将 GPIO 55 配置为 IRQ，其父节点为顶层模式多路复用器 (TLMM)，触发电平设置为高电平。

interrupts-extended = <&tlmm 55 IRQ_TYPE_LEVEL_HIGH>;
        Copy to clipboard
3. 驱动程序必须读取该值，并使用 `request_irq` API 将其作为中断注册到通用中断控制器 (GIC) 中，该 API 还指定了中断服务寄存器 (ISR) 和 IRQ 标志。

irq_no = platform_get_irq(pdev, 1);
        Copy to clipboard

## 配置 GPIOS 以生成时钟或脉冲宽度调制

将任意 GPIO 通过 `GP_CLK` 配置为替代功能，以获取时钟或脉冲宽度调制 (PWM)。

Note

以下步骤适用于 QCS6490 SoC。

有关如何使用 `GP_CLK` 函数查找 GPIO 的更多信息，请参阅 [Pin descriptions](https://docs.qualcomm.com/bundle/publicresource/topics/80-23889-1/pin-definitions.html#sub$pin-descriptions:~:text=and%20available%20configurations.-,Table%20%3A%20Pin%20descriptions%20%E2%80%93%20general%2Dpurpose%20input/output%20ports,-Pad%20number)。

1. 在 `kernel/arch/arm64/boot/dts/qcom/sc7280.dtsi` 文件中添加 GPIO 配置节点。

> 
> 
> +gpio_pwm_default: gpio_pwm_default {
>     +       mux {
>     +               pins = "gpio42";
>     +               function = "gcc_gp1";    // search "gcc_gp" in "kernel/drivers/pinctrl/qcom/pinctrl-sc7280.c", From this we can find out which GPIO's has GP_CLK functionality
>     +       };
>     +
>     +       config {
>     +               pins = "gpio42";
>     +               bias-disable; /* No PULL */
>     +               drive-strength = <8>; /* 2 MA */
>     +       };
>     +};
>     Copy to clipboard

2. 在 `kernel/arch/arm64/boot/dts/qcom/sc7280.dtsi` 文件中定义设备树节点。

+beeper: beeper {
        +       compatible = "gpio-beeper";
        +       pinctrl-names = "default";
        +       pinctrl-0 = <&gpio_pwm_default>;
        +       clocks = <&clock_gcc GCC_GP1_CLK>; //clock_gcc is gcc clk device node, GCC_GP1_CLK index which defined in "kernel/include/dt-bindings/clock/qcom,gcc-sc7280.h"
        +       clock-names = "gpio-pwm-clk";
        +};
        Copy to clipboard
3. 在设备驱动程序中添加以下代码：

+#include <linux/clk.h>
        +#include <linux/io.h>
        ...
        + struct clk *pclk;
        + struct rcg_clk *gp1_rcg_clk;
        + int ret;
        +
        + pclk = devm_clk_get(&pdev->dev, "gpio-pwm-clk");
        + ret = clk_set_rate(pclk, 50000000); // please check the freq table in kernel/drivers/clk/qcom/gcc-sc7280.c, the freq can be found in the freq table of GCC_GP1_CLK.
        + if (ret)
        +     printk("clk set rate fail, ret = %d\n", ret);
        +
        + ret = clk_prepare_enable(pclk);  // By default this will enable clock as PWM with 50% duty cycle.
        + if (ret)
        +     printk("%s: clk_prepare error!!!\n", __func__);
        + else
        +     printk("%s: clk_prepare success!\n", __func__);
        +
        Copy to clipboard
4. 如果不使用时钟或 PWM，请调用 `clk_disable_unprepare()` 禁用时钟以节省功耗。

Note

确保在调用 `clk_disable_unprepare()` 之前先调用 `clk_prepare_enable()`。
5. 要生成所需的占空比，请在调用 `clk_prepare_enable` API 之后调用 `clk_set_duty_cycle()` API。

## 从用户空间配置 GPIOS

使用用户空间的 `libgpiod` 库来控制 GPIOS，以获得更佳性能。

1. 要从主机编译和推送 `libgpiod` 库，请执行以下操作：

    1. 要安装 Arm^®^ (Arm64) 工具链，请运行以下命令：

sudo apt install gcc-aarch64-linux-gnu
            Copy to clipboard

sudo apt install binutils-aarch64-linux-gnu
            Copy to clipboard
    2. 要从 [libgpiod 1.6.4.tar.xz](https://www.kernel.org/pub/software/libs/libgpiod/libgpiod-1.6.4.tar.xz) 下载并提取 libgpiod 源代码，请运行以下命令：

wget https://www.kernel.org/pub/software/libs/libgpiod/libgpiod-1.6.4.tar.xz
            Copy to clipboard

tar xvf libgpiod-1.6.4.tar.xz
            Copy to clipboard

cd libgpiod-1.6.4
            Copy to clipboard
    3. 要配置静态链接的源代码，请运行以下命令：

./configure --enable-tools=yes --build x86_64-pc-linux-gnu --host aarch64-linux-gnu CFLAGS="-static -static-libgcc -Wl,-static,--start-group,/usr/lib/gcc-cross/aarch64-linux-gnu/7.5.0/libgcc.a,/usr/lib/gcc-cross/aarch64-linux-gnu/7.5.0/libgcc_eh.a,/usr/aarch64-linux-gnu/lib/libc.a,--end-group"
            Copy to clipboard
    4. 要编译库，请运行以下命令：

make
            Copy to clipboard

Note

编译会创建链接后的二进制文件。
    5. 要编译静态链接的二进制文件，请运行以下命令：

aarch64-linux-gnu-gcc -static -o tools/gpiodetect tools/gpiodetect.o tools/tools-common.o -Wl,-L<ABSOLUTE_PATH_TO_LIBGPIOD>/libgpiod-1.6.4/lib/.libs,-lgpiod,-lpthread,-static
            Copy to clipboard

aarch64-linux-gnu-gcc -static -o tools/gpioget tools/gpioget.o tools/tools-common.o -Wl,-L<ABSOLUTE_PATH_TO_LIBGPIOD>/libgpiod-1.6.4/lib/.libs,-lgpiod,-lpthread,-static
            Copy to clipboard

aarch64-linux-gnu-gcc -static -o tools/gpioset tools/gpioset.o tools/tools-common.o -Wl,-L<ABSOLUTE_PATH_TO_LIBGPIOD>/libgpiod-1.6.4/lib/.libs,-lgpiod,-lpthread,-static
            Copy to clipboard

aarch64-linux-gnu-gcc -static -o tools/gpiofind tools/gpiofind.o tools/tools-common.o -Wl,-L<ABSOLUTE_PATH_TO_LIBGPIOD>/libgpiod-1.6.4/lib/.libs,-lgpiod,-lpthread,-static
            Copy to clipboard

aarch64-linux-gnu-gcc -static -o tools/gpioinfo tools/gpioinfo.o tools/tools-common.o -Wl,-L<ABSOLUTE_PATH_TO_LIBGPIOD>/libgpiod-1.6.4/lib/.libs,-lgpiod,-lpthread,-static
            Copy to clipboard

aarch64-linux-gnu-gcc -static -o tools/gpiomon tools/gpiomon.o tools/tools-common.o -Wl,-L<ABSOLUTE_PATH_TO_LIBGPIOD>/libgpiod-1.6.4/lib/.libs,-lgpiod,-lpthread,-static
            Copy to clipboard
2. 要在编译后将二进制文件推送到设备，请运行 `scp` 命令。例如：

scp gpioinfo root@<IP_address>:/path/to/directory/on/device
        Copy to clipboard

将二进制文件推送到设备后，在设备上运行以下命令以与 GPIO 交互：

1. 使用 `gpiodetect` 和 `gpioinfo` 命令列出 GPIO 芯片和线路。以下示例展示了 GPIO 芯片信息：

sh-5.2# ./gpiodetect
        gpiochip0 [c440000.spmi:pmic@8:pinctrl@c00] (12 lines)
        gpiochip1 [c440000.spmi:pmic@1:gpio@8800] (10 lines)
        gpiochip2 [c440000.spmi:pmic@2:gpio@8800] (9 lines)
        gpiochip3 [c440000.spmi:pmic@0:gpio@b000] (4 lines)
        gpiochip4 [f100000.pinctrl] (176 lines)
        gpiochip5 [33c0000.pinctrl] (15 lines)
        Copy to clipboard

    以下示例显示了 GPIO 线路：

sh-5.2# ./gpioinfo gpiochip5
        gpiochip5 - 15 lines:
              line    0:      unnamed       unused   input   active-high
              line    1:      unnamed       unused   input   active-high
              line    2:      unnamed       unused   input   active-high
              line    3:      unnamed       unused   input   active-high
              line    4:      unnamed       unused   input   active-high
              line    5:      unnamed       unused   input   active-high
              line    6:      unnamed       unused   input   active-high
              line    7:      unnamed       unused   input   active-high
              line    8:      unnamed       unused   input   active-high
              line    9:      unnamed       unused   input   active-high
              line   10:      unnamed       unused   input   active-high
              line   11:      unnamed       unused   input   active-high
              line   12:      unnamed       unused   input   active-high
              line   13:      unnamed       unused   input   active-high
              line   14:      unnamed       unused   input   active-high
        Copy to clipboard
2. 使用 `gpioset` 命令设置 GPIO 值。例如，要在 `gpiochip4` 上设置 `GPIO line 0`，请执行以下操作：

sh-5.2# ./gpioset gpiochip4 0=1
        sh-5.2# ./gpioinfo gpiochip4
        gpiochip4 - 176 lines:
           line    0:      unnamed       unused   output  active-high
           line    1:      unnamed       unused   input   active-high
        Copy to clipboard
3. 使用 `gpioget` 命令读取 GPIO 值。例如，要在 `gpiochip4` 上读取 `GPIO line 0` 的值，请执行以下操作：

sh-5.2# ./gpioget gpiochip4 0
        1
        sh-5.2# ./gpioinfo gpiochip4
        gpiochip4 - 176 lines:
                 line    0:      unnamed       unused   input   active-high
                 line    1:      unnamed       unused   input   active-high
        Copy to clipboard

Last Published: Jul 22, 2025

[Previous Topic
配置动态电压和频率调节 (DVFS) 调速器](https://docs.qualcomm.com/bundle/publicresource/80-70020-3SC/topics/dynamic-clock-and-voltage-scaling-dcvs.md) [Next Topic
实时 (RT) 内核概述](https://docs.qualcomm.com/bundle/publicresource/80-70020-3SC/topics/real_time_kernel_overview.md)