> ## 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.

# Configure the pinctrl driver

The Pinctrl subsystem in the Qualcomm<sup>®</sup> Linux kernel manages and configures pins used for general-purpose input/output (GPIO), interintegrated circuit (I2C), serial peripheral interface (SPI), and other hardware interfaces.

Pinctrl configurations, such as **pin muxing** and **pin groupings**, are managed in the device-specific pinctrl drivers, where the drivers list all the available pins and functions.

For example, the corresponding driver for QCS6490 is available in the `kernel-src/drivers/pinctrl/qcom/pinctrl-sc7280.c` file.

<Note>
  For more information about additional Qualcomm SoC pinctrl drivers, see [Pinctrl Drivers](https://github.com/torvalds/linux/tree/master/drivers/pinctrl/qcom).
</Note>

The following are the pinctrl data objects:

**Table: Pinctrl data objects**

|                     **Variable**                    |                          **Description**                         |
| :-------------------------------------------------: | :--------------------------------------------------------------: |
| static const struct pinctrl\_pin\_desc sc7280\_pins |                Enumerates all pins and their names               |
|   static const struct msm\_pingroup sc7280\_groups  | Defines the available muxed functions for the group of GPIO pins |
|                enum sc7280\_functions               |         Lists all the available functions as enum values         |

\
For more information about the supported functions of the respective SoC pinctrl binding documentation for QCS6490, see [pinctrl binding documentation](https://www.kernel.org/doc/Documentation/devicetree/bindings/pinctrl/qcom%2Csc7280-pinctrl.yaml).

**Function selection**

For a `sc7280_functions` data object, one or multiple GPIO pins are used as a function and must be registered to the device tree and passed to the right device node.

During system boot, the kernel pinctrl infrastructure registers the functions.

The following example shows the kernel configuration infrastructure:

```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";
    };
```

## Configure the GPIO usage

GPIO pin configuration requires the following two settings. The settings define a GPIO pin state and make those pins available for any input/output activity.

* Mux: The mux setting requires selecting the function name that is mapped from the set of available functions in the SoC-specific pinctrl driver. For more information about pinctrl, see [Pinctrl configuration](https://docs.qualcomm.com/doc/80-80021-3/topic/pinctrl-configuration.html?product=895724676033554725\&facet=Kernel\&version=2.0-rc2#pinctrl-configuration).
* Configuration: The configuration aspect requires setting the drive strength and bias property.

The following examples show how the two settings define the GPIO pin using the following procedures:

1. Define the pin configuration in the device tree:
   ```text theme={null}
   bt_en: bt-en-state {
      pins = "gpio85";
      function = "gpio";
      output-low;
      bias-disable;
   };
   ```
2. Configure the device node or intellectual property (IP) block in the device tree:
   ```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. The driver code must use generic APIs to select and register their GPIO configurations within the pinctrl configurations. The following is an example of available APIs:
   > ```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 as interrupt request (IRQ)**

To set the GPIO as an IRQ, use the following procedure:

1. Configure the GPIO pin in the DTS file:
   1. Set the properties and the function for the GPIO pin.
   2. Set the pin to use GPIO 55 for the `qup_se_l3()` function with the following configurations:
      ```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. Create a DT entry like the previous configuration for the device node where you want set the GPIO as an IRQ. In the following example, the GPIO55 is configured as an IRQ with the parent as a top-level mode multiplexer (TLMM) and the level is set to high.
   ```text theme={null}
   interrupts-extended = <&tlmm 55 IRQ_TYPE_LEVEL_HIGH>;
   ```
3. The driver must read the value and register it as an interrupt to the generic interrupt controller (GIC) using the `request_irq` API specifying the interrupt service register (ISR) and IRQ flags.
   ```text theme={null}
   irq_no = platform_get_irq(pdev, 1);
   ```

## Configure GPIOs to generate clock or pulse width modulation

Configure any GPIO with the `GP_CLK` as an alternate functionality to get clock or pulse width modulation (PWM).

<Note>
  The following procedure is applicable to QCS6490 SoCs.
</Note>

For more information about how to find a GPIO with the `GP_CLK` function, see the [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. Add GPIO configuration node in `kernel/arch/arm64/boot/dts/qcom/sc7280.dtsi` file.

> ```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. Define device tree node in `kernel/arch/arm64/boot/dts/qcom/sc7280.dtsi` file.
   ```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. Add the following code in the device driver:
   ```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. If you do not use clock or PWM, call `clk_disable_unprepare()` to disable the clock to save power. **Note** Ensure to call `clk_prepare_enable()` first before calling `clk_disable_unprepare()`.
5. To generate the required duty cycle, call `clk_set_duty_cycle()` API after `clk_prepare_enable` API.

## Configure GPIOs from the user space

Use the `libgpiod` library from the user space to control the GPIOS for better performance.

1. To compile and push `libgpiod` library from the host computer, do the following:
   1. To install Arm<sup>®</sup> (Arm64) toolchain, run the following commands:
      ```text theme={null}
      sudo apt install gcc-aarch64-linux-gnu
      ```
      ```text theme={null}
      sudo apt install binutils-aarch64-linux-gnu
      ```
   2. To download and extract the libgpiod source code from [libgpiod 1.6.4.tar.xz](https://www.kernel.org/pub/software/libs/libgpiod/libgpiod-1.6.4.tar.xz), run the following commands:
      ```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. To configure the sources for static linking, run the following command:
      ```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. To compile the library, run the following command:
      ```text theme={null}
      make
      ```
      **Note** Compiling creates linked binaries.
   5. To build statically linked binaries, run the following commands:
      ```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. To push the binaries to your device after compilation, run the `scp` command. For example:
   ```text theme={null}
   scp gpioinfo root@<IP_address>:/path/to/directory/on/device
   ```

After pushing the binaries to your device, run the following commands on the device to interact with the GPIOs:

1. Use the `gpiodetect` and `gpioinfo` commands to list the GPIO chips and lines. The following example shows the GPIO chip information:
   ```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)
   ```
   The following example shows the GPIO lines:
   ```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. Use the `gpioset` command to set GPIO values. For example, to set `GPIO line 0` on `gpiochip4`, do the following:
   ```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. Use the `gpioget` command to read GPIO values. For example, to read the value of `GPIO line 0` on `gpiochip4`, do the following:
   ```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
   ```
