发布时间:2026/8/26 17:45:15
设备树之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/8/26 17:45:15

OPENAI GPT PLUS 日常开发你够用吗

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

2026/8/26 18:25:22

企业内训聊天记录怎么导出留存?EchoWe 人才培养场景完整操作指南

摘要 企业通过企业微信组织内训,从需求调研、讲师邀约、课程确认,到报名签到、课后考核、培训反馈,整个过程沉淀了大量关键沟通。这些记录一旦丢失,不仅无法证明培训已合规开展,还会在人才盘点、继任规划、培训效果评估…

2026/8/26 18:25:22

双 RTX 4090 24G 部署 Qwen3.8-27B + MTP 投机解码实战记录

前言本人单位内部有一台双4090 24G的工作站,需要用它来部署Qwen3.8-27B。之前是3.6-35B-A3B,用来跑Hermes Agent速度还可以,但是同事给换到27B后,速度慢得离谱,于是想动手优化一下,最终加上 vLLM 的 MTP 投…

2026/8/26 18:20:21

Flutter 广告接入不再散落:用 ads_manager 统一管理 AdMob

一套 API 接入 Banner、插屏、激励、激励插屏、原生和开屏广告,让广告初始化、预加载、展示回调和收益统计更加简单。 适用版本:ads_manager 1.2.2 技术栈:Flutter、Dart、Google Mobile Ads、AdMob 【一、为什么需要 ads_manager&#xff…

2026/8/26 9:13:28

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/25 11:48:27

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/25 16:56:43

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/26 0:04:32

Python random 模块常用函数详解:从入门到实战

目录 1. 引言2. 准备工作3. 基础随机函数4. 序列相关函数5. 随机种子与复现6. 实战案例7. 注意事项8. 常见问题与排查9. 总结 1. 引言 摘要: 本文系统介绍 Python 标准库 random 模块中最常用的随机数生成函数。内容涵盖基础随机函数(random()、unifor…

2026/8/26 1:19:35

JSON总结

JSON概念 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,主要用于跟服务器进行交换数据。它基于ECMAScript的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C、C、C#、Java、JavaScr…

2026/8/26 1:19:35

保存连接sse 是什么原理,为什么不会一直请求

“保持连接”用的是 SSE(Server-Sent Events),本质是一个没有马上结束的 HTTP 请求。 过程是: 拷贝机发送一次请求: GET /api/code-sync/events服务器返回: Content-Type: text/event-stream但不关闭响应&…

2026/8/24 13:42:17

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/24 18:13:48

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/25 1:08:14

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…