设备树之GPIO

发布时间:2026/10/27 11:41:42

设备树之GPIO 1、示例全景图┌──────────────────────────────────────────────│ 物理芯片上有 16 个引脚PA0 ~ PA15 ││ Pin Controller 决定PA0 今天是 GPIO还是 UART还是 SPI ││ GPIO Controller 决定PA0 既然是 GPIO那现在是高电平还是低电平 │└───────────────────────────────────────────────2、Pin Controller 节点pinctrl: pinctrl50000000 { compatible vendor,stm32-pinctrl; reg 0x50000000 0x4000; /* 定义一组引脚配置PA0~PA3 配成 GPIO 模式 */ gpioa_pins: gpioa-pins { pins PA0, PA1, PA2, PA3; function gpio; /* ← 身份GPIO */ drive-strength 8; /* 驱动能力 */ }; /* 另一组PA4~PA5 配成 UART 模式 */ uart1_pins: uart1-pins { pins PA4, PA5; function uart1_tx_rx; /* ← 身份UART */ bias-pull-up; /* 内部上拉 */ }; };通俗说这是引脚户口本管理处。gpioa_pins给 PA0~PA3 发了GPIO 身份证uart1_pins给 PA4~PA5 发了UART 身份证。同一个引脚不能同时领两个身份。3、GPIO Controller 节点gpioa: gpio50010000 { compatible vendor,stm32-gpio; reg 0x50010000 0x400; gpio-controller; /* ← 我是 GPIO 控制器 */ #gpio-cells 2; /* 引用我需要 2 个 cell */ /* 关键告诉内核我的 0~15 号线 pinctrl 的 PA0~PA15 */ gpio-ranges pinctrl 0 0 16; ngpios 16; };通俗说这是灯的开关总控台。它有 16 个开关0~15 号线。但它不知道这些开关对应哪个物理引脚所以通过gpio-ranges去问 Pin Controller我的 0 号线对应你的 PA01 号线对应 PA1……| 数字 | 值 | 含义 | | ---------- | ------- | ------------------------------- | | pinctrl | 引用 | 找这个 Pin Controller 要引脚 | | 0 | GPIO 偏移 | 从 GPIO 控制器的第 0 号线开始 | | 0 | Pin 偏移 | 对应 Pin Controller 的第 0 号引脚PA0 | | 16 | 数量 | 连续映射 16 条线0~15 → PA0~PA15 |Pin 偏移是芯片封装上物理引脚的全局编号PA00, PA11, PB016...‌Pin 偏移Index‌在pinctrl中使用直接对应硬件寄存器的位位置0-15。‌GPIO 偏移Base/Number‌在gpio子系统使用可能涉及全局编号计算例如 GPIOA 的基号是 0GPIOB 的基号是 16那么 PB5 的全局 GPIO 号是 16521。/dts-v1/; #include stm32mp157.dtsi #include stm32mp15xxac-pinctrl.dtsi / { model STM32MP157 Demo Board; compatible st,stm32mp157-demo, st,stm32mp157; /* * 【GPIO 控制器提供者 - Provider】 * 驱动代码中通过 devm_gpiochip_add_data() 向内核注册 * 消费者通过 my_gpio_expander N flags 引用其中的 GPIO * */ my_gpio_expander: gpio-expander20 { compatible vendor,my-gpio-exp; reg 0x20; /* I2C 地址 0x20 */ status okay; /* 声明本节点是一个 GPIO 控制器 */ gpio-controller; #gpio-cells 2; /* 消费者引用格式: ctrl pin flags */ ngpios 8; /* 该芯片提供 8 个 GPIO */ }; /* * 【消费者设备 - Consumer】 * pinctrl: 驱动中用 devm_pinctrl_get_select_default() 获取并应用 * GPIO: 驱动中用 devm_gpiod_get(dev, reset, ...) 获取 * */ my_device { compatible vendor,mydev; status okay; /* pinctrl 状态定义 */ pinctrl-names default, sleep; pinctrl-0 mydev_pins_default; /* 默认状态 */ pinctrl-1 mydev_pins_sleep; /* 低功耗状态 */ /* GPIO 消费者属性 */ reset-gpios gpioc 6 GPIO_ACTIVE_LOW; /* devm_gpiod_get(dev, reset, ...) */ done-gpios gpioa 13 GPIO_ACTIVE_HIGH; /* devm_gpiod_get(dev, done, ...) */ }; /* * 【另一个消费者LED】 * 引用外部 GPIO 控制器my_gpio_expander的第 2 号引脚 * 驱动中通过 devm_gpiod_get() 或 gpio-leds 子系统获取 * */ leds { compatible gpio-leds; status_led { /*gpios没有前缀用 devm_gpiod_get(dev, NULL, flags) 获取。*/ /*内核已经有 drivers/leds/leds-gpio.c开机自动会*/ /*echo 1 /sys/class/leds/exp-led2/brightness*/ /*echo 0 /sys/class/leds/exp-led2/brightness*/ gpios my_gpio_expander 2 GPIO_ACTIVE_HIGH; label exp-led2; default-state on; }; }; }; /* * 【pinctrl 引脚配置】 * 驱动中通过 devm_pinctrl_get_select_default() 自动应用 default 状态 * 通过 pinctrl_lookup_state() pinctrl_select_state() 手动切换 sleep 状态 * */ pinctrl { mydev_pins_default: mydev-pins-default { pins1 { pinmux STM32_PINMUX(C, 6, GPIO); /* PC6 reset */ drive-push-pull; bias-disable; slew-rate 0; }; pins2 { pinmux STM32_PINMUX(A, 13, GPIO); /* PA13 done */ drive-push-pull; bias-disable; }; }; mydev_pins_sleep: mydev-pins-sleep { pins { pinmux STM32_PINMUX(C, 6, ANALOG), STM32_PINMUX(A, 13, ANALOG); }; }; };#include linux/module.h #include linux/platform_device.h #include linux/pinctrl/consumer.h #include linux/gpio/consumer.h struct mydev_priv { struct pinctrl *pinctrl; struct pinctrl_state *sleep_state; struct gpio_desc *reset; struct gpio_desc *done; }; static int mydev_probe(struct platform_device *pdev) { struct device *dev pdev-dev; struct mydev_priv *priv; priv devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; /* 核心 API 1获取并应用 pinctrl default 状态 */ priv-pinctrl devm_pinctrl_get_select_default(dev); if (IS_ERR(priv-pinctrl)) return PTR_ERR(priv-pinctrl); /* 可选查找 sleep 状态供后续电源管理切换 */ priv-sleep_state pinctrl_lookup_state(priv-pinctrl, sleep); /* 核心 API 2获取 GPIO 消费者 */ priv-reset devm_gpiod_get(dev, reset, GPIOD_OUT_HIGH); if (IS_ERR(priv-reset)) return PTR_ERR(priv-reset); priv-done devm_gpiod_get(dev, done, GPIOD_IN); if (IS_ERR(priv-done)) return PTR_ERR(priv-done); /* 使用 GPIO */ gpiod_set_value(priv-reset, 0); /* 拉低复位 */ msleep(10); gpiod_set_value(priv-reset, 1); /* 释放复位 */ platform_set_drvdata(pdev, priv); dev_info(dev, mydev probed ok\n); return 0; } /* 手动切换 pinctrl 状态进入/退出睡眠 */ static int mydev_suspend(struct device *dev) { struct mydev_priv *priv dev_get_drvdata(dev); if (!IS_ERR_OR_NULL(priv-sleep_state)) pinctrl_select_state(priv-pinctrl, priv-sleep_state); return 0; } static int mydev_resume(struct device *dev) { struct mydev_priv *priv dev_get_drvdata(dev); struct pinctrl_state *def; def pinctrl_lookup_state(priv-pinctrl, default); if (!IS_ERR_OR_NULL(def)) pinctrl_select_state(priv-pinctrl, def); return 0; } static const struct dev_pm_ops mydev_pm_ops { .suspend mydev_suspend, .resume mydev_resume, }; static const struct of_device_id mydev_of_match[] { { .compatible vendor,mydev }, {} }; MODULE_DEVICE_TABLE(of, mydev_of_match); static struct platform_driver mydev_driver { .probe mydev_probe, .driver { .name mydev, .of_match_table mydev_of_match, .pm mydev_pm_ops, }, }; module_platform_driver(mydev_driver); MODULE_LICENSE(GPL); MODULE_DESCRIPTION(Demo Consumer Device);my_device { /* 区域 1pinctrl 状态一级节点 */ pinctrl-names default; pinctrl-0 mydev_pins_default; /* 区域 2GPIO 消费者属性和 gpiod API 对应 */ reset-gpios gpioc 6 GPIO_ACTIVE_LOW; // ← devm_gpiod_get(dev, reset, ...) led-gpios gpioa 13 GPIO_ACTIVE_HIGH; // ← devm_gpiod_get(dev, led, ...) }; pinctrl { /* 区域 3pinctrl 配置二级节点 */ mydev_pins_default: mydev-pins-default { // ← 一级状态节点 pins { // ← 二级配置节点 pinmux STM32_PINMUX(C, 6, GPIO); bias-disable; }; }; };总结你在设备树看到属于哪个世界驱动里怎么操作pinctrl-0 xxx世界 Adevm_pinctrl_get_select_default(dev)pinctrl-names sleep世界 Apinctrl_lookup_state()pinctrl_select_state()pins { pinmux ... }世界 C无 API内核自动解析reset-gpios ...世界 Bdevm_gpiod_get(dev, reset, ...)led-gpios ...世界 Bgpiod_set_value(led, 1/0)类型设备树写法内核消费者你需要写驱动吗LEDcompatible gpio-ledsdrivers/leds/leds-gpio.c❌ 不用写按键compatible gpio-keysdrivers/input/keyboard/gpio_keys.c❌ 不用写固定电压compatible regulator-fixeddrivers/regulator/fixed.c❌ 不用写简单 PWMcompatible pwm-ledsdrivers/leds/leds-pwm.c❌ 不用写看门狗 GPIOcompatible gpio-wdtdrivers/watchdog/gpio_wdt.c❌ 不用写厂商自定义compatible vendor,mydev你自己写的 mydev.c✅ 必须写
延伸阅读

更多相关文章

2026/10/27 11:39:39

OPENAI GPT PLUS 日常开发你够用吗

你的 AI 算力够用吗?开发者日常消耗量级自测: 别凭感觉买 Token,看看你属于哪个段位? 轻度玩家(≈ 1个 Plus 账号的量):日常写写代码、查查 Bug,偶尔让 AI 润色一下文档&#xff0…

2026/10/27 11:40:45

2026国产大模型核心技术解析与开发实战指南

1. 国产大模型发展现状与技术特征 2026年的国产大模型已经形成了独特的技术路线和产业生态。与三年前相比,当前主流模型的参数量级普遍达到万亿级别,但在架构设计上更注重实用性和性价比。典型代表如华为的"盘古3.0"、百度的"文心5.0&quo…

2026/10/27 11:40:45

SSE流式输出实战:协议、网关缓冲与断线重连排坑

1. 先把这件被说烂了的事讲透:SSE到底在流式对话里扮演什么角色 前阵子帮一个团队看他们的对话产品,现象很典型:后端日志显示模型已经在吐字了,前端界面上那个“思考中”的转圈图标还转足了三秒,然后一大段文字“啪”地…

2026/10/27 11:40:45

大模型与知识图谱融合架构设计与实践

1. 大模型与知识图谱的融合趋势 最近两年,大模型和知识图谱这两个技术方向都获得了突破性进展。作为一名长期跟踪AI技术发展的从业者,我观察到这两者的结合正在催生新一代智能系统。大模型以其强大的语言理解和生成能力著称,而知识图谱则以结…

2026/10/27 11:40:45

AI代理视频渲染如何实现确定性?HyperFrames框架原理与实践

1. 为什么“确定性渲染”是 AI 代理做视频的第一道生死线如果你最近在折腾 AI 代理自动生成视频,大概率遇到过这种让人抓狂的情况:同一个提示词、同一份素材、同一个脚本,跑第一遍出来的视频没问题,跑第二遍字幕错位了&#xff0c…

2026/10/27 11:40:45

基于改进Mask R-CNN的自卸车部件识别与优化实践

1. 项目背景与核心挑战 自卸车作为工程机械领域的重要运输工具,其关键部件(如货箱、液压缸、车架等)的实时识别与状态监测对智能运维和自动化作业至关重要。传统人工检测方式存在效率低、成本高、主观性强等问题,而基于深度学习的…

2026/10/27 11:35:37

DB2异机恢复实战:NetBackup跨机还原避坑指南

简介:本资源是一份面向DB2数据库管理员与企业级灾备工程师的DB2异机恢复技术实践指南,聚焦基于Veritas NetBackup(NBU)实现跨服务器环境的DB2数据库可靠恢复,解决生产环境中因硬件故障、机房迁移等场景下的业务连续性保…

2026/10/26 0:20:20

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/27 9:34:54

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/27 0:59:21

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式19_“模式选错”的典型代价

“模式选错”的典型代价 摘要 在软件工程中,设计模式、架构模式、并发模式乃至团队协作模式的选择,往往在项目早期就决定了后续的开发效率和维护成本。本文通过多个真实场景,剖析“模式选错”带来的典型代价——包括返工成本、技术债务累积、…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式20_新手推荐路径

新手推荐路径 摘要 在 AI 辅助开发工具快速普及的今天,新手面对最多的困惑往往不是"工具够不够强",而是"我该从哪一步开始用"。本文提出一条经过实践验证的三阶段学习路径:先从 Ask(问答式交互)起…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑