GPIO 初始化

部分驅動程式會依賴靜態 GPIO 接腳或接腳多工器設定,這些設定會因主機板而異。在這些情況下,通常建議將 GPIO 設定詳細資料保留在主機板驅動程式庫中,確保依附元件驅動程式仍可攜。方法是讓主機板驅動程式庫將中繼資料和初始化步驟清單傳遞給 GPIO 驅動程式庫。請參閱下方的範例。

在主機板驅動程式庫中設定 GPIO 中繼資料

假設 SDMMC 驅動程式需要使用特定替代函式和驅動強度設定接腳。為此,主機板驅動程式庫會建立 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 裝置:

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

GPIO 驅動程式庫會在完成初始化步驟的處理作業後,新增 fuchsia.gpio.BIND_INIT_STEP.GPIO 裝置。多名孩子可以將裝置與自己的帳戶繫結,確保 GPIO 已設定完成,再開始使用。

GPIO 驅動程式庫如何處理設定錯誤

如果 GPIO 驅動程式庫在處理初始化步驟時發生錯誤,會繼續設定其餘 GPIO,但不會新增 init 裝置。這樣可確保盡可能將接腳置於已知狀態,且驅動程式不會嘗試使用可能設定錯誤的接腳。同樣地,如果 GPIO 驅動程式沒有或無法剖析初始化中繼資料,就不會新增任何初始化裝置。

建議在以下兩種情況使用 GPIO 初始化步驟:

  • 驅動程式需要靜態板或平台專屬的 GPIO 設定。

上拉/下拉、替代函式和驅動強度設定通常是板或平台專屬,因此建議在板驅動程式庫中使用 GPIO init 進行設定。如果所有開發板上的 GPIO 輸出值不同 (或不需要相同),也建議採用這種方式設定。

  • 多個驅動程式依賴單一 GPIO 的靜態設定。

如果多個驅動程式依賴一個 GPIO 的靜態設定,則該設定應由 GPIO init 執行。這樣一來,多個驅動程式就不必對單一 GPIO 進行可能發生衝突的呼叫。

如果驅動程式庫會在執行階段變更設定,請勿使用 GPIO 初始化步驟。

GPIO 初始化選項

如需完整的初始化選項清單和說明,請參閱 fuchsia.hardware.pinimpl FIDL 規格。