某些驱动程序依赖于特定于板的静态 GPIO 引脚或引脚多路复用配置。在这些情况下,通常最好将 GPIO 配置详情保留在板驱动程序中,以确保相关驱动程序保持可移植性。这可以通过让板驱动程序将元数据和初始化步骤列表传递给 GPIO 驱动程序。相关示例请参见下文。
在开发板驱动程序中配置 GPIO 元数据
假设 SDMMC 驱动程序要求为引脚配置特定的 alt 功能和驱动器强度。为此,开发板驱动程序会创建一个 fuchsia.hardware.gpioimpl.InitStep
对象列表,指定要进行的 GPIO 协议调用以及进行这些调用的 GPIO 索引:
#include <fidl/fuchsia.hardware.gpioimpl/cpp/wire.h>
// Helper lambda to simplify the following code.
auto sdmmc_gpio = [&](uint64_t alt_function, uint64_t drive_strength_ua) {
return fuchsia_hardware_gpioimpl::wire::InitOptions::Builder(arena)
.alt_function(alt_function)
.drive_strength_ua(drive_strength_ua)
.Build();
};
const fuchsia_hardware_gpioimpl::wire::InitStep init_steps[] = {
{SDMMC_GPIO_0, sdmmc_gpio(SDMMC_GPIO_0_ALT_FUNCTION, 4000)},
{SDMMC_GPIO_1, sdmmc_gpio(SDMMC_GPIO_1_ALT_FUNCTION, 4000)},
{SDMMC_GPIO_2, sdmmc_gpio(SDMMC_GPIO_2_ALT_FUNCTION, 4000)},
{SDMMC_GPIO_3, sdmmc_gpio(SDMMC_GPIO_3_ALT_FUNCTION, 4000)},
{SDMMC_GPIO_4, sdmmc_gpio(SDMMC_GPIO_4_ALT_FUNCTION, 4000)},
{SDMMC_GPIO_5, sdmmc_gpio(SDMMC_GPIO_5_ALT_FUNCTION, 4000)},
};
然后,系统会将此列表作为元数据提供给 GPIO 驱动程序:
fuchsia_hardware_gpioimpl::wire::InitMetadata metadata;
metadata.steps = fidl::VectorView<fuchsia_hardware_gpioimpl::wire::InitStep>::FromExternal(
init_steps, std::size(init_steps));
fit::result encoded = fidl::Persist(metadata);
if (!encoded.is_ok()) {
return encoded.error_value().status();
}
const std::vector<fpbus::Metadata> gpio_metadata{
{{
.type = DEVICE_METADATA_GPIO_INIT_STEPS,
.data = std::move(encoded.value()),
}},
// Other metadata goes here.
};
const fpbus::Node gpio_dev = []() {
fpbus::Node dev = {};
dev.name() = "gpio";
dev.vid() = PDEV_VID_SOME_VENDOR;
dev.pid() = PDEV_PID_SOME_PRODUCT;
dev.did() = PDEV_DID_SOME_GPIO_DEVICE;
dev.mmio() = gpio_mmios;
dev.irq() = gpio_irqs;
dev.metadata() = gpio_metadata;
return dev;
}();
// Add the node here.
使用绑定规则创建 GPIO 配置的依赖项
现在,GPIO 驱动程序正在正确配置这些引脚,必须在绑定之前让 SDMMC 驱动程序依赖于此配置。这是通过在其板驱动程序绑定文件中向 SDMMC 设备添加一个额外的 fragment 来实现的:
using fuchsia.gpio;
// Other nodes go here.
node "gpio-init" {
fuchsia.BIND_INIT_STEP == fuchsia.gpio.BIND_INIT_STEP.GPIO;
fuchsia.BIND_GPIO_CONTROLLER = 1;
}
fuchsia.gpio.BIND_INIT_STEP.GPIO
设备在完成初始化步骤后由 GPIO 驱动程序添加。任意数量的子项都可以绑定到此设备,以确保在启动前已配置其 GPIO。
GPIO 驱动程序如何处理配置错误
如果 GPIO 驱动程序在处理初始化步骤时遇到错误,它会继续设置其余 GPIO,但不会添加 init 设备。这是为了确保将尽可能多的引脚置于已知状态,并且驱动程序不会尝试使用可能配置错误的引脚运行。同样,如果 GPIO 驱动程序没有或无法解析初始化元数据,则不会添加初始化设备。
推荐使用场景
在以下两种情况下,我们建议使用 GPIO 初始化步骤:
- 驱动程序需要特定于板级或平台的静态 GPIO 配置。
上拉/下拉、替代函数和驱动器强度设置通常因板级或平台而异,因此最好使用 GPIO init 在板驱动程序中对其进行配置。如果所有主板上的 GPIO 输出值不相同(或不要求),也建议采用这种方式设置输出值。
- 多个驱动程序依赖于一个 GPIO 的静态配置。
如果多个驱动程序依赖于一个 GPIO 的静态配置,则应通过 GPIO init 完成该配置。这样可以防止多个驱动程序对同一个 GPIO 进行可能存在冲突的调用。
GPIO 初始化步骤不应用于驱动程序将在运行时更改的任何配置。
GPIO 初始化选项
如需查看初始化选项的完整列表及其说明,请参阅 fuchsia.hardware.gpioimpl FIDL 规范。