一句话:GPIO Hog 是一种 DTS 配置机制,让内核在注册 GPIO 控制器时自动预占指定引脚并设置初始状态,无需专门的驱动程序去申请它。
一、为什么需要 GPIO Hog
正常情况下,GPIO 引脚由对应的驱动在 probe() 时通过 gpiod_get() 申请,在 remove() 时释放。这套流程适合”有驱动管理的外设”。
但有一类 GPIO 比较特殊:
- 硬件复位引脚(如 USB Hub 的 RESET_N、以太网 PHY 的 RST)——需要在系统启动极早期拉高/拉低,但没有独立驱动
- 上电使能引脚(如某个电源轨的 EN 脚)——需要在 regulator 驱动加载之前就处于确定电平
- 硬件配置引脚(如启动模式选择)——上电后需要立即固定状态,不能浮空
对这类引脚,如果等驱动 probe() 才去申请,时序可能已经来不及;如果专门为它写一个空壳驱动又太重。
GPIO Hog 解决的就是这个问题:在 GPIO 控制器注册完成的瞬间,内核立刻预占并配置这些引脚,早于任何外设驱动的 probe(),且不需要独立驱动。
二、核心概念
GPIO Hog(”占用”/”独占”)是 Linux 3.12 引入的机制,配置方式是 DTS,不是驱动代码。
关键特点:
| 特点 | 说明 |
|---|---|
| 配置位置 | GPIO 控制器节点的子节点,DTS 中声明 |
| 触发时机 | GPIO chip 注册时(gpiochip_add_data()),早于外设驱动 probe |
| 是否需要驱动 | 不需要,内核自动处理 |
| 引脚状态 | 被标记为 FLAG_IS_HOGGED,其他驱动无法再申请 |
| 电平控制 | 支持输出高、输出低、输入三种模式 |
三、DTS 配置方法
3.1 基本语法
在 GPIO 控制器节点下添加子节点,子节点必须包含 gpio-hog 属性:
&gpio_controller {
子节点名称 {
gpio-hog; /* 标记这是一个 hog 节点,必须有 */
gpios = <引脚编号 极性标志>; /* 指定引脚 */
output-high; /* 配置为输出,逻辑高电平 */
/* output-low; 或输出低电平 */
/* input; 或配置为输入 */
line-name = "描述性名称"; /* 可选,用于标识该引脚 */
};
};
3.2 DTS 属性说明
| 属性 | 是否必须 | 说明 |
|---|---|---|
gpio-hog | ✅ 必须 | 声明这是一个 hog 节点,无值,仅凭存在触发 |
gpios | ✅ 必须 | <偏移量 极性>,极性:0=高有效,1=低有效 |
output-high | 三选一 | 配置为输出,输出逻辑 1(高) |
output-low | 三选一 | 配置为输出,输出逻辑 0(低) |
input | 三选一 | 配置为输入,只占用不驱动 |
line-name | 可选 | 引脚标识名,会显示在 /sys/kernel/debug/gpio |
⚠️ 极性与电平的关系:
gpios = <7 1>表示 GPIO 7,低有效(active-low)。此时output-high输出的是逻辑高,但物理引脚实际为低电平(经过极性反转)。如果只是要控制物理引脚电平,建议将极性设为0(高有效),直接用output-high/output-low控制物理电平,语义更清晰。
3.3 完整示例
/* iMX6ULL GPIO 控制器节点示例 */
&gpio1 {
/* USB Hub 复位引脚:输出低电平,保持 Hub 处于工作状态(RESET_N 低有效) */
usb_hub_reset_hog: usb-hub-reset {
gpio-hog;
gpios = <7 GPIO_ACTIVE_LOW>;
output-high; /* 逻辑高 → 物理低 → Hub 正常工作 */
line-name = "usb-hub-reset";
};
};
&gpio3 {
/* 以太网 PHY 复位:上电后立即释放复位(高电平 = 正常工作) */
eth_phy_reset_hog: eth-phy-reset {
gpio-hog;
gpios = <4 GPIO_ACTIVE_HIGH>;
output-high;
line-name = "eth-phy-reset";
};
/* 某个硬件配置引脚:只需占用,配置为输入即可 */
mode_sel_hog: mode-select {
gpio-hog;
gpios = <12 GPIO_ACTIVE_HIGH>;
input;
line-name = "mode-select";
};
};
四、内核处理流程
GPIO Hog 的整个处理过程由内核自动完成,驱动开发者不需要写任何 C 代码:
gpiochip_add_data() ← 驱动调用,注册 GPIO 控制器
└─ of_gpiochip_add(gc) ← 绑定 DTS 节点
└─ of_gpiochip_scan_gpios(gc)
│
├─ 遍历 GPIO 控制器节点的所有子节点
│
└─ 发现含 "gpio-hog" 属性的子节点
│
├─ 解析 gpios、output-high/output-low/input、line-name
│
└─ gpiod_hog(desc, name, lflags, dflags)
├─ gpiochip_request_own_desc() ← 内部申请,不走正常请求流程
├─ set_bit(FLAG_IS_HOGGED, &desc->flags) ← 标记为已 hog
└─ 按配置设置引脚方向和电平
时序意义:整个流程在 GPIO chip 注册完成时同步完成,早于总线扫描和外设驱动的 probe()。
五、gpiod_hog() 内部实现(仅供参考)
gpiod_hog() 是内核内部函数,驱动开发者不应直接调用,这里列出源码仅作理解参考:
/* drivers/gpio/gpiolib.c */
int gpiod_hog(struct gpio_desc *desc, const char *name,
unsigned long lflags, enum gpiod_flags dflags)
{
struct gpio_chip *gc;
struct gpio_desc *local_desc;
int hwnum;
int ret;
gc = gpiod_to_chip(desc);
hwnum = gpio_chip_hwgpio(desc);
/* 通过 chip 内部接口申请,绕过正常的 gpiod_get 流程 */
local_desc = gpiochip_request_own_desc(gc, hwnum, name,
lflags, dflags);
if (IS_ERR(local_desc)) {
ret = PTR_ERR(local_desc);
pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %dn",
name, gc->label, hwnum, ret);
return ret;
}
/* 在描述符的 flags 中打上 hogged 标记 */
set_bit(FLAG_IS_HOGGED, &desc->flags);
gpiod_info(desc, "hogged as %s%sn",
(dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input",
(dflags & GPIOD_FLAGS_BIT_DIR_OUT) ?
(dflags & GPIOD_FLAGS_BIT_DIR_VAL) ? "/high" : "/low" : "");
return 0;
}
关键点:
- 使用
gpiochip_request_own_desc()而非gpiod_get(),这是 chip 内部的私有申请路径 - 设置
FLAG_IS_HOGGED后,其他驱动调用gpiod_get()申请同一引脚时会返回-EBUSY
六、GPIO Hog vs 普通 GPIO 申请
| 对比项 | GPIO Hog(DTS) | 普通申请(gpiod_get()) |
|---|---|---|
| 配置位置 | GPIO 控制器子节点 | 外设节点的 gpios 属性 + 驱动代码 |
| 申请时机 | GPIO chip 注册时,极早期 | 外设驱动 probe() 时 |
| 需要驱动 | 不需要 | 需要外设驱动 |
| 引脚归属 | 内核持有,无驱动主体 | 由申请的驱动持有 |
| 释放时机 | GPIO chip 注销时 | 驱动 remove() 或手动 gpiod_put() |
| 适用场景 | 无专属驱动的硬件引脚、早期上电时序 | 有驱动管理的外设 GPIO |
| 其他驱动能否申请 | ❌ 不能,返回 -EBUSY | ✅ 释放后可被重新申请 |
七、适用场景与注意事项
适合用 GPIO Hog 的场景
- 硬件复位引脚:USB Hub、以太网 PHY、音频 Codec 的复位脚,需要在驱动 probe 前已经就绪
- 电源使能引脚:上电后需立即有效的 EN 脚,且没有对应的 regulator 驱动
- 硬件模式配置引脚:只需要开机设置一次、保持固定状态的引脚
注意事项
- 不要用 GPIO Hog 代替 regulator 框架:如果引脚控制的是电源轨,应优先考虑
fixed-regulator+ regulator 框架,而不是简单用 Hog 强制拉高 - Hog 的引脚无法被其他驱动动态控制:Hog 的设计意图是”固定状态”,如果引脚需要在运行时被驱动程序动态读写,应使用普通 GPIO 申请
- 调试查看:可通过
/sys/kernel/debug/gpio查看哪些引脚被 hog,会显示line-name和方向/电平状态
# 查看 GPIO 状态,hog 的引脚会标注 [hogged]
cat /sys/kernel/debug/gpio
# 示例输出:
# gpio-7 (usb-hub-reset ) out hi [hogged]
# gpio-52 (eth-phy-reset ) out hi [hogged]
关联笔记
- 平台设备驱动模型 — GPIO 在平台驱动 probe 中的常规申请方式(
of_get_named_gpio、devm_gpio_request_one) - PWM驱动开发 — 同属 Linux 子系统分层架构,核心层 vs host 驱动的职责划分
延伸阅读
GPIO Hog 适合处理上电默认状态;运行期 GPIO 控制可继续参考 LED 和按键驱动。
- 返回嵌入式 Linux 学习路线,确认本文在完整知识结构中的位置。
- LED Platform 驱动开发
- Key Platform 驱动开发(中断与定时器消抖)




