GPIO使用参考


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 10/30/2022

    1. 概述

    General Purpose Input Output (通用输入/输出)简称为GPIO。GPIO 采用标准的LINUX框架,能够使用统一的接口来操作gpio。

    Figure 1: GPIO框架

    GPIO的框架如上图,中间层是 gpiolib,用于管理系统中的 GPIO。gpiolib 汇总了 GPIO 的通用操作,根据 GPIO 的特性,gpiolib 对上(其他 Drivers)提供的一套统一通用的操作 GPIO 的软件接口。对下,Gpiolib 提供了针对不同芯片操作的一套 framework,针对不同芯片,只需要实现mdrv_gpio_io.c,然后使用 Gpiolib 提供的注册函数,将其挂接到 Gpiolib 上。

    2. GPIO NUM与PAD对应表

    请通过原理图上GPIO 的Pad name在表1-1中查找对应的GPIO Index,GPIO Index作为软件操作GPIO相关函数的输入参数使用。

    例如:希望操作的GPIO为 PAD_KEY1,根据表1-1中的内容找到对应的GPIO Index为12。

    表1-1:GPIO NUM与PAD对应表

    Pad Name GPIO Index Pad Name GPIO Index Pad Name GPIO Index Pad Name GPIO Index
    PAD_I2C5_SCL 0 PAD_I2C5_SDA 1 PAD_SD0_GPIO0 2 PAD_SD0_VCTRL 3
    PAD_SD0_CDZ 4 PAD_SD0_D1 5 PAD_SD0_D0 6 PAD_SD0_CLK 7
    PAD_SD0_CMD 8 PAD_SD0_D3 9 PAD_SD0_D2 10 PAD_KEY0 11
    PAD_KEY1 12 PAD_KEY2 13 PAD_KEY3 14 PAD_KEY4 15
    PAD_KEY5 16 PAD_KEY6 17 PAD_KEY7 18 PAD_KEY8 19
    PAD_KEY9 20 PAD_KEY10 21 PAD_KEY11 22 PAD_KEY12 23
    PAD_KEY13 24 PAD_PM_PWM0 25 PAD_PM_PWM1 26 PAD_PM_I2CM_SCL 27
    PAD_PM_I2CM_SDA 28 PAD_PM_UART_RX0 29 PAD_PM_UART_TX0 30 PAD_PM_IR_RX 31
    PAD_PM_GPIO0 32 PAD_PM_GPIO1 33 PAD_PM_GPIO2 34 PAD_PM_GPIO3 35
    PAD_PM_GPIO4 36 PAD_PM_GPIO5 37 PAD_PM_SPI_WPZ 38 PAD_PM_SPI_DO 39
    PAD_PM_SPI_CZ 40 PAD_PM_SPI_HLD 41 PAD_PM_SPI_CK 42 PAD_PM_SPI_DI 43
    PAD_SAR_GPIO0 44 PAD_SAR_GPIO1 45 PAD_EMMC_RSTN 46 PAD_EMMC_CLK 47
    PAD_EMMC_CMD 48 PAD_EMMC_DS 49 PAD_EMMC_D3 50 PAD_EMMC_D4 51
    PAD_EMMC_D0 52 PAD_EMMC_D5 53 PAD_EMMC_D1 54 PAD_EMMC_D6 55
    PAD_EMMC_D2 56 PAD_EMMC_D7 57 PAD_OUTP_RX1_CH_0 58 PAD_OUTN_RX1_CH_0 59
    PAD_OUTP_RX1_CH_1 60 PAD_OUTN_RX1_CH_1 61 PAD_OUTP_RX1_CH_2 62 PAD_OUTN_RX1_CH_2 63
    PAD_OUTP_RX1_CH_3 64 PAD_OUTN_RX1_CH_3 65 PAD_OUTP_RX0_CH_0 66 PAD_OUTN_RX0_CH_0 67
    PAD_OUTP_RX0_CH_1 68 PAD_OUTN_RX0_CH_1 69 PAD_OUTP_RX0_CH_2 70 PAD_OUTN_RX0_CH_2 71
    PAD_OUTP_RX0_CH_3 72 PAD_OUTN_RX0_CH_3 73 PAD_OUTP_RX0_CH_4 74 PAD_OUTN_RX0_CH_4 75
    PAD_OUTP_RX0_CH_5 76 PAD_OUTN_RX0_CH_5 77 PAD_SPDIF_TX 78 PAD_SR_IO3 79
    PAD_SR_IO2 80 PAD_SR_IO1 81 PAD_SR_IO0 82 PAD_SR_PDN1 83
    PAD_SR_MCLK1 84 PAD_SR_RST1 85 PAD_I2C1_SDA 86 PAD_I2C1_SCL 87
    PAD_SR_PDN0 88 PAD_SR_MCLK0 89 PAD_SR_RST0 90 PAD_I2C0_SDA 91
    PAD_I2C0_SCL 92 PAD_SR_PDN2 93 PAD_SR_MCLK2 94 PAD_SR_RST2 95
    PAD_I2C2_SDA 96 PAD_I2C2_SCL 97 PAD_SR_PDN3 98 PAD_SR_MCLK3 99
    PAD_SR_RST3 100 PAD_I2C3_SDA 101 PAD_I2C3_SCL 102 PAD_PWM_OUT0 103
    PAD_PWM_OUT1 104 PAD_PWM_OUT2 105 PAD_PWM_OUT3 106 PAD_PWM_OUT4 107
    PAD_PWM_OUT5 108 PAD_PWM_OUT6 109 PAD_PWM_OUT7 110 PAD_PWM_OUT8 111
    PAD_PWM_OUT9 112 PAD_PWM_OUT10 113 PAD_PWM_OUT11 114 PAD_OUTP_TX0_CH_0 115
    PAD_OUTN_TX0_CH_0 116 PAD_OUTP_TX0_CH_1 117 PAD_OUTN_TX0_CH_1 118 PAD_OUTP_TX0_CH_2 119
    PAD_OUTN_TX0_CH_2 120 PAD_OUTP_TX0_CH_3 121 PAD_OUTN_TX0_CH_3 122 PAD_OUTP_TX0_CH_4 123
    PAD_OUTN_TX0_CH_4 124 PAD_OUTP_TX1_CH_0 125 PAD_OUTN_TX1_CH_0 126 PAD_OUTP_TX1_CH_1 127
    PAD_OUTN_TX1_CH_1 128 PAD_OUTP_TX1_CH_2 129 PAD_OUTN_TX1_CH_2 130 PAD_OUTP_TX1_CH_3 131
    PAD_OUTN_TX1_CH_3 132 PAD_OUTP_TX1_CH_4 133 PAD_OUTN_TX1_CH_4 134 PAD_SAR_ADC_0 135
    PAD_SAR_ADC_1 136 PAD_SAR_ADC_2 137 PAD_SAR_ADC_3 138 PAD_SAR_ADC_4 139
    PAD_SAR_ADC_5 140 PAD_SAR_ADC_6 141 PAD_SAR_ADC_7 142 PAD_SAR_ADC_8 143
    PAD_SAR_ADC_9 144 PAD_SAR_ADC_10 145 PAD_SAR_ADC_11 146 PAD_SAR_ADC_12 147
    PAD_SAR_ADC_13 148 PAD_SAR_ADC_14 149 PAD_SAR_ADC_15 150 PAD_SAR_ADC_16 151
    PAD_SAR_ADC_17 152 PAD_SAR_ADC_18 153 PAD_SAR_ADC_19 154 PAD_SAR_ADC_20 155
    PAD_SAR_ADC_21 156 PAD_SAR_ADC_22 157 PAD_SAR_ADC_23 158 PAD_SR_IO4 159
    PAD_RGMII0_MCLK 160 PAD_RGMII0_RSTN 161 PAD_RGMII0_RXCLK 162 PAD_RGMII0_RXCTL 163
    PAD_RGMII0_RXD0 164 PAD_RGMII0_RXD1 165 PAD_RGMII0_RXD2 166 PAD_RGMII0_RXD3 167
    PAD_RGMII0_TXCLK 168 PAD_RGMII0_TXCTL 169 PAD_RGMII0_TXD0 170 PAD_RGMII0_TXD1 171
    PAD_RGMII0_TXD2 172 PAD_RGMII0_TXD3 173 PAD_RGMII0_MDIO 174 PAD_RGMII0_MDC 175
    PAD_UART_RX2 176 PAD_UART_TX2 177 PAD_UART_RX3 178 PAD_UART_TX3 179
    PAD_UART_RX4 180 PAD_UART_TX4 181 PAD_UART_RX1 182 PAD_UART_TX1 183
    PAD_FUART_RX 184 PAD_FUART_TX 185 PAD_FUART_RTS 186 PAD_FUART_CTS 187

    3. 内核使用GPIO

    3.1. 申请gpio端口

    • 目的

      创建端口为GPIO。

    • 语法

      int gpio_request(unsigned gpio, const char *label)
      
    • 参数

      参数名称 描述
      gpio GPIO Index
      label 具体名称
    • 返回值

      返回值 描述
      0 成功
      other 失败

    3.2. 释放gpio端口

    • 目的

      释放GPIO端口。

    • 语法

      void gpio_free(unsigned gpio)
      
    • 参数

      参数名称 描述
      gpio GPIO Index
    • 返回值

      返回值 描述
      void

    3.3. 设为输入

    • 目的

      标记gpio为输入。

    • 语法

      int gpio_direction_input(unsigned gpio);
      
    • 参数

      参数名称 描述
      gpio GPIO Index
    • 返回值

      返回值 描述
      0 成功
      other 失败

    3.4. 设为输出

    • 目的

      标记gpio为输出。

    • 语法

      int gpio_direction_output(unsigned gpio, int value);
      
    • 参数

      参数名称 描述
      gpio GPIO Index
      value 输出值
    • 返回值

      返回值 描述
      0 成功
      other 失败

    3.5. 获取输入电平

    • 目的

      获取输入引脚的电平。

    • 语法

      int gpio_get_value(unsigned gpio);
      
    • 参数

      参数名称 描述
      gpio GPIO Index
    • 返回值

      返回值 描述
      int 电平值

    3.6. 设置输出电平

    • 目的

      设定输出引脚的电平。

    • 语法

      void gpio_set_value(unsigned gpio, int value);
      
    • 参数

      参数名称 描述
      gpio GPIO Index
      value 输出值
    • 返回值

      返回值 描述
      0 成功
      other 失败

    3.7. 设置引脚为GPIO MODE

    • 目的

      设置引脚为GPIO MODE。

    • 语法

      void MDrv_GPIO_Pad_Set(U8 u8IndexGPIO);
      
    • 参数

      参数名称 描述
      u8IndexGPIO Group Index
    • 返回值

      返回值 描述
      void

    3.8. 设置引脚的TMUX模式

    • 目的

      设置引脚的TMUX模式。

    • 语法

      U8 MDrv_GPIO_PadVal_Set(U8 u8IndexGPIO, U32 u32PadMode);
      
    • 参数

      参数名称 描述
      u8IndexGPIO Group Index
      u32PadMode TMUX MODE
    • 返回值

      返回值 描述
      1 输出参数错误
      0 成功

    3.9. 获取引脚的TMUX模式

    • 目的

      获取引脚的TMUX模式。

    • 语法

      U8 MDrv_GPIO_PadVal_Get(U8 u8IndexGPIO, U32 u32PadMode);
      
    • 参数

      参数名称 描述
      u8IndexGPIO Group Index
      u32PadMode 获取到的TMUX MODE
    • 返回值

      返回值 描述
      1 输出参数错误
      0 成功

    3.10. 设置引脚的电压模式

    • 目的

      获取输入引脚的电平。

    • 语法

      void MDrv_GPIO_VolVal_Set(U8 u8Group, U32 u32PadMode);
      
    • 参数

      参数名称 描述
      u8Group Group num (11 Groups in total)
      u32PadMode Mode = 0:引脚电压为3.3V; Mode = 1:引脚电压为1.8V
    • 返回值

      返回值 描述
      void

    3.11. 获取引脚状态

    • 目的

      判断引脚的状态是输入还是输出。

    • 语法

      U8 MDrv_GPIO_Pad_InOut(U8 u8IndexGPIO, U8 u8PadLevel);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
      u8PadLevel 0表示引脚状态为输出,1表示引脚状态为输入
    • 返回值

      返回值 描述
      1 输入参数错误
      0 成功

    3.12. 设置GPIO的上拉功能

    • 目的

      开启指定的GPIO上拉功能。

    • 语法

      U8 MDrv_GPIO_Pull_Up(U8 u8IndexGPIO);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
    • 返回值

      返回值 描述
      0 设置成功
      other 该引脚不支持上拉设置或者输入参数错误

    3.13. 设置GPIO的下拉功能

    • 目的

      开启指定的GPIO下拉功能。

    • 语法

      U8 MDrv_GPIO_Pull_Down(U8 u8IndexGPIO);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
    • 返回值

      返回值 描述
      0 设置成功
      other 该引脚不支持下拉设置或者输入参数错误

    3.14. 关闭GPIO的上/下拉功能

    • 目的

      关闭指定的GPIO上/下拉功能,并切换至悬空状态。

    • 语法

      U8 MDrv_GPIO_Pull_Off(U8 u8IndexGPIO);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
    • 返回值

      返回值 描述
      0 设置成功
      other 该引脚不支持上拉设置或者输入参数错误

    3.15. 获取GPIO的上/下拉状态

    • 目的

      获取指定的GPIO上/下拉状态。

    • 语法

      U8 MDrv_GPIO_Pull_Status(U8 u8IndexGPIO, U8* u8PullStatus);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
      U8PullStatus 获取到的上/下拉状态
    • 返回值

      返回值 描述
      0 获取成功
      1 该引脚不支持上拉设置或者输入参数错误

    3.16. 设置GPIO的驱动能力

    • 目的

      设置指定的GPIO的驱动能力。

    • 语法

      U8 MDrv_GPIO_Drv_Set(U8 u8IndexGPIO, U8 u8Level);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
      u8Level 驱动能力等级
    • 返回值

      返回值 描述
      0 设置成功
      other 该引脚不支持驱动能力设置或者输入参数错误

    3.17. 获取GPIO的驱动能力等级

    • 目的

      获取指定的GPIO的驱动能力等级。

    • 语法

      U8 MDrv_GPIO_Drv_Get(U8 u8IndexGPIO, U8* u8Level);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
      u8Level 获取到的GPIO的驱动能力等级
    • 返回值

      返回值 描述
      0 获取成功
      1 该引脚不支持驱动能力设置或者输入参数错误

    3.18. 获取GPIO的中断号

    • 目的

      获取指定的GPIO的中断号。

    • 语法

      int MDrv_GPIO_To_Irq(U8 u8IndexGPIO);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
    • 返回值

      返回值 描述
      virq Virq为返回的中断号
      负数或0 失败

    3.19. 获取GPIO Index

    • 目的

      通过GPIO Name获取GPIO Index。

    • 语法

      U8 MDrv_GPIO_NameToNum(U8 pu8Name, U8* GpioIndex);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
      GpioIndex 获取到的GPIO Index
    • 返回值

      返回值 描述
      1 输入参数错误
      0 成功

    3.20. 获取特定PadMode对应的PIN脚

    • 目的

      查询能够使用某一个特定PadMode的所有GPIO脚。

    • 语法

      U32* MDrv_GPIO_PadModeToPadIndex(U32 u32Mode);
      
    • 参数

      参数名称 描述
      u32Mode 所要查询的PadMode
    • 返回值

      返回值 描述
      数组首地址 存放GPIO Index的数组

    4. 用户空间使用GPIO

    4.1. export/unexport文件接口

    用户空间可以通过sysfs接口操作GPIO:首先需要打开 CONFIG_GPIO_SYSFS 配置,该配置位于menuconfig中:Device Drivers -> GPIO support -> /sys/class/gpio/... (sysfs interface)

    /sys/class/gpio对应的源码位于driver/gpio/gpiolib-sysfs.c

    /sys/class/gpio目录下的包含export/unexport、gpioN、gpio_chipN三种文件:

    文件名 读写权限 描述
    export wo GPIO Index 在用户空间申请某个GPIO的控制权
    unexport wo GPIO Index 在用户空间移除某个GPIO的控制权
    gpioN ro 包含具体GPIO的direction、value等信息
    gpio_chipN ro 指代GPIO控制器

    • /sys/class/gpio/export 文件属性为只允许写不允许读,用户程序通过写入GPIO的编号来向内核申请将某个GPIO的控制权导出到用户空间(sysfs),前提是没有内核代码申请这个GPIO端口,如用户申请编号为12的GPIO的命令:

      # echo 12 > export
      

      上述操作会为GPIO Index为12的GPIO创建一个节点gpio12,此时/sys/class/gpio目录下边生成一个gpio12的目录,如下图所示:

    • /sys/class/gpio/unexport 文件属性也为只允许写不允许读,和export的效果相反,用户通过写入GPIO的编号来移除用户空间(sysfs)的接口。如移除gpio12文件夹的操作命令:

      # echo 12 > unexport
      

      上述操作将会移除gpio12这个节点,如下图所示:

    4.2. /sys/class/gpio/gpioN

    /sys/class/gpio/gpioN 指代某个具体的gpio端口,里边有如下属性文件:

    文件名 读写权限 描述
    direction rw in 输入模式,value不可写
    out 输出模式,value可写
    high 输出状态,默认高电平状态,value可写
    low 输出状态,默认低电平状态,value可写
    value rw 1 高电平状态
    0 低电平状态
    edge rw none disable gpio中断
    rising 使能gpio中断,并设置为上升沿触发
    falling 使能gpio中断,并设置为下降沿触发
    both 使能gpio中断,并设置为双边沿触发

    direction 表示gpio端口的方向,读取结果是in或out,读取命令为:

    # cat direciton
    

    value 表示gpio引脚的电平,0表示低电平,1表示高电平;读取命令为:

    # cat value
    

    可以对direction进行写操作,命令为:

    # echo in > direction
    

    # echo out > direction
    

    如果direction被配置为输出(out),电平默认为低,同时value是可写的,操作命令为:

    # echo 1 > value
    
    # echo 0 > value
    

    direction写入low或high时不仅可以设置为输出还可以设置指定的输出电平。操作命令为:

    # echo high > direction
    

    # echo low > direction
    

    当然如果内核不支持或者内核代码不愿意,将不会存在这个属性,比如内核调用了gpio_export(N,0)就表示内核不愿意修改gpio端口方向属性。

    edge 表示是否使能gpio中断,并设置触发模式,支持上升沿触发、下降沿触发、双边沿触发:

    # cat edge
    

    可以对edge进行写操作,命令为:

    # echo none > edge
    # echo rising > edge
    # echo falling > edge
    # echo both > edge
    

    如果需要使能某只脚的中断,需要先将该脚设置为输入状态,并设置触发模式,则可以调用poll(2)函数监听该中断,中断触发后poll(2)函数就会返回。

    4.3. /sys/class/mstar/msys

    LINUX GPIO框架暂时未支持GPIO上下拉和驱动能力调节相关配置,在LINUX的GPIO标准框架外,我们又增加了另外的文件接口用于操作GPIO的上下拉和调节驱动能力。如需支持此功能,首先需要打开 CONFIG_MSYS_GPIO 配置,该配置位于menuconfig中:Device Drivers -> SStar SoC platform drivers -> msys api ->support GPIO pull and driving modify

    /sys/class/mstar/msys对应的源代码位于driver/sstar/msys/ms_msys.c

    设置上拉/下拉之前需要先将GPIO设置为输入状态,输出状态上拉/下拉是没法测量的:

    引脚设置为输入状态后,进入sys/class/mstar/msys文件夹:

    • gpio_pull 可以写入up和down

      文件名 读写权限 描述
      gpio_pull rw up 上拉模式
      down 下拉模式

      查看GPIO当前的pull 状态是pull up / pull down / pull off:

      1. # echo 50 > gpio_pull
      2. # cat gpio_pull
      

      如果输入非法的GPIO Index 和GPIO Name,则会报错:

      设置上拉和设置下拉的命令为:

      1. # echo 50 up > gpio_pull
      2. # echo 50 down > gpio_pull
      

      设置后查看gpio_pull的状态,如下图,50表示GPIO Index,PAD_OUTN_RX0_CH3表示GPIO Name。

      1. # cat gpio_pull
      

      如果输入非法的GPIO Index 和GPIO Name,则会报错:

      检查具体BIT是否被正确写入,可以根据GPIO_Mapping_Table,查找对应的PAD(如下图GPIO INDEX:50)。当pull up的时候PE bit位为1,PS bit位为0;pull down的时候PE bit位为1,PS bit位为0。具体操作命令为:

      1. # riu_r 0x103e 0x34
      

      查看riu_r返回值的BIT6、BIT11

    • gpio_drive 可以写入驱动的等级

      文件名 读写权限 描述
      gpio_drive rw 0~8 设置GPIO的驱动等级

      当前平台中GPIO的驱动能力等级可查阅GPIO_Mapping_Table。

      查看GPIO的初始驱动能力等级的命令位:(也可以直接使用GPIO43的名称PAD_OUTP_RX0_CH0)

      1. # echo 43 > gpio_drive
      2. # cat gpio_drive
      

      如果输入非法的GPIO Index 和GPIO Name,则会报错:

      设置驱动能力之前将GPIO设置为高电平输出状态方便测量,设置命令为:

      1. # echo 43 1 > gpio_drive
      

      43为GPIO Index,1为驱动能力等级,对应4mA

      设置驱动能力之后查看gpio_driver的状态,如下图,设置GPIO Index为43的引脚的驱动能力为4mA成功。

      1. # cat gpio_drive
      

      检查具体BIT是否被正确写入,可以根据GPIO_Mapping_Table,查找对应的PAD(如下图GPIO INDEX:50)。当设置驱动等级为1时,[103E56]#7 ~ #8为01。具体操作命令为:

      1. # riu_r 0x103e 0x2B
      

      查看riu_r返回值的BIT7、BIT8

    4.4. 示例

    用户空间代码操作GPIO请参考sstargpio.c。

    sstargpio.c

    1. #include <stdlib.h>
    2. #include <unistd.h>
    3. #include <stdio.h>
    4. #include <fcntl.h>
    5. #include <linux/fb.h>
    6. #include <linux/kd.h>
    7. #include <sys/mman.h>
    8. #include <sys/ioctl.h>
    9. #include <sys/time.h>
    10. #include <string.h>
    11. #include <errno.h>
    12.
    13. #include "mi_sys.h"
    14.
    15. #define GPIO_DEV "/sys/class/gpio"
    16. #define SSTAR_GPIO_IN 0
    17. #define SSTAR_GPIO_OUT 1
    18.
    19. /* API call reference
    20.     SStar_Gpio_Export(10);
    21.     SStar_Gpio_SetDirection(10, SSTAR_GPIO_OUT);
    22.     SStar_Gpio_SetValue(10, 0/1);
    23. */
    24.
    25. // export gpio port
    26. MI_S32 SStar_Gpio_Export(MI_S32 s32Gpio)
    27. {
    28.     MI_S32 s32Ret = -1;
    29.     MI_S32 s32Fd = -1;
    30.
    31.     char as8GpioDev[128];
    32.
    33.     memset(as8GpioDev, 0, sizeof(as8GpioDev));
    34.     sprintf(as8GpioDev, "%s/export", GPIO_DEV);
    35.
    36.     s32Fd = open(as8GpioDev, O_WRONLY);
    37.
    38.     if (s32Fd < 0)
    39.         printf("failed to export gpio %d\n", s32Gpio);
    40.     else
    41.     {
    42.         char as8GpioPort[10];
    43.         memset(as8GpioPort, 0, sizeof(as8GpioPort));
    44.         sprintf(as8GpioPort, "%d", s32Gpio);
    45.         write(s32Fd, as8GpioPort, strlen(as8GpioPort));
    46.         printf("export gpio port: %d\n", s32Gpio);
    47.         close(s32Fd);
    48.         s32Ret = MI_SUCCESS;
    49.     }
    50.
    51.     return s32Ret;
    52. }
    53.
    54. // set gpio direction: 0 in, others out
    55. MI_S32 SStar_Gpio_SetDirection(MI_S32 s32Gpio, MI_S32 s32Direction)
    56. {
    57.     MI_S32 s32Ret  = -1;
    58.     const char *ps8Direction = NULL;
    59.     MI_S32 s32Fd = -1;
    60.
    61.     char as8GpioDev[128];
    62.
    63.     memset(as8GpioDev, 0, sizeof(as8GpioDev));
    64.     sprintf(as8GpioDev, "%s/gpio%d/direction", GPIO_DEV, s32Gpio);
    65.
    66.     s32Fd = open(as8GpioDev, O_RDWR);
    67.
    68.     if (s32Fd < 0)
    69.         printf("failed to set gpio%d direction\n", s32Gpio);
    70.     else
    71.     {
    72.         if (SSTAR_GPIO_IN == s32Direction)
    73.             ps8Direction = "in";
    74.         else if (SSTAR_GPIO_OUT == s32Direction)
    75.             ps8Direction = "out";
    76.         else
    77.         {
    78.             printf("Unkown gpio direction %d\n", s32Direction);
    79.         }
    80.         write(s32Fd, ps8Direction, strlen(ps8Direction));
    81.         printf("set gpio%d direction: %s\n", s32Gpio, ps8Direction);
    82.         close(s32Fd);
    83.         s32Ret = 0;
    84.     }
    85.
    86.     return s32Ret;
    87. }
    88.
    89. // get gpio direction
    90. MI_S32 SStar_Gpio_GetDirection(MI_S32 s32Gpio, MI_S8 *ps8Direction, MI_S32 s32Len)
    91. {
    92.     MI_S32 s32Ret  = -1;
    93.     MI_S32 s32Fd = -1;
    94.
    95.     char as8GpioDev[128];
    96.
    97.     memset(as8GpioDev, 0, sizeof(as8GpioDev));
    98.     sprintf(as8GpioDev, "%s/gpio%d/direction", GPIO_DEV, s32Gpio);
    99.
    100.     s32Fd = open(as8GpioDev, O_RDWR);
    101.
    102.     if (s32Fd < 0)
    103.         printf("failed to read gpio%d direction\n", s32Gpio);
    104.     else
    105.     {
    106.         memset(ps8Direction, 0, s32Len);
    107.         read(s32Fd, ps8Direction, s32Len);
    108.         printf("get gpio%d direction: %s\n", s32Gpio, ps8Direction);
    109.         close(s32Fd);
    110.         s32Ret = MI_SUCCESS;
    111.     }
    112.
    113.     return s32Ret;
    114. }
    115.
    116. // set gpio value: 0 low, 1 high
    117. MI_S32 SStar_Gpio_SetValue(MI_S32 s32Gpio, MI_S8 s8Value)
    118. {
    119.     MI_S32 s32Ret  = -1;
    120.     MI_S32 s32Fd = -1;
    121.
    122.     char as8GpioDev[128];
    123.
    124.     memset(as8GpioDev, 0, sizeof(as8GpioDev));
    125.     sprintf(as8GpioDev, "%s/gpio%d/value", GPIO_DEV, s32Gpio);
    126.
    127.     s32Fd = open(as8GpioDev, O_RDWR);
    128.
    129.     if (s32Fd < 0)
    130.         printf("failed to set gpio%d value\n", s32Gpio);
    131.     else
    132.     {
    133.         if (0 == s8Value)
    134.         {
    135.             write(s32Fd, (const void*)"0", 1);
    136.         }
    137.         else if (1 == s8Value)
    138.         {
    139.             write(s32Fd, (const void*)"1", 1);
    140.         }
    141.         else
    142.         {
    143.             printf("error:set gpio value fail (%d)\n", s8Value);
    144.         }
    145.         close(s32Fd);
    146.         s32Ret = MI_SUCCESS;
    147.     }
    148.
    149.     return s32Ret;
    150. }
    151.
    152. // get gpio value
    153. MI_S32 SStar_Gpio_GetValue(MI_S32 s32Gpio, MI_S8 *s8Level)
    154. {
    155.     MI_S32 s32Ret  = -1;
    156.     MI_S32 s32Fd = -1;
    157.
    158.     char as8GpioDev[128];
    159.     char as8[2];
    160.
    161.     memset(as8, 0, sizeof(as8));
    162.     memset(as8GpioDev, 0, sizeof(as8GpioDev));
    163.     sprintf(as8GpioDev, "%s/gpio%d/value", GPIO_DEV, s32Gpio);
    164.
    165.     s32Fd = open(as8GpioDev, O_RDWR);
    166.
    167.     if (s32Fd < 0)
    168.         printf("failed to read gpio%d value\n", s32Gpio);
    169.     else
    170.     {
    171.         read(s32Fd, as8, 1);
    172.         *s8Level = atoi(as8);
    173.         //printf("read gpio status: %s\n", s8Value);
    174.         close(s32Fd);
    175.         s32Ret = MI_SUCCESS;
    176.     }
    177.
    178.     return s32Ret;
    179. }
    180.
    181. // get gpio value
    182. int new_SStar_Gpio_GetValue(MI_S32 s32Gpio)
    183. {
    184.     int value = -1;
    185.     MI_S32 s32Fd = -1;
    186.
    187.     char as8GpioDev[128];
    188.     char as8[2];
    189.
    190.     memset(as8, 0, sizeof(as8));
    191.     memset(as8GpioDev, 0, sizeof(as8GpioDev));
    192.     sprintf(as8GpioDev, "%s/gpio%d/value", GPIO_DEV, s32Gpio);
    193.
    194.     s32Fd = open(as8GpioDev, O_RDWR);
    195.     if (s32Fd < 0)
    196.         printf("failed to read gpio%d value\n", s32Gpio);
    197.     else
    198.     {
    199.         read(s32Fd, as8, 1);
    200.         value = atoi(as8);
    201.         close(s32Fd);
    202.     }
    203.
    204.     return value;
    205. }
    

    用户空间代码使能gpio中断请参考sstargpio_poll.c。

    sstargpio_poll.c

    1.    #include <stdio.h>
    2.    #include <stdlib.h>
    3.    #include <unistd.h>
    4.    #include <fcntl.h>
    5.    #include <sys/poll.h>
    6.
    7.    int main(int argc, char *argv[])
    8.    {
    9.        char buff[1024];
    10.        int gpio_id;
    12.        struct pollfd fds[1];
    13.        int gpio_fd = open("/sys/class/gpio/gpio135/value", O_RDONLY);
    14.        if (gpio_fd == -1)
    15.            {printf("gpio open\n");}
    16.        else
    17.            {printf("/sys/class/gpio/gpio135/value\n");}
    18.        fds[0].fd = gpio_fd;
    19.        fds[0].events = POLLPRI;
    20.        int ret = read(gpio_fd, buff, 10);
    21.        if (ret == -1)
    22.            printf("read fail\n");
    23.        else
    24.            printf("read\n");
    25.        while (1)
    26.        {
    27.            printf("revents is %d\n", fds[0].revents);
    28.            ret = poll(fds, 1, -1);
    29.            if (ret == -1)
    30.                printf("poll\n");
    31.
    32.            if (fds[0].revents & POLLPRI)
    33.            {
    34.                ret = lseek(gpio_fd, 0, SEEK_SET);
    35.                if (ret == -1)
    36.                    printf("lseek\n");
    37.                ret = read(gpio_fd, buff, 10);
    38.                if (ret == -1)
    39.                    printf("read\n");
    40.                printf("get interrupt\n");
    41.            }
    42.        }
    43.    }
    

    5. UBOOT使用GPIO

    5.1. CMD:gpio -Config gpio port

    用法(query and control gpio pins):

    <input|set|clear|toggle> <pin> → input/set/clear/toggle the specified pin

    gpio status [-a] [<bank> | <pin>] → show [all / claimed] GPIOs

    举例:

    gpio input <gpio#> → gpio input 69 // gpio69 set as input

    gpio set <gpio#> → gpio set 10 // gpio10 set as output high

    gpio clear <gpio#> → gpio clear 49 // gpio49 set as output low

    gpio toggle <gpio#> → gpio toggle 49 // gpio49 level toggle

    gpio status <gpio#> → gpio status 20 // gpio20 status

    5.2. API

    5.2.1. 设置引脚为GPIO MODE

    • 目的

      设置引脚为GPIO MODE。

    • 语法

      void MDrv_GPIO_Pad_Set(U8 u8IndexGPIO);
      
    • 参数

      参数名称 描述
      u8IndexGPIO Group Index
    • 返回值

      返回值 描述
      void

    5.2.2. 设置引脚的TMUX模式

    • 目的

      设置引脚的TMUX模式。

    • 语法

      U8 MDrv_GPIO_PadVal_Set(U8 u8IndexGPIO, U32 u32PadMode);
      
    • 参数

      参数名称 描述
      u8IndexGPIO Group Index
      u32PadMode TMUX MODE
    • 返回值

      返回值 描述
      1 输出参数错误
      0 成功

    5.2.3. 获取引脚的TMUX模式

    • 目的

      获取引脚的TMUX模式。

    • 语法

      U8 MDrv_GPIO_PadVal_Get(U8 u8IndexGPIO, U32 u32PadMode);
      
    • 参数

      参数名称 描述
      u8IndexGPIO Group Index
      u32PadMode 获取到的TMUX MODE
    • 返回值

      返回值 描述
      1 输出参数错误
      0 成功

    5.2.4. 设置引脚的电压模式

    • 目的

      获取输入引脚的电平。

    • 语法

      void MDrv_GPIO_VolVal_Set(U8 u8Group, U32 u32PadMode);
      
    • 参数

      参数名称 描述
      u8Group Group num (11 Groups in total)
      u32PadMode Mode = 0:引脚电压为3.3V;
      Mode = 1:引脚电压为1.8V
    • 返回值

      返回值 描述
      void

    5.2.5. 获取引脚状态

    • 目的

      判断引脚的状态是输入还是输出。

    • 语法

      U8 MDrv_GPIO_Pad_InOut(U8 u8IndexGPIO, U8 u8PadLevel);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
      u8PadLevel 0表示引脚状态为输出,1表示引脚状态为输入
    • 返回值

      返回值 描述
      1 输入参数错误
      0 成功

    5.2.6. 设置GPIO的上拉功能

    • 目的

      开启指定的GPIO上拉功能。

    • 语法

      U8 MDrv_GPIO_Pull_Up(U8 u8IndexGPIO);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
    • 返回值

      返回值 描述
      0 设置成功
      other 该引脚不支持上拉设置或者输入参数错误

    5.2.7. 设置GPIO的下拉功能

    • 目的

      开启指定的GPIO下拉功能。

    • 语法

      U8 MDrv_GPIO_Pull_Down(U8 u8IndexGPIO);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
    • 返回值

      返回值 描述
      0 设置成功
      other 该引脚不支持下拉设置或者输入参数错误

    5.2.8. 关闭GPIO的上/下拉功能

    • 目的

      关闭指定的GPIO上/下拉功能,并切换至悬空状态。

    • 语法

      U8 MDrv_GPIO_Pull_Off(U8 u8IndexGPIO);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
    • 返回值

      返回值 描述
      0 设置成功
      other 该引脚不支持上拉设置或者输入参数错误

    5.2.9. 获取GPIO的上/下拉状态

    • 目的

      获取指定的GPIO上/下拉状态。

    • 语法

      U8 MDrv_GPIO_Pull_Status(U8 u8IndexGPIO, U8* u8PullStatus);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
      U8PullStatus 获取到的上/下拉状态
    • 返回值

      返回值 描述
      0 获取成功
      1 该引脚不支持上拉设置或者输入参数错误

    5.2.10. 设置GPIO的驱动能力

    • 目的

      设置指定的GPIO的驱动能力。

    • 语法

      U8 MDrv_GPIO_Drv_Set(U8 u8IndexGPIO, U8 u8Level);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
      u8Level 驱动能力等级
    • 返回值

      返回值 描述
      0 设置成功
      other 该引脚不支持驱动能力设置或者输入参数错误

    5.2.11. 获取GPIO的驱动能力等级

    • 目的

      获取指定的GPIO的驱动能力等级。

    • 语法

      U8 MDrv_GPIO_Drv_Get(U8 u8IndexGPIO, U8* u8Level);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
      u8Level 获取到的GPIO的驱动能力等级
    • 返回值

      返回值 描述
      0 获取成功
      1 该引脚不支持驱动能力设置或者输入参数错误

    5.2.12. 获取GPIO Index

    • 目的

      通过GPIO Name获取GPIO Index。

    • 语法

      U8 MDrv_GPIO_NameToNum(U8 pu8Name, U8* GpioIndex);
      
    • 参数

      参数名称 描述
      u8IndexGPIO GPIO Index
      GpioIndex 获取到的GPIO Index
    • 返回值

      返回值 描述
      1 输入参数错误
      0 成功

    5.2.13. 获取特定PadMode对应的PIN脚

    • 目的

      查询能够使用某一个特定PadMode的所有GPIO脚。

    • 语法

      U32* MDrv_GPIO_PadModeToPadIndex(U32 u32Mode);
      
    • 参数

      参数名称 描述
      u32Mode 所要查询的PadMode
    • 返回值

      返回值 描述
      数组首地址 存放GPIO Index的数组

    6. GPIO复用功能

    6.1. Kernel Config

    编译Kernel时:make menuconfig

    Device Drivers-->
        [*] SStar SoC platform drivers-->
    

    6.2. 复用功能使用说明

    当需要使用GPIO的复用功能时候,首先需要获取所要操作的PIN脚的Name、所要复用的Tmux Mode,将他们配置在xxx-padmux.dtsi中:

    1. <PAD_VSYNC_OUT      PINMUX_FOR_VGA_VSYNC_MODE_1      MDRV_PUSE_VGA_VSYNC>
    2. <PAD_HSYNC_OUT      PINMUX_FOR_VGA_HSYNC_MODE_1      MDRV_PUSE_VGA_HSYNC>
    

    如上所示,第一列和第二列分别表示Pad Name和Tmux Mode,MDRV_PUSE_XXX可以理解为当前这一组的配置的Name。

    配置的时候需要注意的事项:

    • 一个Pad只能配置一种Mode,不可以一个Pad同时配置多个Mode。

    • 一个Puse只能对应一组配置,否则会造成冲突。

    • 配置的Pad和Mode必须是匹配的。

    • 不允许在驱动中直接进行复用操作,要求复用的配置都集中到xxx_padmux.dtsi。(需要动态调整复用配置的除外,这是为了方便管理和减少配置冲突,也因此这份dtsi文件中汇聚了几乎所有引脚的复用配置)

    6.3. API

    6.3.1. 获取复用到的引脚

    • 目的

      以Puse为检索条件遍历,获取xxx-padmux.dtsi中配置到的Pad。

    • 语法

      int mdrv_padmux_getpad (int Puse);
      
    • 参数

      参数名称 描述
      Puse Puse的宏定义
    • 返回值

      返回值 描述
      PadId 成功获取到padmux.dtsi中的Pad的宏定义
      PAD_UNKNOWN 输入的Puse有误或者padmux.dtsi中没有对应的PadId

    6.3.2. 获取复用到的Tmux Mode

    • 目的

      以Puse为检索条件遍历,获取xxx-padmux.dtsi中配置到的Tmux Mode。

    • 语法

      int mdrv_padmux_getmode (int Puse);
      
    • 参数

      参数名称 描述
      Puse Puse的宏定义
    • 返回值

      返回值 描述
      PadId 成功获取到padmux.dtsi中的Mode的宏定义
      PAD_UNKNOWN 输入的Puse有误或者padmux.dtsi中没有对应的PadId

    6.3.3. 获取PUSE的宏定义

    • 目的

      因为PUSE的宏定义遵循一套规则:

      1. 不同IP之间的偏移为0x10000

      2. 同一个IP中不同Channel之间的偏移为0x100

      3. 同一个IP同一个Channel中不同Puse之间的偏移为0x1

      因此可以根据这三个参数获取Puse的宏定义。

    • 语法

      int mdrv_padmux_getpuse (int IP_Index, int Channel_Index, int Pad_Index);
      
    • 参数

      参数名称 描述
      IP_Index Puse所在的IP,可在mdrv_puse.h中查阅
      Channel_Index Puse所在的Channel,可在mdrv_puse.h中查阅
      Pad_Index Puse在channel中的Index,可在mdrv_puse.h中查阅
    • 返回值

      返回值 描述
      Puse 成功获取到padmux.dtsi中的PadId

    6.3.4. 获取特定PadMode对应的PIN脚

    • 目的

      查询能够使用某一个特定PadMode的所有GPIO脚。

    • 语法

      U32* MDrv_GPIO_PadModeToPadIndex(U32 u32Mode);
      
    • 参数

      参数名称 描述
      u32Mode 所要查询的PadMode
    • 返回值

      返回值 描述
      数组首地址 存放GPIO Index的数组

    6.3.5. 获取特定Pad目前的Tmux Mode

    • 目的

      该API用于获取某只Pad当前配置的PadMode,前提是这只Pad配置PadMode的时候是通过Padmux接口进行配置,直接操作寄存器进行配置的方式则不会使该API生效。

    • 语法

      U8* MDrv_GPIO_PadValGet (U8 u8IndexGPIO, U32* u32PadMode);
      
    • 参数

      参数名称 描述
      u8IndexGPIO 所要查询的PadMode
      u32PadMode 获取到的PadMode
    • 返回值

      返回值 描述
      1 成功
      0 失败

    7. PAD初始状态设置

    7.1. Kernel Config

    编译Kernel时:make menuconfig

    Device Drivers-->
        [*] SStar SoC platform drivers-->
            [*] PAD_INIT driver
    

    7.2. 功能使用说明

    PAD的初始状态包括输入/输出状态、电平状态、内部上拉状态、引脚驱动能力等级。因此在设置PAD初始状态的时候,主要是对以上四种状态进行配置。在xxx-padmux.dtsi中具体的配置格式如下:

        /*
         * Format:
         * <Pad_Index   Direction       Level_State        Pull_State          Driving_Level>
         */
        1. <PAD_KEY0    GPIO_DIR_IN     GPIO_LEVEL_NA      PAD_PULL_UP         PAD_DRV_0>,
        2. <PAD_KEY1    GPIO_DIR_OUT    GPIO_LEVEL_LOW     PAD_PULL_DOWN       PAD_DRV_1>,
        3. <PAD_KEY2    GPIO_DIR_OUT    GPIO_LEVEL_HIGH    PAD_HIZ             PAD_DRV_DEFAULT>,
        4. <PAD_KEY3    GPIO_DIR_OUT    GPIO_LEVEL_NA      PAD_PULL_DEFAULT    PAD_DRV_2>,
        5. <PAD_KEY4    GPIO_DIR_NA     GPIO_LEVEL_NA      PAD_PULL_DEFAULT    PAD_DRV_DEFAULT>
        6. <GPIO_NR     GPIO_DIR_NA     GPIO_LEVEL_NA      PAD_PULL_DEFAULT    PAD_DRV_DEFAULT>;
    

    如上所示:

    • Pad_Index:表示PAD序号,可参考表1-1:GPIO NUM与PAD对应表。

    • Direction:表示Pad的输入/输出模式,可以选择配置为:GPIO_DIR_IN、GPIO_DIR_OUT、GPIO_DIR_NA。

      GPIO_DIR_IN表示设置为输入,GPIO_DIR_OUT表示设置为输出。如果只需要设置PAD的内部上拉状态和驱动能力等级,而不需要将PAD设置为GPIO mode的话,可以在Direction位置传入GPIO_DIR_NA。Pad设置为输入/输出模式的时候需要将这只Pad设置为GPIO mode,所以需要在配置padmux的位置加入GPIO mode的设定

      1.    <PAD_KEY0      PINMUX_FOR_GPIO_MODE      MDRV_PUSE_GPIO_KEY0>,
      2.    <PAD_KEY1      PINMUX_FOR_GPIO_MODE      MDRV_PUSE_GPIO_KEY1>,
      2.    <PAD_KEY2      PINMUX_FOR_GPIO_MODE      MDRV_PUSE_GPIO_KEY2>,
      3.    <PAD_KEY3      PINMUX_FOR_GPIO_MODE      MDRV_PUSE_GPIO_KEY3>,
      
    • Level_State:表示电平高低状态,可以选择配置为:GPIO_LEVEL_HIGH、GPIO_LEVEL_LOW、GPIO_LEVEL_NA。

      GPIO_LEVEL_HIGH表示高电平,GPIO_LEVEL_LOW表示低电平,GPIO_LEVEL_NA则表示无需配置初始电平,使用默认电平即可。

    • Pull_State:表示内部上下拉状态,可以选择配置为:PAD_PULL_UP、PAD_PULL_DOWN、PAD_HIZ、PAD_PULL_DEFAULT。

    • PAD_PULL_UP表示内部上拉,PAD_PULL_DOWN表示内部下拉,PAD_HIZ表示悬空,在不需要设置内部上拉状态的时候,可以选择PAD_PULL_DEFAULT,表示设置为默认状态

    • Driving_Level:表示驱动能力等级,可以选择配置为PAD_DRV_0、PAD_DRV_1、PAD_DRV_2......当不需要设置驱动能力等级的时候,也可以选择PAD_DRV_DEFAULT,即使用当前驱动能力等级,不做配置

      Name Config
      Direction GPIO_DIR_IN、GPIO_DIR_OUT、GPIO_DIR_NA
      Level_State GPIO_LEVEL_HIGH、GPIO_LEVEL_LOW、GPIO_LEVEL_NA
      Pull_State PAD_PULL_UP、PAD_PULL_DOWN、PAD_HIZ、PAD_PULL_DEFAULT
      Driving_Level PAD_DRV_0、PAD_DRV_1、PAD_DRV_2、……PAD_DRV_DEFAULT