虚拟 GPIO 消费者

虚拟 GPIO 消费者模块允许用户实例化请求 GPIO 的虚拟设备,然后通过 debugfs 控制它们的行为。虚拟消费者设备可以从设备树或通过 configfs 实例化。

虚拟消费者使用面向驱动程序的 GPIO API,并允许使用用户空间驱动的自动化测试来覆盖它。GPIO 是使用 gpiod_get_array() 请求的,因此我们支持每个连接器 ID 多个 GPIO。

创建 GPIO 消费者

gpio-consumer 模块注册一个名为 'gpio-virtuser' 的 configfs 子系统。有关 configfs 文件系统的详细信息,请参阅 configfs 文档。

用户可以创建 configfs 组和项的层次结构,以及修改公开属性的值。一旦消费者被实例化,此层次结构将被转换为适当的设备属性。一般结构是

组: /config/gpio-virtuser

这是 gpio-consumer configfs 树的顶层目录。

组: /config/gpio-consumer/example-name

属性: /config/gpio-consumer/example-name/live

属性: /config/gpio-consumer/example-name/dev_name

这是一个表示 GPIO 消费者设备的目录。

只读 dev_name 属性公开设备在平台总线上出现在系统中的名称。这对于在 /sys/kernel/debug/gpio-virtuser/$dev_name 下查找关联的 debugfs 目录非常有用。

'live' 属性允许在完全配置设备后触发设备的实际创建。接受的值为:'1' 以启用虚拟设备,'0' 以禁用和拆除它。

创建 GPIO 查找表

用户可以在设备组下创建多个 configfs 组

组: /config/gpio-consumer/example-name/con_id

'con_id' 目录表示单个 GPIO 查找,其值映射到 gpiod_get() 函数的 'con_id' 参数。例如:con_id == 'reset' 映射到 reset-gpios 设备属性。

用户可以为每个查找分配多个 GPIO。每个 GPIO 都是 'con_id' 组下具有用户定义名称的子目录。

属性: /config/gpio-consumer/example-name/con_id/0/key

属性: /config/gpio-consumer/example-name/con_id/0/offset

属性: /config/gpio-consumer/example-name/con_id/0/drive

属性: /config/gpio-consumer/example-name/con_id/0/pull

属性: /config/gpio-consumer/example-name/con_id/0/active_low

属性: /config/gpio-consumer/example-name/con_id/0/transitory

这是一个描述 con_id-gpios 属性中单个 GPIO 的组。

对于使用 configfs 创建的虚拟消费者,我们使用机器查找表,因此此组可以被视为文件系统与 'struct gpiod_lookup' 中单个条目的字段之间的映射。

'key' 属性表示此 GPIO 所属的芯片的名称或 GPIO 线名称。这取决于 'offset' 属性的值:如果其值 >= 0,则 'key' 表示要查找的芯片的标签,而 'offset' 表示该芯片中线的偏移量。如果 'offset' < 0,则 'key' 表示线的名称。

其余属性映射到 GPIO 查找结构的 'flags' 字段。前两个将字符串值作为参数

``'drive'``: 'push-pull', 'open-drain', 'open-source' ``'pull'``: 'pull-up', 'pull-down', 'pull-disabled', 'as-is'

'active_low''transitory' 是布尔属性。

激活 GPIO 消费者

配置完成后,必须将 'live' 属性设置为 1 才能实例化消费者。可以将其设置回 0 以销毁虚拟设备。该模块将同步等待新的模拟设备成功探测,如果这种情况没有发生,写入 'live' 将导致错误。

设备树

虚拟 GPIO 消费者也可以在设备树中定义。兼容字符串必须是:"gpio-virtuser",并且至少有一个属性遵循标准化的 GPIO 模式。

定义虚拟 GPIO 消费者的设备树代码示例

gpio-virt-consumer {
    compatible = "gpio-virtuser";

    foo-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>, <&gpio1 2 0>;
    bar-gpios = <&gpio0 6 0>;
};

控制虚拟 GPIO 消费者

一旦设备激活,它将导出 debugfs 属性,用于控制 GPIO 数组以及每个请求的 GPIO 线。让我们考虑以下设备属性:foo-gpios = <&gpio0 0 0>, <&gpio0 4 0>;

将创建以下 debugfs 属性组

组: /sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo/

此组将包含整个 GPIO 数组的属性。

属性: /sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo/values

属性: /sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo/values_atomic

这两个属性都允许读取和设置 GPIO 值的数组。用户必须以字符串的形式传递数组中包含的确切数量的值,其中包含 0 和 1,分别表示非活动和活动的 GPIO 状态。在此示例中:echo 11 > values

values_atomic 属性的工作方式与 values 相同,但内核将在中断上下文中执行 GPIO 驱动程序回调。

组: /sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/

此组表示单个 GPIO,其中 $index 是其在数组中的偏移量。

属性: /sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/consumer

允许设置和读取 GPIO 线的消费者标签。

属性: /sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/debounce

允许设置和读取 GPIO 线的去抖动周期。

属性: /sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/direction

属性: /sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/direction_atomic

这两个属性允许设置 GPIO 线的方向。它们接受 “input” 和 “output” 作为值。原子变体在中断上下文中执行驱动程序回调。

属性: /sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/interrupts

如果在输入模式下请求该线,则向此属性写入 1 将使模块侦听 GPIO 上的边沿中断。写入 0 将禁用监视。读取此属性将返回当前注册的中断数(包括上升沿和下降沿)。

属性: /sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/value

属性: /sys/kernel/debug/gpio-virtuser/$dev_name/gpiod:foo:$index/value_atomic

这两个属性都允许读取和设置单个请求的 GPIO 线的数值。它们接受以下值:10