# pinctrl 드라이버 구성

Qualcomm Linux 커널의 Pinctrl 서브시스템은 범용 입출력(GPIO), 집적 회로 인터페이스(I2C), 시리얼 주변장치 인터페이스(SPI) 및 기타 하드웨어 인터페이스에 사용되는 핀을 관리하고 구성합니다.

**pin muxing** 및 **pin groupings** 같은 Pinctrl 구성은 기기별 pinctrl 드라이버에서 관리되는데, 이 드라이버는 사용 가능한 모든 핀과 기능을 나열합니다.

예를 들어, QCS6490의 해당하는 드라이버는 `kernel-src/drivers/pinctrl/qcom/pinctrl-sc7280.c` 파일에서 사용할 수 있습니다.

참고

추가적인 Qualcomm SoC pinctrl 드라이버에 대한 자세한 내용은 [Pinctrl Drivers](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 binding documentation](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-3KO/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. 드라이버 코드는 pinctrl 구성 내에서 GPIO 구성을 선택하고 등록하려면 일반적인 API를 사용해야 합니다.

    다음은 사용 가능한 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. 다음 구성을 사용하여 `qup_se_l3()` 함수에 GPIO 55를 사용하도록 핀을 설정합니다.

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 항목을 생성합니다.

    다음 예시에서는 GPIO55가 IRQ로 구성되어 있으며, 상위 항목은 최상위 모드 멀티플렉서(TLMM)로 설정되어 있고 수준은 높음으로 설정되어 있습니다.

interrupts-extended = <&tlmm 55 IRQ_TYPE_LEVEL_HIGH>;
        Copy to clipboard
3. 드라이버는 인터럽트 서비스 레지스터(ISR) 및 IRQ 플래그를 지정하는 `request_irq` API를 사용하여 일반 인터럽트 컨트롤러(GIC)에 인터럽트를 등록하려면 해당 값을 읽고 이를 등록해야 합니다.

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

## GPIOS를 구성하여 클럭 또는 펄스 폭 변조 생성

`GP_CLK` 가 포함된 GPIO를 대체 기능으로 구성하여 클럭 또는 펄스 폭 변조(PWM)를 구할 수 있습니다.

참고

다음 절차는 QCS6490 SoC에 적용됩니다.

`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 구성 노드를 추가합니다.

> 
> 
> +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` 파일에서 `devicetree` 노드를 정의합니다.

+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()` 를 호출하여 클럭을 비활성화합니다.

참고

`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

참고

컴파일링을 수행하면 연결된 바이너리가 생성됩니다.
    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: Jan 01, 2026

[Previous Topic
동적 전압 및 주파수 스케일링(DVFS) 관리자 구성](https://docs.qualcomm.com/bundle/publicresource/80-70020-3KO/topics/dynamic-clock-and-voltage-scaling-dcvs.md) [Next Topic
실시간(RT) 커널 개요](https://docs.qualcomm.com/bundle/publicresource/80-70020-3KO/topics/real_time_kernel_overview.md)