Skip to main content
 首页 » 操作系统

Linux GPIO使用总结

2022年07月19日25cmt

一、GPIO重要概念

要想操作GPIO引脚,需要先把所用引脚配置成GPIO功能,这个通过pinctrl子系统来实现。然后可以根据设置的引脚的方向来读取引脚的值和设置输出值。GPIO子系统存在之前,我们驱动需要在代码中配置寄存器来使用GPIO引脚。再BSP工程师实现好GPIO子系统后,我们就可以在设备树中指定GPIO引脚,在驱动中使用GPIO子系统的标准函数来获取GPIO、设置GPIO方向、读取/设置GPIO的值。这样的驱动代码是于单板无关的。

二、GPIO内核相关文档

Documentation\devicetree\bindings\pinctrl\pinctrl-bindings.txt 
Documentation\gpio\gpio.txt 
Documentation\devicetree\bindings\gpio\gpio.txt

三、GPIO设备树配置

1. BSP工程师实现的gpio驱动,驱动工程师直接在设备树中配置使用。

//client节点 
device { 
    led-gpios = <组, 哪个几个,flag>; //"组"是必须要有的元素,为gpio控制器的描述,这里除了组之外还有几个域是由组中的#gpio-cells的值决定的。 
}; 
 
//service端,设备树中对一个gpio控制器的表示: 
gpio1 { 
    ...... 
    gpio-controller; 
    #gpio-cells = <2>; //表示client使用gpio1这一组中的某个引脚时,除了组之外还需要使用2个整数来表示。 
};

2. 举个例子:

foo_device { 
    compatible = "acme,foo"; 
    ...... 
    led-gpios = <&gpio 15 GPIO_ACTIVE_HIGH> /*red*/ //一般这里可能为&gpioX 
        <&gpio 16 GPIO_ACTIVE_HIGH> /*green*/ 
        <&gpio 17 GPIO_ACTIVE_HIGH>; /*blue*/ 
     
    power-gpios = <&gpio, 1 GPIO_ACTIVE_LOW>; //注意这里使用了avtive_low属性了 
};

驱动代码中:

gpiod_get_index(dev, "led", 0, GOIOD_OUT_HIGH); //取出设备树中名为led的gpio中的第0个引脚,也就是red。 
gpiod_get_index(dev, "led", 1, GOIOD_OUT_HIGH); //取出第1个

若在设备树中只定义了一个引脚,就可以使用:

gpiod_get(dev, "power", GPIO_OUTPUT_HIGH); //把这个设备下名为power的那个引脚给取出来。

三、在驱动中使用GPIO

1.GPIO子系统有两套接口

(1) 一是基于描述符(descriptor-based)的,相关api函数都是以"gpiod_"为前缀,它使用gpio_desc结构来表示一个引脚。
(2) 另一种是老(legency)的,相关api函数都是以"gpio_"为前缀,它使用一个整数来表示一个引脚。

要操作一个引脚,首先要get引脚,然后设置方向,然后读取、写值。

2.列举操作GPIO常使用的函数

//1.获取GPIO 
gpiod_get  //legency为gpio_request 
gpiod_get_index 
gpiod_get_array //legency为gpio_request_array 
devm_gpiod_get 
devm_gpiod_get_index 
devm_gpiod_get_array 
 
//2.设置方向 
gpiod_direction_input  //legency为gpio_direction_input 
gpiod_direction_output //legency为gpio_direction_input 
 
//3.读值、写值 
gpiod_get_value //legency为gpio_get_value 
gpiod_set_value //legency为gpio_set_value 
 
//4.释放GPIO 
gpio_free //gpio_free 
gpiod_put //gpio_free_array 
gpiod_put_array 
devm_gpiod_put 
devm_gpiod_put_array

  前缀为"devm_"的含义是设备资源管理,这是一种自动释放资源的机制。它的思想是“资源是属于设备的,设备不存在时资源就可以自动释放”。在Linux驱动开发过程中,先申请了GPIO,再申请内存,如果内存申请失败,那么在返回之前就需要先释放GPIO资源。如果使用的是devm相关函数,在内存申请失败时可以直接返回,设备的销毁函数会自动地释放已经申请了的GPIO资源。建议使用devm相关函数操作GPIO。

3.如何通过GPIO号来使用GPIO

比如要通过gpio号来操作原理图上的GPIO5_14这个gpio引脚,那么得先知道这个gpio引脚的number是多少。那么得先找到gpio5组的基gpio number是多少。

/sys/class/gpio/# ls 
export gpio30 gpiochip0 gpiochip32 gpiochip64 gpiochip96 gpiochip128 gpiochip504 unexport //gpiochip96 这一组gpio的基gpio号是96 
/sys/class/gpio/gpiochip128# ls 
base device label ngpio power subsystem uevent 
/sys/class/gpio/gpiochip128# cat label //可以看出设备树节点名为gpio@20ac000,20ac000就是这一组gpio寄存器的基地址,可通过它查看每一组gpio的基gpio号 
20ac000.gpio 
/sys/class/gpio/gpiochip128# cat base //表示这一组gpio的基gpio号为128 
128 
/sys/class/gpio/gpiochip128# cat ngpio //表示这一组gpio的个数 
32

在dtsi文件中检索20ac000就可以看到如下设备树配置,所以知道gpio5这一组gpio的基gpio号是128

gpio5: gpio@20ac000 { 
    compatible = "fsl,im6ul-gpio", "fsl,imx35-gpio"; 
    reg = <0x020ac000 0x4000>; 
    interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>; 
    gpio-controller; 
    #gpio-cells = <0x2>; 
    interrupt-controller; 
    #interrupt-cells = <0x2>; 
};

那么GPIO5_14,其gpio号就是128+14=142,然后可以将这个gpio给导出来,设置其方向,配置其值,进行验证。

/sys/class/gpio# echo 142 > export 
/sys/class/gpio# ls 
export unexport gpio142  ... //此时可以看到多了一个gpio142目录 
/sys/class/gpio/gpio142# ls 
active_low direction power uevent device edge subsystem value //此时可以cat active_low 看是否具有active_low属性 
/sys/class/gpio/gpio142# echo in > direction //设置为输入引脚 
/sys/class/gpio/gpio142# cat value //读取其值 
1 
/sys/class/gpio# echo 142 > unexport //取消映射

如果某个引脚已经被使用了,再次export就会报错:“resource busy”。算出引脚号后就可以在驱动中使用legency函数来通过gpio号来操作gpio引脚了。

注意: Qcom平台,如果内核级驱动程序通过of_get_named_gpio()函数或类似函数获取,请求并使用该GPIO,则无法将该GPIO导出以进行sysfs控制。


五、active_low属性

  注意,设置的逻辑电平并不一定等于物理电平,因为有active_low属性,若在获取GPIO的时候指定了active_low属性,那么设置为1就是低电平,设置为0才是高电平。但是也有一些函数直接忽略active_low属性,整理如下:

unction(example)               active-low属性        物理电平 
gpiod_set_raw_value(desc, 0)    don't care             0 
gpiod_set_raw_value(desc, 1)    don't care             1 
gpiod_set_value(desc, 0)        是                     1 
gpiod_set_value(desc, 0)        否                     0 
gpiod_set_value(desc, 1)        是                     0 
gpiod_set_value(desc, 1)        否                     1

本文参考链接:https://www.cnblogs.com/hellokitty2/p/12500546.html