GPIO 聚合器

GPIO 聚合器提供了一种聚合 GPIO 并将其作为新的 gpio_chip 公开的机制。这支持以下用例。

使用 Sysfs 聚合 GPIO

GPIO 控制器使用 /dev/gpiochip* 字符设备导出到用户空间。 对这些设备的访问控制由标准的 UNIX 文件系统权限提供,以全有或全无为基础:要么用户可以访问 GPIO 控制器,要么不能访问。

GPIO 聚合器通过将一组或多个 GPIO 聚合到一个新的 gpio_chip 中来提供对 GPIO 的访问控制,该 gpio_chip 可以使用标准的 UNIX 文件所有权和权限分配给组或用户。此外,这简化并加强了将 GPIO 导出到虚拟机,因为 VM 可以只获取完整的 GPIO 控制器,不再需要关心要获取哪些 GPIO 以及不获取哪些 GPIO,从而减少了攻击面。

聚合的 GPIO 控制器通过写入 sysfs 中的只写属性文件来实例化和销毁。

/sys/bus/platform/drivers/gpio-aggregator/

“new_device” ...

用户空间可以要求内核实例化一个聚合的 GPIO 控制器,方法是写入一个字符串,描述要聚合到 “new_device” 文件中的 GPIO,使用以下格式

[<gpioA>] [<gpiochipB> <offsets>] ...

哪里

“<gpioA>” ...

是 GPIO 线名称,

“<gpiochipB>” ...

是一个 GPIO 芯片标签,并且

“<offsets>” ...

是由破折号分隔的 GPIO 偏移量和/或 GPIO 偏移量范围的逗号分隔列表。

示例:通过将 “e6052000.gpio” 的 GPIO 线 19 和 “e6050000.gpio” 的 GPIO 线 20-21 聚合到一个新的 gpio_chip 中来实例化一个新的 GPIO 聚合器

$ echo 'e6052000.gpio 19 e6050000.gpio 20-21' > new_device
“delete_device” ...

用户空间可以要求内核在使用后通过将其设备名称写入 “delete_device” 文件来销毁聚合的 GPIO 控制器。

示例:销毁先前创建的聚合 GPIO 控制器,假设为 “gpio-aggregator.0”

$ echo gpio-aggregator.0 > delete_device

使用 Configfs 聚合 GPIO

组: /config/gpio-aggregator

这是 gpio-aggregator configfs 树的根目录。

组: /config/gpio-aggregator/<example-name>

此目录表示 GPIO 聚合器设备。您可以为 <example-name> 分配任何名称(例如 agg0),除了以 _sysfs 前缀开头的名称,这些名称保留用于通过 Sysfs 创建的设备自动生成的 configfs 条目。

属性: /config/gpio-aggregator/<example-name>/live

live 属性允许在完全配置设备后触发设备的实际创建。接受的值是

  • 1, yes, true : 启用虚拟设备

  • 0, no, false : 禁用虚拟设备

属性: /config/gpio-aggregator/<example-name>/dev_name

只读 dev_name 属性公开设备在平台上出现在系统中的名称(例如 gpio-aggregator.0)。这对于识别新创建的聚合器的字符设备很有用。如果它是 gpio-aggregator.0,则 /sys/devices/platform/gpio-aggregator.0/gpiochipX 路径告诉您 GPIO 设备 ID 是 X

您必须为您要实例化的每个虚拟行创建子目录,精确命名为 line0, line1, ..., lineY,当您要实例化 Y+1 (Y >= 0) 行时。通过将 live 设置为 1,在激活设备之前配置所有行。

组: /config/gpio-aggregator/<example-name>/<lineY>/

此目录表示要包含在聚合器中的 GPIO 线。

属性: /config/gpio-aggregator/<example-name>/<lineY>/key

属性: /config/gpio-aggregator/<example-name>/<lineY>/offset

创建 <lineY> 目录后的默认值是

  • key : <empty>

  • offset : -1

key 必须始终显式配置,而 offset 取决于情况。每个 <lineY> 存在两种配置模式

(a). 对于通过 GPIO 线名称查找

  • key 设置为线名称。

  • 确保 offset 保持 -1(默认值)。

(b). 对于通过 GPIO 芯片名称和芯片内的线偏移量查找

  • key 设置为芯片名称。

  • offset 设置为线偏移量 (0 <= offset < 65535)。

属性: /config/gpio-aggregator/<example-name>/<lineY>/name

name 属性为 lineY 设置自定义名称。如果未设置,则该行将保持未命名。

配置完成后,必须将 'live' 属性设置为 1,以便实例化聚合器设备。可以将其设置回 0 以销毁虚拟设备。该模块将同步等待新的聚合器设备成功探测,如果未发生这种情况,写入 'live' 将导致错误。这与使用 sysfs new_device 接口创建它时的行为不同。

注意

对于通过 Sysfs 创建的聚合器,configfs 条目是自动生成的,并显示为 /config/gpio-aggregator/_sysfs.<N>/。您无法使用 mkdir(2)/rmdir(2) 添加或删除行目录。要修改行,您必须使用 “delete_device” 接口来拆除现有设备并从头开始重新配置它。但是,您仍然可以使用 live 属性切换聚合器,并在手动将 live 设置为 0 时调整每行的 key, offsetname 属性(即,它不等待延迟探测)。

示例配置命令

# Create a directory for an aggregator device
$ mkdir /sys/kernel/config/gpio-aggregator/agg0

# Configure each line
$ mkdir /sys/kernel/config/gpio-aggregator/agg0/line0
$ echo gpiochip0 > /sys/kernel/config/gpio-aggregator/agg0/line0/key
$ echo 6         > /sys/kernel/config/gpio-aggregator/agg0/line0/offset
$ echo test0     > /sys/kernel/config/gpio-aggregator/agg0/line0/name
$ mkdir /sys/kernel/config/gpio-aggregator/agg0/line1
$ echo gpiochip0 > /sys/kernel/config/gpio-aggregator/agg0/line1/key
$ echo 7         > /sys/kernel/config/gpio-aggregator/agg0/line1/offset
$ echo test1     > /sys/kernel/config/gpio-aggregator/agg0/line1/name

# Activate the aggregator device
$ echo 1         > /sys/kernel/config/gpio-aggregator/agg0/live

通用 GPIO 驱动程序

GPIO 聚合器也可以用作 DT 中描述的简单 GPIO 操作设备的通用驱动程序,而无需专用的内核驱动程序。这在工业控制中很有用,并且与例如 spidev 非常相似,它允许用户从用户空间与 SPI 设备通信。

将设备绑定到 GPIO 聚合器可以通过修改 gpio-aggregator 驱动程序或写入 Sysfs 中的 “driver_override” 文件来执行。

示例:如果 “door” 是 DT 中描述的 GPIO 操作设备,使用其自己的兼容值

door {
        compatible = "myvendor,mydoor";

        gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>,
                <&gpio2 20 GPIO_ACTIVE_LOW>;
        gpio-line-names = "open", "lock";
};

可以通过以下任一方式将其绑定到 GPIO 聚合器

  1. 将其兼容值添加到 gpio_aggregator_dt_ids[],

  2. 使用 “driver_override” 手动绑定

$ echo gpio-aggregator > /sys/bus/platform/devices/door/driver_override
$ echo door > /sys/bus/platform/drivers/gpio-aggregator/bind

之后,已创建一个新的 gpiochip “door”

$ gpioinfo door
gpiochip12 - 2 lines:
        line   0:       "open"       unused   input  active-high
        line   1:       "lock"       unused   input  active-high