在Linux内核的GPIO子系统中,desc_to_gpio
函数用于将GPIO描述符(gpio_desc
)转换为全局唯一的GPIO编号。以下是该函数的详细解析:
1. 函数原型
int desc_to_gpio(const struct gpio_desc *desc);
- 参数:
desc
(指向gpio_desc
的指针) - 返回值:
- 成功时返回全局GPIO编号(整数,如105)。
- 失败时返回负数错误码(如
-EINVAL
表示无效描述符)。
2. 核心作用
- 编号转换:将抽象的
gpio_desc
转换为全局GPIO编号,便于:- 调试时输出人类可读的编号。
- 与遗留代码或某些子系统(如pinctrl)交互。
- 内部实现:
static inline int desc_to_gpio(const struct gpio_desc *desc) { if (!desc || !desc->chip || !desc->chip->base) return -EINVAL; return desc->chip->base + desc->offset; }
- 通过
desc->chip->base
(控制器起始编号)和desc->offset
(引脚在控制器内的偏移量)计算全局编号。
- 通过
3. 典型使用场景
(1) 调试输出
struct gpio_desc *led_gpio = gpiod_get(dev, "led", GPIOD_OUT_HIGH);
if (!IS_ERR(led_gpio)) {
int gpio_num = desc_to_gpio(led_gpio);
dev_info(dev, "LED GPIO number: %d\n", gpio_num);
}
(2) 与pinctrl子系统交互
// 获取GPIO编号后配置引脚复用
int gpio = desc_to_gpio(led_gpio);
if (gpio >= 0) {
pinctrl_gpio_direction_output(pmx, gpio);
}
4. 关键注意事项
(1) 避免硬编码全局编号
- 风险:全局编号是动态分配的(由内核根据
gpio_chip
注册顺序决定),不同系统或不同启动时可能不同。 - 正确做法:始终通过
gpio_desc
操作GPIO,仅在必要时(如调试)使用desc_to_gpio
。
(2) 错误处理
- 检查返回值:
int gpio_num = desc_to_gpio(invalid_desc); if (gpio_num < 0) { dev_err(dev, "Invalid GPIO descriptor\n"); }
(3) 性能考量
- 直接使用描述符更高效:
gpio_desc
已包含所有必要信息,频繁调用desc_to_gpio
可能增加开销。
5. 反向操作:gpio_to_desc
- 函数原型:
struct gpio_desc *gpio_to_desc(unsigned gpio);
- 作用:将全局GPIO编号转换为
gpio_desc
,用于安全操作引脚。 - 示例:
struct gpio_desc *desc = gpio_to_desc(105); if (!IS_ERR(desc)) { gpiod_set_value(desc, 1); }
6. 总结
函数 | 方向 | 作用 | 典型场景 |
---|---|---|---|
desc_to_gpio | 描述符 → 编号 | 获取全局GPIO编号(调试/兼容性) | 日志输出、遗留代码交互 |
gpio_to_desc | 编号 → 描述符 | 安全操作GPIO(推荐方式) | 驱动主体逻辑 |
最佳实践:
- 优先使用
gpio_desc
进行GPIO操作,避免直接操作全局编号。 - 仅在必要时(如调试)使用
desc_to_gpio
,并严格处理错误。