我正在尝试开发一个简单的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设备。
...首先,我需要以某种方式设置设备树: ... 但是,我绝对不知道在哪里放一大堆代码
设备树节点和属性不应称为“代码”。 大多数设备连接到外围总线,因此设备节点通常是外围总线节点的子节点。
你能给我一个简单设备的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;
}