> ## Documentation Index
> Fetch the complete documentation index at: https://dragonwingdocs.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 配置（例如**引脚复用（pin muxing）**和**引脚分组（pin groupings）**）在特定于设备的 pinctrl 驱动中管理，这些驱动列出了所有可用的引脚和功能。

例如，QCS6490 对应的驱动位于 `kernel-src/drivers/pinctrl/qcom/pinctrl-sc7280.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 绑定文档](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）：复用设置需要从特定于 SoC 的 pinctrl 驱动中可用功能集里选择所映射的功能名称。有关 pinctrl 的更多信息，请参阅 [Pinctrl 配置](https://docs.qualcomm.com/doc/80-80021-3/topic/pinctrl-configuration.html?product=895724676033554725\&facet=Kernel\&version=2.0-rc2#pinctrl-configuration)。
* 配置（Configuration）：配置方面需要设置驱动强度（drive strength）和偏置（bias）属性。

以下示例展示了如何通过以下步骤用这两项设置定义 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（指定中断服务寄存器（ISR）和 IRQ 标志）将其作为中断注册到通用中断控制器（GIC）。
   ```text theme={null}
   irq_no = platform_get_irq(pdev, 1);
   ```

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

将任何具有 `GP_CLK` 备用功能的 GPIO 配置为时钟或脉宽调制（PWM）输出。

<Note>
  以下步骤适用于 QCS6490 SoC。
</Note>

有关如何查找具有 `GP_CLK` 功能的 GPIO 的更多信息，请参阅[引脚描述](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_disable_unprepare()` 之前先调用 `clk_prepare_enable()`。
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
   ```
