当前位置: 首页 > news >正文

linux gpio errno EBUSY问题举例分析

1,异常场景

在适配点灯功能的时候,测试发现🈶下面的报错dmesg 查看

# 加载第一个驱动
[   12.345678] gpio-occupier gpio-occupier: Successfully requested and occupied GPIO 503# 加载第二个驱动,失败
[   12.567890] gpio-requester gpio-requester: CRITICAL: Failed to request GPIO 503, err -17 (EBUSY)
[   12.567895] platform gpio-requester: Driver gpio-requester probe failed with error -17

    2,代码分析

    驱动 A: gpio_occupier.c (先占用 GPIO)

    这个驱动在加载时会申请并占用 GPIO 503。

    #include <linux/module.h>
    #include <linux/platform_device.h>
    #include <linux/gpio.h>
    #include <linux/of.h>#define OCCUPIER_GPIO 503static int gpio_occupier_probe(struct platform_device *pdev)
    {int ret;// 申请 GPIO 503,并设置为输出高电平,标签为 "gpio-occupier"ret = devm_gpio_request_one(&pdev->dev, OCCUPIER_GPIO, GPIOF_OUT_INIT_HIGH, "gpio-occupier");if (ret < 0) {dev_err(&pdev->dev, "Failed to request GPIO %d\n", OCCUPIER_GPIO);return ret;}dev_info(&pdev->dev, "Successfully requested and occupied GPIO %d\n", OCCUPIER_GPIO);return 0;
    }static const struct of_device_id occupier_of_match[] = {{ .compatible = "my-vendor,gpio-occupier", {} },{}
    };
    MODULE_DEVICE_TABLE(of, occupier_of_match);static struct platform_driver gpio_occupier_driver = {.probe = gpio_occupier_probe,.driver = {.name = "gpio-occupier",.of_match_table = occupier_of_match,},
    };
    module_platform_driver(gpio_occupier_driver);MODULE_LICENSE("GPL");
    MODULE_AUTHOR("AI Assistant");
    MODULE_DESCRIPTION("A driver to occupy a GPIO for demonstration");
    

    驱动 B: gpio_requester.c (后申请,会失败)

    这个驱动尝试申请同一个 GPIO 503,将会失败。

    #include <linux/module.h>
    #include <linux/platform_device.h>
    #include <linux/gpio.h>
    #include <linux/of.h>#define REQUESTER_GPIO 503 // 与驱动 A 的 GPIO 相同static int gpio_requester_probe(struct platform_device *pdev)
    {int ret;// 尝试申请已经被占用的 GPIO 503,标签为 "gpio-requester"ret = devm_gpio_request_one(&pdev->dev, REQUESTER_GPIO, GPIOF_OUT_INIT_LOW, "gpio-requester");if (ret < 0) {// 这里会打印错误信息,ret 的值将是 -17dev_err(&pdev->dev, "CRITICAL: Failed to request GPIO %d, err %d (EBUSY)\n", REQUESTER_GPIO, ret);return ret;}dev_info(&pdev->dev, "Successfully requested GPIO %d\n", REQUESTER_GPIO);return 0;
    }static const struct of_device_id requester_of_match[] = {{ .compatible = "my-vendor,gpio-requester", {} },{}
    };
    MODULE_DEVICE_TABLE(of, requester_of_match);static struct platform_driver gpio_requester_driver = {.probe = gpio_requester_probe,.driver = {.name = "gpio-requester",.of_match_table = requester_of_match,},
    };
    module_platform_driver(gpio_requester_driver);MODULE_LICENSE("GPL");
    MODULE_AUTHOR("AI Assistant");
    MODULE_DESCRIPTION("A driver to demonstrate a failed GPIO request");
    

    3. 异常日志

    日志分析:

    • err -17 就是 EBUSY 的错误码。
    • 日志明确指出了是哪个驱动 (gpio-requester) 在申请哪个 GPIO (503) 时失败了。
    • Driver ... probe failed with error -17 表明因为 probe 函数返回了错误,整个驱动的加载都失败了。

     查看 sys/kernel/debug/gpio 的分析过程

    这是定位 EBUSY 问题的最关键、最直接的步骤。

    第 1 步:确保 debugfs 已挂载

    # 检查是否已挂载
    mount | grep debugfs# 如果没有输出,则手动挂载
    sudo mount -t debugfs none /sys/kernel/debug
    

    第 2 步:查看 GPIO 全局状态

    cat /sys/kernel/debug/gpio
    

    第 3 步:分析输出

    gpiochip0: GPIOs 0-511, parent: platform/10000000.pinctrl, 10000000.pinctrl:gpio-493 ( |cd ) in hi IRQ...gpio-503 ( |gpio-occupier ) out hi  <-- 关键信息在这里!...gpiochip1: GPIOs 512-1023, parent: platform/20000000.pinctrl, 20000000.pinctrl:...
    

    分析过程:这个标签 gpio-occupier 和我们第一个驱动的标签完全一致!这直接证明了 GPIO 503 确实被 gpio-occupier 驱动占用了。

    4,如何解决gpio复用的问题

    1.1 常见原因

    • 引脚未配置为GPIO功能:pinctrl子系统未将引脚复用功能设为GPIO,仍为I2C/SPI/UART等。
    • 引脚被其他外设占用:设备树中多个节点引用同一引脚,或驱动加载顺序导致冲突。
    • 驱动未正确引用pinctrl状态:设备节点未正确关联pinctrl配置。

    1.2 调试命令

    cat /sys/kernel/debug/gpio
    

    如果目标GPIO未显示或标签异常,说明未被正确配置为GPIO。


    1.3 设备树配置(关键步骤)

    1.3.1 定义pinctrl节点

    在设备树中,为GPIO功能创建专用pinctrl配置节点,确保 function 属性设为 gpio(或平台等效宏):

    &pio {gpio_func: gpio_func {pins_cmd_dat {pins = <PINMUX_GPIO84__FUNC_GPIO84>; // 示例:GPIO84bias-pull-up;                       // 上拉(可选)output-high;                        // 默认输出高(可选)};};
    };
    

    说明

    • PINMUX_GPIO84__FUNC_GPIO84 为平台提供的宏,表示将引脚配置为GPIO功能89。
    • 不同SoC的宏名不同,需查阅芯片手册或内核头文件(如 imx6ul-pinfunc.h)3。

    1.3.2 关联设备节点

    在目标设备节点中引用pinctrl配置:

    my_device {compatible = "my-vendor,my-device";pinctrl-names = "default";pinctrl-0 = <&gpio_func>; // 引用GPIO功能配置gpios = <&gpio1 84 GPIO_ACTIVE_HIGH>; // GPIO属性status = "okay";
    };
    

    注意

    • pinctrl-0 必须指向GPIO功能的pinctrl节点312。
    • 确保无其他节点(如I2C/SPI节点)复用同一引脚。

    1.4. 驱动代码调整

    1.4.1 自动处理(推荐)

    如果设备树正确配置,pinctrl子系统会在驱动probe前自动应用GPIO配置,无需额外代码69。

    1.4.2 手动切换(必要时)

    若需动态切换,可在驱动中显式获取并设置pinctrl状态:

    #include <linux/pinctrl/consumer.h>struct pinctrl *pinctrl;
    struct pinctrl_state *gpio_state;// 获取pinctrl句柄
    pinctrl = devm_pinctrl_get(&pdev->dev);
    if (IS_ERR(pinctrl)) {dev_err(&pdev->dev, "Failed to get pinctrl\n");return PTR_ERR(pinctrl);
    }// 查找GPIO状态
    gpio_state = pinctrl_lookup_state(pinctrl, "default");
    if (IS_ERR(gpio_state)) {dev_err(&pdev->dev, "Failed to lookup GPIO state\n");return PTR_ERR(gpio_state);
    }// 切换到GPIO状态
    ret = pinctrl_select_state(pinctrl, gpio_state);
    if (ret < 0) {dev_err(&pdev->dev, "Failed to select GPIO state\n");return ret;
    }// 现在可以安全申请GPIO
    ret = devm_gpio_request_one(&pdev->dev, gpio_num, GPIOF_OUT_INIT_LOW, "my-gpio");
    

    说明

    • 适用于需在运行时切换引脚功能的场景(如休眠/唤醒)914。
    • 多数情况下,设备树配置已足够,无需手动干预。

    1.5. 验证与调试

    1.5.1 检查pinctrl状态

    # 查看当前pinctrl配置(需内核支持)
    cat /sys/kernel/debug/pinctrl/*/pins
    

    确认目标引脚的 function 为 gpio

    1.5.2 检查GPIO占用

    cat /sys/kernel/debug/gpio | grep "gpio-84"
    

    应显示类似:

    gpio-84  ( |my-gpio ) out lo
    

    1.5.3 动态调试

    启用gpiolib调试日志:

    echo 'file gpiolib.c +p' > /sys/kernel/debug/dynamic_debug/control
    dmesg | grep -i "gpio_request"
    

    可查看详细的申请失败原因。


    1.6. 常见问题与解决方案

    问题现象可能原因解决方案
    EBUSY 且debugfs无显示引脚未配置为GPIO检查pinctrl节点的 function 属性是否为 gpio89。
    EBUSY 且显示其他标签引脚被其他外设占用修改设备树,移除冲突节点的引脚引用。
    驱动加载顺序问题GPIO驱动先于pinctrl加载调整设备树节点顺序或确保pinctrl驱动优先加载。

    1.7. 完整示例

    1.7.1 设备树配置

    &pio {my_gpio: my_gpio {pins = <PINMUX_GPIO84__FUNC_GPIO84>;bias-pull-up;output-low;};
    };my_device {compatible = "my-vendor,my-device";pinctrl-names = "default";pinctrl-0 = <&my_gpio>;gpios = <&gpio1 84 GPIO_ACTIVE_HIGH>;status = "okay";
    };
    

    1.7.2 驱动代码

    ret = devm_gpio_request_one(&pdev->dev, 84, GPIOF_OUT_INIT_LOW, "my-gpio");
    if (ret < 0) {dev_err(&pdev->dev, "GPIO request failed: %d\n", ret);return ret;
    }

     

    http://www.dtcms.com/a/545576.html

    相关文章:

  • 如何在 macOS 中清理 Homebrew 软件包 ?
  • 手机网站设计立找亿企邦湖南长沙房价2023年最新房价
  • 如何选择徐州网站开发wordpress新建页面位置
  • nestjs引篇
  • apmserv 设置网站目录yy头像在线制作网站
  • 基于YOLO+多模态大模型+人脸识别+视频检索的智慧公安综合研判平台(vue+flask+AI算法)
  • 二手车网站程序德阳网站建设 选哪家好
  • 极智算服务器用的还是自己的网络吗安全吗
  • Jenkins vs GitLab CI/CD vs Arbess,CI/CD工具一文纵评
  • 机器学习—— 回归分析之如何建立回归模型
  • MySQL中SUBSTRING_INDEX函数作用
  • 网站设计评级杭州网站搜索排名
  • 2.1 AI与大模型介绍
  • 厦门网站建设阿里流量型网站 cms
  • 【笔试真题】- 科大讯飞研发岗-2025.09.27
  • 20.15 多模态系统测试实战:跨模态对齐实现98%准确率的关键方案
  • GXDE 2025 Edition RC 开始测试
  • 网站设计标注图怎么做广东阳江发布最新消息
  • Java中使用Collator实现对象List按照中文姓名属性进行A-Z的排序实现
  • Oracle AWR 报告中的SQL来自哪儿?
  • 企业网站建设的作用创意设计之都
  • 蓝牙钥匙 第1次 蓝牙技术演进全景透视:从1.0到5.3,物联网时代的互联基石
  • Java、Python、C# 和 C++ 在函数定义语法上的主要区别
  • 安装网站程序报价单模板英文
  • mmcv的安装
  • OpenCV(十五):绘制矩形和圆
  • 网站建设基本流程视频关于动漫制作专业
  • 【React】节流会在react内失效??
  • ARM SMMU v3架构规范中文版
  • 北京58网站建设云南手工活外发加工网