【问题标题】:How to use kernel GPIO descriptor interface如何使用内核 GPIO 描述符接口
【发布时间】:2019-02-09 22:34:20
【问题描述】:

我正在尝试开发一个简单的 Linux 内核模块,用于管理固定在 Raspberry Pi 的 GPIO 上的一堆传感器/执行器。
我需要的 GPIO 功能非常简单:获取/设置引脚值,接收 IRQ,...

在我的代码中,我有一个 misc_device,它实现了通常的 openreadwrite 和 打开操作。例如,在我的读取操作中,我想获取特定 GPIO 引脚的值(高/低)。

幸运的是,内核为此类 GPIO 操作提供了接口。实际上,根据官方GPIO doc 的说法,有两个接口:遗留接口,非常简单但已弃用,以及新的基于描述符的接口。
我想将后者用于我的项目,并且我了解如何实现我需要的所有东西,除了一件事:设备树的东西。
参考board.txt,在我可以调用 gpiod_get_index() 和稍后 gpiod_get_value() 之前,首先我需要像这样设置设备树:

foo_device {
    compatible = "acme,foo";
    ...
    led-gpios = <&gpio 15 GPIO_ACTIVE_HIGH>, /* red */
            <&gpio 16 GPIO_ACTIVE_HIGH>, /* green */
            <&gpio 17 GPIO_ACTIVE_HIGH>; /* blue */

    power-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
};

但是,我完全不知道将那段代码放在哪里,也不知道我是否真的需要它。请注意,我有一个看起来像这样的杂项设备,其中 aaa_fops 包含读取操作:

static struct miscdevice aaa = {
    MISC_DYNAMIC_MINOR, "aaa", &aaa_fops
};

使用不推荐使用的旧接口,我的问题将得到解决,因为它不需要弄乱设备树,但如果不太复杂,我仍然想使用新接口。

我已阅读大量文档,包括官方和非官方文档,但无法为我的问题找到一个直接而简单的答案。我试图在内核源代码中找到答案,尤其是在驱动程序部分,但只是迷失在一个复杂而混乱的山谷中。 缺乏关于内核的工作、最小示例 (WME) 显着减慢了我的学习过程,这只是我对它的看法。
您能否给我一个简单设备(最好是杂项)的 WME,其阅读() 操作获取引脚的值,使用新的 GPIO 接口?

如果您需要有关我的代码的更多详细信息,请询问。提前致谢!

注意 1:我知道我的大部分工作都可以在用户空间而不是内核空间中完成;我的项目仅用于教育目的,学习内核。

注意 2:我选择 misc 设备是因为它很简单,但如果需要,我可以切换到 char 设备。

【问题讨论】:

    标签: linux-kernel raspberry-pi linux-device-driver kernel-module gpio


    【解决方案1】:

    ...首先我需要像这样设置设备树:
    ...
    但是,我完全不知道将那段代码放在哪里

    设备树节点和属性不应称为“代码”
    大多数设备都连接到外围总线,因此设备节点通常是外围总线节点的子节点。


    你能给我一个简单设备的 WME

    您可以在内核源代码中找到大量基于描述符的 GPIO 使用示例。
    由于文档将 GPIO 描述符指定为名为 &lt;function&gt;-gpios,对字符串“\-gpios”的目录 arch/arm/boot/dts 的 grep 报告了许多可能的示例。
    特别是有

    ./bcm2835-rpi-b.dts:    hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>;
    

    hpd-gpios 属性属于 bcm283x.dtsi 中定义的 hdmi 基节点,由 gpu/drm/vc4/vc4_hdmi.c 驱动程序使用.

    /* General HDMI hardware state. */
    struct vc4_hdmi {
            ... 
            int hpd_gpio;
            ...
    };
    
    
    static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
    {
        ...
            /* Only use the GPIO HPD pin if present in the DT, otherwise
             * we'll use the HDMI core's register.
             */
            if (of_find_property(dev->of_node, "hpd-gpios", &value)) {
                    ...
    
                    hdmi->hpd_gpio = of_get_named_gpio_flags(dev->of_node,
                                                             "hpd-gpios", 0,
                                                             &hpd_gpio_flags);
                    if (hdmi->hpd_gpio < 0) {
                            ret = hdmi->hpd_gpio;
                            goto err_unprepare_hsm;
                    }
                    ...
            }
    

    如果hpd-gpios 属性已定义/找到并从板的设备树中成功检索,则驱动程序的结构成员 hpd_gpio 保存 GPIO 引脚号。
    由于此驱动程序不调用 devm_gpio_request(),因此框架显然为驱动程序分配了 GPIO 引脚。


    然后驱动程序可以访问 GPIO 引脚。

    static enum drm_connector_status
    vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
    {
        ...
            if (vc4->hdmi->hpd_gpio) {
                    if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^
                        vc4->hdmi->hpd_active_low)
                            return connector_status_connected;
                    else
                            return connector_status_disconnected;
            }
    

    【讨论】:

      猜你喜欢
      • 2016-08-09
      • 2012-05-09
      • 2019-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多