Skip to content

# 7.1.1. GPIO使用

J6X Acore芯片内中共有3个sys有gpio设备，分别是peri, cam和video，每个设备最多有32个gpio引脚，并且每个gpio引脚都支持中断。

## 7.1.1.1. 驱动层使用

### 7.1.1.1.1. GPIO DTS配置

GPIO设备树节点的属性命名方式一般为<names>-gpios或<names>-gpio，举例如下：

    /**
    * peri_port0表示peri sys的第一个gpio设备
    * 下列设备节点共有四个gpio引脚，分别是：
    *       peri sys的第一个gpio设备 16号引脚(从0开始)
    *       peri sys的第二个gpio设备 17号引脚(从0开始)
    *        cam sys的第一个gpio设备 28号引脚(从0开始)
    *      video sys的第一个gpio设备 18号引脚(从0开始)
    * GPIO_ACTIVE_HIGH表示高电平有效，一般设为GPIO_ACTIVE_HIGH
    */
    gpio-test {
            test-gpios = <&peri_port0 16 GPIO_ACTIVE_HIGH
                          &peri_port1 17 GPIO_ACTIVE_HIGH
                          &cam_port0 28 GPIO_ACTIVE_HIGH
                          &video_port0 18 GPIO_ACTIVE_HIGH>;
    };

### 7.1.1.1.2. GPIO驱动API

包含头文件

    #include <linux/gpio/consumer.h>

#### 7.1.1.1.2.1. 从设备树中获取释放gpio

    struct gpio_desc *gpiod_get(struct device *dev, const char *con_id,
                                        enum gpiod_flags flags)

    struct gpio_desc *gpiod_get_index(struct device *dev,
                                              const char *con_id, unsigned int idx,
                                              enum gpiod_flags flags)

    struct gpio_desc *gpiod_get_optional(struct device *dev,
                                        const char *con_id,
                                        enum gpiod_flags flags)

    struct gpio_desc *gpiod_get_index_optional(struct device *dev,
                                              const char *con_id,
                                                       unsigned int index,
                                                       enum gpiod_flags flags)

    struct gpio_descs *gpiod_get_array(struct device *dev,
                                              const char *con_id,
                                              enum gpiod_flags flags)

    struct gpio_descs {
          struct gpio_array *info;
          unsigned int ndescs;
          struct gpio_desc *desc[];
    }

    struct gpio_descs *gpiod_get_array_optional(struct device *dev,
                                                       const char *con_id,
                                                       enum gpiod_flags flags)

    struct gpio_desc *devm_gpiod_get(struct device *dev, const char *con_id,
                                     enum gpiod_flags flags)

    struct gpio_desc *devm_gpiod_get_index(struct device *dev,
                                           const char *con_id,
                                           unsigned int idx,
                                           enum gpiod_flags flags)

    struct gpio_desc *devm_gpiod_get_optional(struct device *dev,
                                              const char *con_id,
                                              enum gpiod_flags flags)

    struct gpio_desc *devm_gpiod_get_index_optional(struct device *dev,
                                                    const char *con_id,
                                                    unsigned int index,
                                                    enum gpiod_flags flags)

    struct gpio_descs *devm_gpiod_get_array(struct device *dev,
                                           const char *con_id,
                                           enum gpiod_flags flags)

    struct gpio_descs *devm_gpiod_get_array_optional(struct device *dev,
                                                    const char *con_id,
                                                    enum gpiod_flags flags)

    void gpiod_put(struct gpio_desc *desc)

    void gpiod_put_array(struct gpio_descs *descs)

    void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)

    void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs)

#### 7.1.1.1.2.2. gpio的使用：方向设置，输出，输入

    int gpiod_direction_input(struct gpio_desc *desc)
    int gpiod_direction_output(struct gpio_desc *desc, int value)

    int gpiod_get_direction(const struct gpio_desc *desc)

    int gpiod_get_value(const struct gpio_desc *desc);
    void gpiod_set_value(struct gpio_desc *desc, int value);

    int gpiod_get_raw_value(const struct gpio_desc *desc)
    void gpiod_set_raw_value(struct gpio_desc *desc, int value)

    int gpiod_direction_output_raw(struct gpio_desc *desc, int value)

    int gpiod_get_array_value(unsigned int array_size,
                            struct gpio_desc **desc_array,
                            struct gpio_array *array_info,
                            unsigned long *value_bitmap);
    int gpiod_get_raw_array_value(unsigned int array_size,
                                  struct gpio_desc **desc_array,
                                  struct gpio_array *array_info,
                                  unsigned long *value_bitmap);

    int gpiod_set_array_value(unsigned int array_size,
                            struct gpio_desc **desc_array,
                            struct gpio_array *array_info,
                            unsigned long *value_bitmap)
    int gpiod_set_raw_array_value(unsigned int array_size,
                                  struct gpio_desc **desc_array,
                                  struct gpio_array *array_info,
                                  unsigned long *value_bitmap)

#### 7.1.1.1.2.3. 可睡眠api的使用和场景

    /* 一般加_cansleep后缀的可睡眠的api用于i2c，spi或者其他接口的扩展GPIO */

    /* 查看gpio是否可睡眠 */

    int gpiod_cansleep(const struct gpio_desc *desc)

    /* 可睡眠api使用 */
    int gpiod_get_value_cansleep(const struct gpio_desc *desc)
    void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
    int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
    void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)

    int gpiod_get_array_value_cansleep(unsigned int array_size,
                                     struct gpio_desc **desc_array,
                                     struct gpio_array *array_info,
                                     unsigned long *value_bitmap);
    int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
                                     struct gpio_desc **desc_array,
                                     struct gpio_array *array_info,
                                     unsigned long *value_bitmap);

    int gpiod_set_array_value_cansleep(unsigned int array_size,
                                     struct gpio_desc **desc_array,
                                     struct gpio_array *array_info,
                                     unsigned long *value_bitmap)
    int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
                                           struct gpio_desc **desc_array,
                                           struct gpio_array *array_info,
                                           unsigned long *value_bitmap)

#### 7.1.1.1.2.4. gpio描述符和中断号的转换

    int gpiod_to_irq(const struct gpio_desc *desc)

#### 7.1.1.1.2.5. gpio描述符和gpio号的转换

    int desc_to_gpio(const struct gpio_desc *desc)
    struct gpio_desc *gpio_to_desc(unsigned gpio)

## 7.1.1.2. 用户层使用

在用户层可以使用/sys/class/gpio节点来进行相关gpio的操作。

在sys节点下存在如下节点：

    #申请gpio
    echo <gpio_num> > /sys/class/gpio/export
    #释放gpio
    echo <gpio_num> > /sys/class/gpio/unexport
    #设置gpio为输出
    #当设置dir为out时，可以向value中echo 1/0，分别表示输入高低电平。
    echo out > /sys/class/gpio/gpio<gpio_num>/direction
    #设置高电平
    echo 1 > /sys/class/gpio/gpio<gpio_num>/value
    #设置低电平
    echo 0 > /sys/class/gpio/gpio<gpio_num>/value

    #设置gpio为输入, 当设置dir为in时，cat value表示输入的值(0-低，1-高)。
    echo in > /sys/class/gpio/gpio<gpio_num>/direction
    #读取gpio的外部值
    cat /sys/class/gpio/gpio<gpio_num>/value

    #查看gpio的debug接口
    cat /sys/kernel/debug/gpio

    #查看gpio和pinctrl的关系
    #可以看到系统的引脚和gpio的号关系
    cat /sys/kernel/debug/pinctrl/<pinctrl_dev>/gpio-ranges

### 7.1.1.2.1. sysfs接口介绍

#### 7.1.1.2.1.1. export&unexport

/sys/class/gpio/export和/sys/class/gpio/unexport，这两个节点只能写不能读。

用户程序通过写入gpio的编号来向内核申请将某个gpio的控制权导出到用户空间，前提是没有内核代码申请这个gpio端口，如用户申请编号为480的GPIO的命令：

    echo 480 > export

上述操作会为480号gpio创建一个节点gpio480，此时/sys/class/gpio目录下边生成一个gpio480的目录。

/sys/class/gpio/unexport和导出的效果相反，比如移除gpio480这个节点操作命令：

    echo 480 > unexport #该操作将会移除gpio480这个节点，释放序号为480的gpio。

#### 7.1.1.2.1.2. direction

其中direction表示gpio端口的方向，读取结果是in或out。也可以对该文件进行写操作，写入out时该gpio设为输出，写入in时该gpio设为输入。

#### 7.1.1.2.1.3. value

当设置dir为in时，cat value表示输入的值(0-低，1-高)。

当设置dir为out时，可以向value中echo 1/0，分别表示输入高低电平。

#### 7.1.1.2.1.4. edge

用户层设置中断时，direction需要设置为in，然后向edge中设置相应的值。

edge的值 | 含义
--- | ---
none | 表示引脚为输入，不是中断引脚
rising | 表示引脚为中断输入，上升沿触发
falling | 表示引脚为中断输入，下降沿触发
both | 表示引脚为中断输入，边沿触发

## 7.1.1.3. 调试

    cat /sys/kernel/debug/gpio

查询上述节点，可以获取到当前系统中正在使用的gpio和所处的状态（in，out，IRQ）。

    root@hobot:~# cat /sys/kernel/debug/gpio
    gpiochip4: GPIOs 423-438, parent: i2c/3-0076, 3-0076, can sleep:
    gpio-423 (                    |io-ser-reset0       ) out hi
    gpio-424 (                    |io-ser-reset1       ) out hi
    gpio-425 (                    |io-ser-reset2       ) out hi
    gpio-426 (                    |io-ser-reset3       ) out hi

    gpiochip3: GPIOs 439-455, parent: platform/360b0000.gpio, 360b0000.gpio:

    gpiochip2: GPIOs 456-473, parent: platform/370f5000.gpio, 370f5000.gpio:

    gpiochip1: GPIOs 474-479, parent: platform/39500000.gpio, 39500000.gpio:

    gpiochip0: GPIOs 480-511, parent: platform/394f0000.gpio, 394f0000.gpio:
    gpio-481 (                    |sysfs               ) out hi ACTIVE LOW
    gpio-491 (                    |sysfs               ) in  hi
    gpio-495 (                    |sysfs               ) in  hi
    gpio-496 (                    |sysfs               ) in  hi
    gpio-498 (                    |sysfs               ) in  hi
    gpio-503 (                    |io-ext-reset        ) out lo
    root@hobot:~#

## 7.1.1.4. 确定gpio-index

kernel_index = base + offset，base 通过 “/sys/class/gpio” 或者“/sys/kernel/debug/gpio” 获取，offset通过dts获取。

以pin sensor8_err为例：通过查看 hobot-pinctrl-j6e.dtsi，可以知道sensor8_err对应的gpio chip是”video_port0: gpio@360b0000”，对应的offset是 13。 查看/sys/kernel/debug/gpio，可知“video_port0: gpio@360b0000”对应的base是439，则sensor8_err对应的gpio kernel index是：439 + 13 = 452。

### 7.1.1.4.1. 查看hobot-pinctrl-j6e.dtsi，获取offset和base。

下面设备树可知sensor8_err对应video_sensor8_err，对应的gpio chip是”video_port0: gpio@360b0000”。 video_gnss_int的offset为0，递增计数，则video_sensor8_err的offset为13。

    pinctrl_video: pinctrl@36090000 {
       compatible = "horizon,j6e-pinctrl";
       reg = <0x0 0x36090000 0x0 0x1000>,
             <0x0 0x360a0000 0x0 0x1000>;
       pctldev-name = "video";
       status = "okay";

       video_gpio: video_gpio_func {
          pinmux {
             function = "video_gpio";
             pins = "video_gnss_int", "video_peri_rsto",
                      "video_cam_pint", "video_sd_1v8", "video_sd_bus_pow",
                      "video_sensor0_err", "video_sensor1_err",
                      "video_sensor2_err", "video_sensor3_err", "video_sensor4_err",
                      "video_sensor5_err", "video_sensor6_err",
                      "video_sensor7_err", "video_sensor8_err",
                      "video_sensor9_err", "video_sensor10_err", "video_sensor11_err";
          };
          pinconf {
             pins = "video_gnss_int", "video_peri_rsto",
                      "video_cam_pint", "video_sd_1v8", "video_sd_bus_pow",
                      "video_sensor0_err", "video_sensor1_err",
                      "video_sensor2_err", "video_sensor3_err", "video_sensor4_err",
                      "video_sensor5_err", "video_sensor6_err",
                      "video_sensor7_err", "video_sensor8_err",
                      "video_sensor9_err", "video_sensor10_err", "video_sensor11_err";
             drive-strength = <1>;
          };
       };

如这行：gpiochip3: GPIOs 439-455, parent: platform/360b0000.gpio, 360b0000.gpio: “GPIOs 439-455”代表base是439

    cat /sys/kernel/debug/gpio

    root@hobot:~# cat /sys/kernel/debug/gpio
    gpiochip4: GPIOs 423-438, parent: i2c/3-0076, 3-0076, can sleep:
    gpio-423 (                    |io-ser-reset0       ) out hi
    gpio-424 (                    |io-ser-reset1       ) out hi
    gpio-425 (                    |io-ser-reset2       ) out hi
    gpio-426 (                    |io-ser-reset3       ) out hi

    gpiochip3: GPIOs 439-455, parent: platform/360b0000.gpio, 360b0000.gpio:

    gpiochip2: GPIOs 456-473, parent: platform/370f5000.gpio, 370f5000.gpio:
    gpio-464 (                    |scl                 ) out lo
    gpio-465 (                    |sda                 ) in  lo
    gpio-466 (                    |scl                 ) out lo
    gpio-467 (                    |sda                 ) in  lo
    gpio-468 (                    |scl                 ) out lo
    gpio-469 (                    |sda                 ) in  lo
    gpio-470 (                    |scl                 ) out lo
    gpio-471 (                    |sda                 ) in  lo
    gpio-472 (                    |scl                 ) out lo
    gpio-473 (                    |sda                 ) in  lo

    gpiochip1: GPIOs 474-479, parent: platform/39500000.gpio, 39500000.gpio:

    gpiochip0: GPIOs 480-511, parent: platform/394f0000.gpio, 394f0000.gpio:
    gpio-495 (                    |scl                 ) out lo
    gpio-496 (                    |sda                 ) in  lo
    gpio-503 (                    |io-ext-reset        ) out lo