GPIO使用参考
REVISION HISTORY¶
| Revision No. | Description |
Date |
|---|---|---|
| 1.0 | 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。
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。
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的宏定义遵循一套规则:
-
不同IP之间的偏移为0x10000
-
同一个IP中不同Channel之间的偏移为0x100
-
同一个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