2008年3月20日 星期四

Linux SPI subsystem (1)

目前進行中的項目是在 DaVinci 平台上開發 SPI 控制器驅動程式,不過由於手邊缺乏硬體平台可供測試的關係,現在仍然進度緩慢。不過這期間也研究了一下 Linux SPI 子系統,稍微有一些心得,來和各位分享一下。

SPI 是 Serial Peripheral Interface 的縮寫,它是一種串列式的 IO 介面,時脈約 1~ 70MHz,詳細資料可見 [1]。 DaVinci DM6446 上配備了一個 SPI 控制器,支援二個 chip select,時脈可達 33MHz。

Linux SPI 子系統將驅動程式分為三種類型:
  • SPI bus driver:
    主要目的為提供 API 給下層的 master driver 及上層的 protocol driver (稍後會提)來註冊,並傳送封包至下層的 driver。
  • SPI master driver:
    主要工作為初始化控制器,並負責對暫存器寫入以及中斷處理。
  • SPI protocol driver:
    主要為發送 SPI 訊息封包至所選擇的裝置。
從這樣的架構來看,bus driver 扮演了一個抽象層的角色,對上隱藏了硬體的細節,對下則隱藏了對特定裝置的通訊協定。是故 master driver 並不需要知道控制器接了什麼周邊,它只專注在如何操作控制器來將訊息封包送出;而 protocol driver 只需專心於和特定週邊的溝通,而不需了解要如何傳送訊息封包。

在子系統中,訊息封包的格式定義在 spi.h 的 spi_message 結構中。protocol driver 要傳送資料,只需填上 spi_message 結構相對應的欄位,並呼叫 spi_sync 以起始傳送。或者也可直接呼叫 spi_read/spi_write,參數則填入你的 buffer pointer 以及長度即可。

一般在嵌入式系統中,SPI 周邊多是直接固定在板子上,且硬體並無特別的方式可供偵測,因此我們需要在平台初始化時預先定義系統包含那些 SPI 周邊,而子系統也定義一個結構 spi_board_info 提供給開發者填入相對應的資訊,例如:

struct spi_board_info devices[] = {
     {
         .modalias = "mydevice",
         .max_speed_hz = 6000000,
         .bus_num = 0,
         .chip_select = 1,
         .mode = SPI_MODE_1,
     },
     {
         ......
     },
};

接著呼叫 spi_register_board_info 來註冊這些裝置。需要注意的是,modalias 欄位的值必須與 protocol driver 註冊的名字相同;bus driver 會以該值作為比對的依據。若需在執行時期註冊新的裝置,則可呼叫 spi_new_device 來加入。

關於 master driver 的部分留待下一篇來討論。

相關連結:
[1] Serial Peripheral Interface Bus
[2] TMS320DM644x DMSoC Serial Peripheral Interface (SPI) User's Guide

2 則留言:

kezeodsnx 提到...

借轉,如有冒犯,請告知,我會立刻刪除

Ramax 提到...

Hi kezeodsnx,

歡迎轉載,文章皆以 CC 授權