0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

驱动之路#21:一行 reset-gpios,驱动为何就能用 GPIO?

BSP调试从0到1 来源:嵌入式分享 作者:嵌入式分享 2026-04-14 09:20 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

本合集分享的是,我当初学习Linux驱动的来时路——《《驱动之路》开篇:自序&前言》。

正文

嵌入式 Linux 开发中,我们经常会在设备树(DTS)中写下这样的配置:

1640195c-37a0-11f1-b0db-92fbcf53809c.png

神奇的是,驱动程序无需手动操作寄存器、无需硬编码 GPIO 编号,就能通过内核提供的接口轻松获取这个复位 GPIO,实现设备复位控制。这背后的底层逻辑是什么?今天就扒一扒这层底层逻辑。

1 DTS 到底在配置什么?

首先我们得明确,reset-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>; 这行代码不是给 CPU 看的,而是给内核和驱动的 “约定说明书”,每一部分都有明确含义:

reset-gpios:是 “属性名”,遵循 Linux 设备树的 GPIO 属性命名规范(后缀-gpios),告诉内核 “这是一个用于复位功能的 GPIO 配置”。

&gpio2:是 “GPIO 控制器的引用”,表示这个 GPIO 归属于gpio2控制器。

RK_PB4:是 “GPIO 引脚编号”,是芯片厂商定义的宏,本质是一个整数。

GPIO_ACTIVE_HIGH:是 “GPIO 有效电平”,表示该 GPIO 为高电平有效。

PS:GPIO_ACTIVE_HIGH会被内核解析并存储在gpio_desc中,驱动调用 gpiod_set_value() 时:若配置为GPIO_ACTIVE_HIGH,驱动传入1则内核设置 GPIO 为高电平,传入0为低电平;若配置为GPIO_ACTIVE_LOW,驱动传入1则内核自动设置为低电平(有效电平),传入0为高电平。驱动无需关心 “有效电平是高还是低”,只需按 “逻辑值”(1 = 有效,0 = 无效)调用接口,内核会自动完成电平转换。也就是说,gpiod_set_value() 设置的是“逻辑值”而非“物理值”。

简单说,这行配置的核心作用是:向内核声明 “当前设备的复位 GPIO 是 gpio2 控制器的 PB4 引脚,高电平有效”,为后续驱动获取 GPIO 打下基础。

2 DTS 配置到驱动获取的 4 个关键步骤

DTS 配置只是 “纸上约定”,驱动能真正拿到 GPIO 并使用,依赖内核的 “解析 - 注册 - 匹配 - 提供” 全流程。

步骤 1:内核解析 DTS,提取 GPIO 配置信息

Linux 内核启动时,会先执行 “设备树解析阶段”:

(1)内核的设备树解析器(dtb_parser)会遍历 DTS 文件,找到所有带-gpios后缀的属性(包括reset-gpios)。

(2)解析器会识别&gpio2对应的 GPIO 控制器(通过 DTS 中gpio2节点的compatible属性匹配内核中的 GPIO 驱动,比如rockchip,rk3576-gpio).

(3)将RK_PB4引脚编号转换为内核统一的 “GPIO 全局编号”(这是关键!)。内核为了管理所有 GPIO,会给每个 GPIO 分配一个全局唯一的整数 ID(GPIO 编号),其计算规则如下:

169c8084-37a0-11f1-b0db-92fbcf53809c.png (4)解析器将 “GPIO 编号 + 有效电平” 封装成struct gpio_desc结构体(GPIO 描述符,内核中代表一个 GPIO 的 “身份证”),并与当前设备的struct device结构体关联(存在设备的私有数据中)。 至此,DTS 中的 “文字配置” 已被内核解析为 “可操作的 GPIO 描述符”,就像把 “地址信息” 转换成了 “快递单号”,等待驱动来 “取件”。

步骤 2:GPIO 控制器驱动初始化,提供操作接口

在解析 DTS 之前,内核已经加载了gpio2对应的 GPIO 控制器驱动(通常是芯片原厂 BSP 工程师编写的平台驱动),该驱动会完成两件关键事:

(1)向内核 GPIO 子系统注册struct gpio_chip结构体(GPIO 芯片描述符),其中包含:

GPIO 控制器的基地址(操作寄存器的物理地址,已通过ioremap映射为虚拟地址);

该控制器管理的 GPIO 数量(比如gpio2管理 32 个引脚);

操作 GPIO 的核心函数(request申请、free释放、set_value设置电平、get_value读取电平)。

(2)内核 GPIO 子系统会为该控制器分配 “GPIO 基号”(比如gpio2分配 32-63 号),确保全局编号不重复。

这一步的作用是:让内核具备操作gpio2控制器下所有 GPIO 的能力,相当于给 “快递站” 配备了 “快递员”(操作函数),能处理后续的 GPIO 申请和控制请求。

步骤 3:设备与驱动匹配,驱动申请 GPIO 资源

当内核完成 DTS 解析和 GPIO 控制器初始化后,会启动 “设备与驱动匹配” 流程:

(1)内核根据 DTS 中当前设备节点的compatible属性,在驱动链表中查找匹配的设备驱动。 (2)驱动匹配成功后,会执行probe函数,在probe函数中,驱动会通过内核提供的 GPIO 申请接口,获取reset-gpios对应的 GPIO。

比如:

16f612a2-37a0-11f1-b0db-92fbcf53809c.png

这里的核心接口是devm_gpiod_get_optional(devm_前缀表示内核自动管理资源,驱动卸载时自动释放 GPIO),它接收参数"reset"对应 DTS 中的reset-gpios属性(内核会自动拼接-gpios后缀)。

步骤 4:驱动操作 GPIO,实现业务功能

通过层层函数调用,驱动最终拿到reset_gpio(gpio_desc指针)。

1751cbf6-37a0-11f1-b0db-92fbcf53809c.png

然后就可以通过内核提供的接口gpiod_set_value() 操作 GPIO 的电平,这里的gpiod_set_value() 接口会最终调用 GPIO 控制器驱动中的set_value函数,通过操作 GPIO 寄存器(如输出控制寄存器、数据寄存器)实现电平切换,完成硬件层面的复位控制。

17af5776-37a0-11f1-b0db-92fbcf53809c.png

3 总结

DTS 配置reset-gpios后驱动能直接获取,本质是 “三层约定 + 两层封装” 的结果:

三层约定:DTS 与内核的 “配置格式约定”、GPIO 控制器与内核的 “驱动接口约定”、驱动与内核的 “资源申请约定”;

两层封装:内核 GPIO 子系统封装硬件差异、devm_机制封装资源管理。

这种设计让嵌入式开发摆脱了 “寄存器操作的繁琐” 和 “硬件差异的困扰”,驱动开发者只需专注于业务逻辑(比如何时触发复位),无需关心底层实现,这也是 Linux 设备树 “硬件描述与驱动分离” 设计思想的核心体现。

最后留个问题: reset-gpios里的GPIO_ACTIVE_HIGH能随便写吗?我们下期分享~

(完)

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5210

    文章

    20731

    浏览量

    338264
  • 驱动
    +关注

    关注

    12

    文章

    1999

    浏览量

    88765
  • Linux
    +关注

    关注

    88

    文章

    11848

    浏览量

    219756
  • GPIO
    +关注

    关注

    16

    文章

    1336

    浏览量

    56550
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    Linux reset子系统及驱动实例

    上篇讲了Linux clock驱动,今天说说Linux的reset驱动
    发表于 05-31 16:16 1921次阅读
    Linux <b class='flag-5'>reset</b>子系统及<b class='flag-5'>驱动</b>实例

    驱动之路#22:reset-gpios参数能随便写吗?

      正文 刚开始在配置 reset-gpios = 时,我会疑惑: GPIO_ACTIVE_HIGH 只是个“标记”吗?能不能随便写成 GPIO_ACTIVE_LOW ,或者干脆不写? 答案
    的头像 发表于 04-29 18:13 2755次阅读
    <b class='flag-5'>驱动</b><b class='flag-5'>之路</b>#22:<b class='flag-5'>reset-gpios</b>参数能随便写吗?

    如何在 Yocto 中集成由 HID 设备控制的 I2C 触摸驱动程序?

    ;amp;ft260_gpio>; 中断 = IRQ_TYPE_EDGE_FALLING>; reset-gpios = <&ft260_gpio 2 GPIO
    发表于 04-23 07:22

    linux下如何修改gpio驱动

    今天我们大家讨论下关于GPIO驱动些东西,首先我们来看下针对OK210开发板LED驱动的源码,这也是个比较简单的
    发表于 01-14 14:45

    74HC595驱动点阵显示一行

    大神帮我看看,点阵显示一行的程序,下载进去不亮#include#include#define NOP() _nop_()***it SER=P3^4;***it R_CLK=P3^5
    发表于 09-29 23:55

    个多行的字符串如何一行一行的执行然后一行一行的显示出来啊

    要做个将hex文件转化成bin 文件的labview,结果发现不少按一行一行处理的,而是将所有字符串当成一行来处理的,就是假如有5二十个
    发表于 06-30 14:24

    想问下为什么我把第一行和第二换了个位置就会出现很多报错?

    想问下为什么我把第一行和第二换了个位置就会出现很多报错?int main(void){GPIO_InitTypeDef GPIO_InitStructure;第
    发表于 04-07 15:47

    Labview 怎么用报表生成函数 一行一行自动换行写表格Excel

    `Labview 怎么用报表生成函数 一行一行自动换行写表格Excel`
    发表于 11-21 13:37

    怎样按照我的个excel模版,一行一行的把数据写入而且上一行的数据不会消失。

    目前我做到。把数据一行一行输入,用添加表格到excel的控件,但是每次写入,上次的数据就没了。怎么样实时向excel填入数据,一行
    发表于 12-21 11:52

    请问下aio-3588sJd4触摸屏的驱动源码在哪个目录下?

    ;simple-panel-dsi";reg = ;backlight = ;//enable-gpios = ;reset-gpios = ;enable-delay-ms
    发表于 02-13 10:28

    NAU8822的IIC接口用GPIO-base的驱动,如何换成硬件IIC的驱动

    CCAP0_GATE>; clock-names = \"xclk\"; reset-gpios = < gpiom 1 GPIO_ACTIVE_LOW>
    发表于 08-18 07:28

    一行代码——Android

    android开发。第一行代码开发入门 。
    发表于 03-21 11:40 0次下载

    一行代码——Android

    一行代码——Android
    发表于 03-19 11:24 0次下载

    Linux内核reset驱动实例

    reset驱动实例 类似于clock驱动reset驱动也是编进内核的,在Linux启动时,完成rese
    的头像 发表于 09-27 14:21 1949次阅读

    驱动之路#03:LCD 时序参数分析

    (有效行前的不可视行数),移动到首个有效的 “准备行数”;10 tvfp: 垂直下宽/前肩(有效后的不可视行数),扫完最后一行后的 “收尾行数”;22 tvd: 每帧有效行数(分辨率垂直值),屏幕实际显示的垂直像素数(行数)
    的头像 发表于 02-10 08:27 3238次阅读
    <b class='flag-5'>驱动</b><b class='flag-5'>之路</b>#03:LCD 时序参数分析