设备树之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✅ 必须写

相关新闻

OPENAI GPT PLUS 日常开发你够用吗

OPENAI GPT PLUS 日常开发你够用吗

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

2026/11/14 12:43:15 阅读更多 →
CPS测试真正衡量的是什么(以及如何在不伤到手的情况下提高测试成绩)

CPS测试真正衡量的是什么(以及如何在不伤到手的情况下提高测试成绩)

CPS测试真正衡量的是什么(以及如何在不伤到手的情况下提高测试成绩) 每秒点击数、测试时长、点击技巧及获取可重复结果的实用指南 每秒点击次数测试看起来几乎简单到无法解释。你只需在方框内点击,直到计时器停止,然后将点击次数…

2026/11/14 10:37:16 阅读更多 →
阿里云 ECS 云原生实战:部署架构与网络验收

阿里云 ECS 云原生实战:部署架构与网络验收

阿里云 ECS 云原生实战:部署架构与网络验收工具地址:https://www.speedce.com 社区论坛:https://bbs.speedce.com 联系:speedceadsgmail.com写在前面 围绕「阿里云 ECS」,本文提供可落地的技术指南,并在关键…

2026/10/25 4:21:18 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/14 5:13:29 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/14 5:13:29 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/14 5:13:29 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/13 22:08:41 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/14 2:41:37 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/14 5:13:29 阅读更多 →

日新闻

周新闻

月新闻