> ## Documentation Index
> Fetch the complete documentation index at: https://dragonwingdocs-staging.qualcomm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 配置 pinctrl 驱动程序

Qualcomm<sup>®</sup> Linux 内核中的 Pinctrl 子系统管理和配置用于通用输入/输出（GPIO）、集成电路间（I2C）、串行外设接口（SPI）和其他硬件接口的引脚。

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

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

其他受支持目标的对应 pinctrl 驱动程序位于以下文件中：

* QCS5430：`kernel-src/drivers/pinctrl/qcom/pinctrl-sc7280.c`
* IQ-9075：`kernel-src/drivers/pinctrl/qcom/pinctrl-sa8775p.c`
* IQ-8275：`kernel-src/drivers/pinctrl/qcom/pinctrl-qcs8300.c`
* IQ-615：`kernel-src/drivers/pinctrl/qcom/pinctrl-qcs615.c`

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

以下是 pinctrl 数据对象：

**表：Pinctrl 数据对象**

|                        **变量**                       |       **描述**       |
| :-------------------------------------------------: | :----------------: |
| static const struct pinctrl\_pin\_desc sc7280\_pins |     枚举所有引脚及其名称     |
|   static const struct msm\_pingroup sc7280\_groups  | 定义 GPIO 引脚组的可用复用功能 |
|                enum sc7280\_functions               |    将所有可用功能列为枚举值    |

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

**功能选择**

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

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

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

```text theme={null}
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";
    };
```

## 配置 GPIO 用法

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

* 复用（Mux）：mux 设置需要从 SoC 特定 pinctrl 驱动程序中一组可用功能中选择映射的功能名称。有关 pinctrl 的更多信息，请参见 [Pinctrl configuration](https://dragonwingdocs-staging.qualcomm.com/System/Kernel/configure-the-pinctrl-driver)。
* 配置：配置方面需要设置驱动强度和偏置属性。

以下示例展示了这两个设置如何使用以下过程定义 GPIO 引脚：

1. 在设备树中定义引脚配置：
   ```text theme={null}
   bt_en: bt-en-state {
      pins = "gpio85";
      function = "gpio";
      output-low;
      bias-disable;
   };
   ```
2. 在设备树中配置设备节点或知识产权（IP）块：
   ```text theme={null}
   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>;
   ```
3. 驱动程序代码必须使用通用 API 在 pinctrl 配置中选择并注册其 GPIO 配置。以下是可用 API 的示例：
   > ```text theme={null}
   > 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.
   > */
   > ```

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

要将 GPIO 设置为 IRQ，请使用以下过程：

1. 在 DTS 文件中配置 GPIO 引脚：
   1. 设置 GPIO 引脚的属性和功能。
   2. 使用以下配置将引脚设置为使用 GPIO 55 用于 `qup_se_l3()` 功能：
      ```text theme={null}
      qupv3_se3_rx: qupv3-se3-rx-state {
         pins = "gpio55";
         function = "qup03"; // To be taken from available from functions.
         drive-strength = <2>;
         bias-disable;
      };
      ```
2. 为您要将 GPIO 设置为 IRQ 的设备节点创建一个与上述配置类似的 DT 条目。在以下示例中，GPIO55 配置为 IRQ，父级为顶层模式多路复用器（TLMM），电平设置为高。
   ```text theme={null}
   interrupts-extended = <&tlmm 55 IRQ_TYPE_LEVEL_HIGH>;
   ```
3. 驱动程序必须读取该值，并使用 `request_irq` API 将其注册为通用中断控制器（GIC）的中断，同时指定中断服务寄存器（ISR）和 IRQ 标志。
   ```text theme={null}
   irq_no = platform_get_irq(pdev, 1);
   ```

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

将任何 GPIO 配置为 `GP_CLK` 作为备用功能，以获取时钟或脉冲宽度调制（PWM）。

<Note>
  以下过程适用于 QCS6490 SoC。
</Note>

有关如何查找具有 `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 配置节点。

> ```text theme={null}
> +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 */
> +       };
> +};
> ```

2. 在 `kernel/arch/arm64/boot/dts/qcom/sc7280.dtsi` 文件中定义设备树节点。
   ```text theme={null}
   +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";
   +};
   ```
3. 在设备驱动程序中添加以下代码：
   ```text theme={null}
   +#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__);
   +
   ```
4. 如果您不使用时钟或 PWM，请调用 `clk_disable_unprepare()` 以禁用时钟以节省功耗。**注意** 确保先调用 `clk_prepare_enable()` 然后再调用 `clk_disable_unprepare()`。
5. 要生成所需的占空比，请在 `clk_prepare_enable` API 之后调用 `clk_set_duty_cycle()` API。

## 从用户空间配置 GPIO

使用用户空间的 `libgpiod` 库来控制 GPIO 以获得更好的性能。

1. 要从主机计算机编译并推送 `libgpiod` 库，请执行以下操作：
   1. 要安装 Arm<sup>®</sup>（Arm64）工具链，请运行以下命令：
      ```text theme={null}
      sudo apt install gcc-aarch64-linux-gnu
      ```
      ```text theme={null}
      sudo apt install binutils-aarch64-linux-gnu
      ```
   2. 要从 [libgpiod 1.6.4.tar.xz](https://www.kernel.org/pub/software/libs/libgpiod/libgpiod-1.6.4.tar.xz) 下载并解压 libgpiod 源代码，请运行以下命令：
      ```text theme={null}
      wget https://www.kernel.org/pub/software/libs/libgpiod/libgpiod-1.6.4.tar.xz
      ```
      ```text theme={null}
      tar xvf libgpiod-1.6.4.tar.xz
      ```
      ```text theme={null}
      cd libgpiod-1.6.4
      ```
   3. 要为静态链接配置源代码，请运行以下命令：
      ```text theme={null}
      ./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"
      ```
   4. 要编译库，请运行以下命令：
      ```text theme={null}
      make
      ```
      **注意** 编译会创建链接二进制文件。
   5. 要构建静态链接的二进制文件，请运行以下命令：
      ```text theme={null}
      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
      ```
      ```text theme={null}
      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
      ```
      ```text theme={null}
      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
      ```
      ```text theme={null}
      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
      ```
      ```text theme={null}
      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
      ```
      ```text theme={null}
      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
      ```
2. 编译后要将二进制文件推送到您的设备，请运行 `scp` 命令。例如：
   ```text theme={null}
   scp gpioinfo root@<IP_address>:/path/to/directory/on/device
   ```

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

1. 使用 `gpiodetect` 和 `gpioinfo` 命令列出 GPIO 芯片和线路。以下示例显示 GPIO 芯片信息：
   ```text theme={null}
   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)
   ```
   以下示例显示 GPIO 线路：
   ```text theme={null}
   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
   ```
2. 使用 `gpioset` 命令设置 GPIO 值。例如，要在 `gpiochip4` 上设置 `GPIO line 0`，请执行以下操作：
   ```text theme={null}
   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
   ```
3. 使用 `gpioget` 命令读取 GPIO 值。例如，要读取 `gpiochip4` 上 `GPIO line 0` 的值，请执行以下操作：
   ```text theme={null}
   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
   ```
