如何使用内核GPIO描述符接口

问题描述 投票:0回答:1

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

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

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

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>;
};

但是,我绝对不知道在哪里放一大堆代码,也不知道我真的需要它。请注意,我有一个看起来像这样的misc设备,其中aaa_fops包含读取操作:

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

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

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

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

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

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

linux-kernel raspberry-pi linux-device-driver kernel-module gpio
1个回答
0
投票

...首先,我需要以某种方式设置设备树: ... 但是,我绝对不知道在哪里放一大堆代码

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


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

您可以在内核源代码中找到许多基于描述符的GPIO用法示例。 由于文档将GPIO描述符指定为名为<function>-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属性并从主板的DeviceTree中成功检索,则驱动程序的结构成员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;
        }
© www.soinside.com 2019 - 2024. All rights reserved.