NXP i.MX8系列平台开发讲解 - 3.7 Linux 之GPIO子系统

本文详细介绍了LinuxGPIO子系统在i.MX8MQ平台上的应用,包括GPIO子系统的作用、与Pinctrl的关系、gpiolib功能、gpiodriver实现、设备树配置以及sysfs操作方法。着重讨论了GPIO的管理和控制,以及如何利用系统文件系统进行设备操作,提高开发效率和平台移植性。
摘要由CSDN通过智能技术生成

专栏文章目录传送门返回专栏目录


目录

1. GPIO 子系统简介

2. GPIO子系统的作用与Pinctrl关系

2.1. GPIO子系统作用

2.2 GPIO与Pinctrl关系

3. GPIO子系统的实现

3.1. gpiolib功能

3.2 gpio driver

4. 设备树相关分析

5. sysfs 操作GPIO

6. 总结


本文实操是基于Android11 系统下i.MX8MQ环境下:

  • cpu: i.mx8mq

  • OS:Android 11

  • Kernel version:kernel 5.4

Linux GPIO子系统是Linux内核中的一个子系统,用于管理通用输入输出(GPIO)引脚。GPIO引脚是一种通用的数字引脚,可以在运行时被配置为输入或输出,用于连接各种外部设备和传感器。


1. GPIO 子系统简介

GPIO 代表通用输入/输出,是嵌入式 Linux 系统中最常用的外设之一。在内部,Linux 内核通过生产者/消费者模型实现对 GPIO 的访问。有生成 GPIO 线路的驱动程序 (GPIO 控制器驱动程序) 和使用 GPIO 线路的驱动程序 (键盘、触摸屏、传感器等) 。

为了管理 GPIO 注册和分配,Linux 内核中有一个名为 gpiolib 的框架。此框架为内核空间和用户空间应用程序中运行的设备驱动程序提供 API。

图片

根据上图,系统的最底层是 GPIO 控制器,其驱动是与硬件相关的模块。主要功能是调用 GPIO 库提供的注册接口。而 GPIO 库则是一个与硬件无关的模块,专门用于管理 GPIO 控制器的注册和注销。对于用户层而言,只需要操作相关文件即可,无需关注底层的具体细节。这种设计让用户能够更方便地进行 GPIO 控制,而无需深入了解底层硬件的相关内容。


2. GPIO子系统的作用与Pinctrl关系

GPIO子系统是用于去管理控制GPIO,能有一套统一的接口设备去管理,大大降低了开发的困难,增加了方便。

2.1. GPIO子系统作用

  • 外设控制:通过配置 GPIO 引脚为输出,用户可以轻松地控制外部设备,如 LED、蜂鸣器、继电器等。

  • 传感器接口:GPIO 子系统允许配置 GPIO 引脚为输入,从而可以读取外部传感器的状态,实现与传感器的通信和数据采集。

  • 简化开发:GPIO 子系统提供了一个简单且统一的接口,使得开发者可以更容易地与 GPIO 引脚进行交互,而无需编写底层驱动程序。

  • 平台移植性:GPIO 子系统的抽象层次使得 Linux 内核可以在不同硬件平台上运行,而无需对 GPIO 控制器进行特定的适配。

2.2 GPIO与Pinctrl关系

GPIO子系统是对GPIO进行初始化设置,并且提供一些操作的接口,比如设置输入输出,读取GPIO的状态等等,但是在最这些操作之前都需要使用到pinctrl子系统对GPIO进行一系列的秒速设置PIN的复用还有电器属性,就比如对PIn设置为什么功能GPIO

总体来说就是,在pinctrl子系统定义在gpio之前就需要操作完毕。


3. GPIO子系统的实现

GPIO子系统实现需要的主要代码:


./drivers/gpio/gpiolib-cdev.c //GPIO 控制器字符设备接口的实现
./drivers/gpio/gpiolib-devres.c  //GPIO 控制器设备资源管理
./drivers/gpio/gpiolib-legacy.c //旧版本gpio 兼容
./drivers/gpio/gpiolib-sysfs.c  //支持文件系统操作
./drivers/gpio/gpiolib.c  //gpio 子系统核心实现
./drivers/gpio/gpiolib-of.c // 设备树支持

//i.MX8MQ 支持的gpio
./drivers/gpio/gpio-mxc.c

图片

根据图中,看到GPIO驱动框架中的,gpiolib是一个比较重要的部分,提供了一组不依赖硬件的接口层,可以看作为一个类似的中间层,对于怎么去实现这些接口都是Soc硬件厂商需要去完善。比如这里用到的i.MX8MQ ,就需要使用到./drivers/gpio/gpio-mxc.c, 如里是其他平台那就需要配合其他Soc代码。

3.1. gpiolib功能

这里将介绍几个重要的功能函数

# gpio的电平设置和检测
void gpiod_set_value(struct gpio_desc *desc, int value)
int gpiod_get_value(const struct gpio_desc *desc)
# gpio 的方向设置
int gpiod_direction_output(struct gpio_desc *desc, int value)
int gpiod_direction_input(struct gpio_desc *desc)
# gpio控制器的添加与移除
int gpiochip_add(struct gpio_chip *chip);
void gpiochip_remove(struct gpio_chip *chip);
# gpio申请与释放
int gpiod_request(struct gpio_desc *desc, const char *label);
void gpiod_free(struct gpio_desc *desc);

3.2 gpio driver

gpio driver这个将会包含gpio_chip, gpio_desc,这个结构体就完全包含了所有的一些操作,再加上gpio_device一般会有多个这样就形成一个链表。

LIST_HEAD(gpio_devices);

图片

其中gpio 设备结构体可以看到具体的关系结构体
 


//./drivers/gpio/gpiolib.h
struct gpio_device {
        int                     id;
        struct device           dev;
        struct cdev             chrdev;
        struct device           *mockdev;
        struct module           *owner;
        struct gpio_chip        *chip;
        struct gpio_desc        *descs;
        int                     base;
        u16                     ngpio;
        const char              *label;
        void                    *data;
        struct list_head        list;
        struct blocking_notifier_head notifier;

#ifdef CONFIG_PINCTRL
        /*
         * If CONFIG_PINCTRL is enabled, then gpio controllers can optionally
         * describe the actual pin range which they serve in an SoC. This
         * information would be used by pinctrl subsystem to configure
         * corresponding pins for gpio usage.
         */
        struct list_head pin_ranges;
#endif
};


4. 设备树相关分析

 以i.MX8MQ设备树为例

//vim ./arch/arm64/boot/dts/freescale/imx8mq.dtsi

                        gpio1: gpio@30200000 {
                                compatible = "fsl,imx8mq-gpio", "fsl,imx35-gpio";
                                reg = <0x30200000 0x10000>;
                                interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clk IMX8MQ_CLK_GPIO1_ROOT>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
                                #interrupt-cells = <2>;
                                gpio-ranges = <&iomuxc 0 10 30>;
                        };

                        gpio2: gpio@30210000 {
                                compatible = "fsl,imx8mq-gpio", "fsl,imx35-gpio";
                                reg = <0x30210000 0x10000>;
                                interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clk IMX8MQ_CLK_GPIO2_ROOT>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
                                #interrupt-cells = <2>;
                                gpio-ranges = <&iomuxc 0 40 21>;
                        };

                        gpio3: gpio@30220000 {
                                compatible = "fsl,imx8mq-gpio", "fsl,imx35-gpio";
                                reg = <0x30220000 0x10000>;
                                interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
                                             <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
                                clocks = <&clk IMX8MQ_CLK_GPIO3_ROOT>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
                                #interrupt-cells = <2>;
                                gpio-ranges = <&iomuxc 0 61 26>;
                        };
                        //未完...

​​​​​​

从设备树来看,定义了好几个gpio组,gpio1,gpio2,gpio3都是一个GPIO控制器,都是Soc厂商已经设定好,接下来我们去如何定义一个GPIO,这里截取部分DTS。


&pcie0 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_pcie0>;
        disable-gpio = <&gpio3 17 GPIO_ACTIVE_LOW>;
        reset-gpio = <&gpio1 5 GPIO_ACTIVE_LOW>;
        uwake-gpio = <&gpio3 22 GPIO_ACTIVE_LOW>;

其中reset-gpio = <&gpio1 5 GPIO_ACTIVE_LOW>;

这里就是设置了gpio1_io5 reset 低电平有效,在通过驱动将会使用起这个GPIO,从设备树来看都是采用定义GPIO所属的组,和它的offset号,有效电平是什么即可,再配合当前使用在某个驱动上,驱动会对该GPIO进行操作。


5. sysfs 操作GPIO

 此功能需要在内核开启配置CONFIG_GPIO_SYSFS

图片

gpio一共有5组,一共有5个bank,5个控制器 同时在dev 下可以看到设备

图片

查看gpio控制器的详细信息

图片

对于GPIO控制器各个的含义介绍

文件名称含义
baseGPIO  控制器管理的 GPIO 引脚中的第一个引脚的编号。
device符号链接,指向与  GPIO 控制器相关的设备对象的路径和信息。
labelGPIO  控制器的标签或名称,用于标识其用途或所属设备。
ngpioGPIO  控制器支持的 GPIO 引脚的数量。
power包含与  GPIO 控制器的电源管理信息的目录。
subsystem包含与  GPIO 控制器相关的子系统信息的目录。
uevent包含与 GPIO 控制器设备的 uevent 事件相关的信息。

设置GPIO输出模式步骤

echo  N > /sys/class/gpio/export
echo out > /sys/class/gpio/gpioN/direction 
echo 1 > /sys/class/gpio/gpioN/value
echo  N > /sys/class/gpio/unexport

设置GPIO输入模式步骤

echo  N > /sys/class/gpio/export
echo in > /sys/class/gpio/gpioN/direction 
cat  /sys/class/gpio/gpioN/value
echo  N > /sys/class/gpio/unexport

这里的N是引脚的号码,计算方式为GPIO所在的基值加上引脚的offset就得到了N

举例:MX8MQ_IOMUXC_I2C4_SDA_GPIO5_IO21 设置输出状态

N=4*32+21=149

疑问:这里为什么是4*32而不是5*32,这里说明下,这里GPIO5其实对应的是gpiochip128(第5个gpio控制器),但在i.MX8MQ设备树中的不是以GPIO0开头,是以GPIO1开始,所以就要减去1。

# MX8MQ_IOMUXC_I2C4_SDA_GPIO5_IO21

echo 149 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio149/direction
cat /sys/class/gpio/gpio149/direction
echo 1 > /sys/class/gpio/gpio149/value

图片

将MX8MQ_IOMUXC_SAI1_RXC_GPIO4_IO1 设置成输入模式

echo 97 > /sys/class/gpio/export
echo in > /sys/class/gpio/gpio97/direction
cat /sys/class/gpio/gpio97/direction
cat /sys/class/gpio/gpio97/value


6. 总结

GPIO子系统大概就这样讲完了,主要还是通过gpiolib去实现整个功能,然后用户通过操作文件系统方式进行控制gpio,引入gpio子系统就已经系统管理起各种不一样Soc的GPIO,使用更加方便。

  • 28
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值