一、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