SPI(1)——Documentation/spi/spi_summary.txt翻譯

Linux內核SPI支持概述
====================================linux

02 - 2012編程

1.什麼是SPI?
------------
  "Serial Peripheral Interface" (SPI) 是同步四線串行接口,用於將微控制器鏈接到傳感器,存儲器和外圍設備的鏈路。這是一個簡單的「事實上的」標準,並不足以得到標準化機構。 SPI使用主/從配置安全

  三條信號線中有一個是時鐘(SCK,一般在10 MHz的數量級),以及具備"Master Out, Slave In" (MOSI) 或 "Master In, Slave Out" (MISO) 信號的並行數據線。(也使用其餘名稱。)有四種時鐘模式能夠交換數據; mode-0 和mode-3 是最經常使用的。 每一個時鐘週期將數據移出並移入數據; 除非有數據位須要移位,不然時鐘不會輸出。
但並不是全部數據位都被使用; 並不是每一個協議都使用這些全雙工功能。數據結構

  SPI主控器使用第四條 "chip select" 線來激活給定的SPI從器件,所以這三條信號線(CLK,DI,DO)能夠並聯鏈接到多個芯片。全部SPI從設備都要支持芯片選擇功能; 它們一般是低電平有效信號,爲從設備'x'的片選線指定名字爲nCSx(例如nCS0)。某些設備有其餘信號,一般包括對主設備的中斷。併發

  與 USB 或 SMBus 等串行總線不一樣,即便 SPI 從機功能的低級協議一般也不能在供應商之間互操做(SPI內存芯片等商品除外)。app

    - SPI可用於請求/響應式設備協議,如觸摸屏傳感器和存儲器芯片。框架

    - 它也能夠用於在任一單方向傳輸數據(半雙工)或二者雙向同時(全雙工)傳輸數據。異步

    - 某些設備可能使用8位字。 其它設備可能使用不一樣的字長,例如12位或20位數字樣本的流。async

    - 一個字節一般首先發送最高有效位(MSB),但也有時最早發送的是最低有效位(LSB)。函數

    - 有時SPI用於環形設備,如移位寄存器。

  一樣,SPI從設備不多支持任何類型的自動發現/枚舉協議。 從給定的SPI主設備可訪問的從設備樹一般是使用配置表手動設置的。

  SPI只是這種四線協議使用的名稱之一,而且大多數控制器處理「MicroWire」(將其視爲半雙工SPI,用於請求/響應協議),SSP(「同步串行協議」) ,PSP(「可編程串行協議」)和其餘相關協議是沒有問題的。

  一些芯片經過組合MOSI和MISO消除信號線,並在硬件級別將其自身限制爲半雙工。 事實上,一些SPI芯片將這種信號模式做爲捆紮選項。 這些可使用與SPI相同的編程接口進行訪問,但固然它們不能處理全雙工傳輸。 您可能會發現此類芯片被描述爲使用「三線」:SCK,data,nCSx。(該data信號線有時稱爲MOMI或SISO。)

  微控制器一般支持做爲SPI協議的主端和從端。 本文檔(和Linux)支持SPI交互的主端和從端。

 

2. Who uses it? On what kinds of systems?
---------------------------------------
  使用SPI的Linux開發人員可能正在爲嵌入式系統板編寫設備驅動程序。SPI用於控制外部芯片,它也是每一個MMC或SD存儲卡支持的協議。(早期的「DataFlash」卡,使用相同的鏈接器和卡形狀MMC卡,僅支持SPI。)某些PC硬件使用SPI閃存做爲BIOS代碼。

  SPI從芯片的範圍從用於模擬傳感器和編解碼器的數字/模擬轉換器到存儲器,再到USB控制器或以太網適配器等外設; 和更多。

  大多數使用SPI的系統都會在主板上集成一些設備。 有些提供擴展鏈接器上的SPI連接; 在沒有專用SPI控制器的狀況下,GPIO引腳可用於建立低速「bitbanging」適配器(就是經過GPIO來模擬SPI)。 不多有系統會 「熱插拔」 SPI控制器; 使用SPI的緣由集中在低成本和簡單的操做上,若是對動態重配置看的很重要,USB一般是更合適的低引腳數的外設總線。

  許多能夠運行Linux的微控制器將一個或多個I/O接口與SPI模式集成在一塊兒。 在支持SPI的狀況下,他們可使用MMC或SD卡而無需專用的 MMC / SD / SDIO 控制器。

 

3. 我困惑了。 這四種SPI「時鐘模式」是什麼?
-----------------------------------------------------
  這裏很容易混淆,你找到的供應商文檔不必定有用。兩個模式位組成了這四種模式:

    - CPOL表示初始時鐘極性。 CPOL = 0表示時鐘從低電平開始,所以第一個(前沿)邊沿上升,第二個(後沿)邊沿降低。 CPOL = 1表示時鐘從高電平開始,所以第一個(前沿)邊沿降低。

    - CPHA表示用於採樣數據的時鐘相位; CPHA = 0表示前沿的樣本,CPHA = 1表示後沿。

  因爲信號須要在採樣以前穩定,所以CPHA = 0意味着其數據在第一個時鐘沿以前寫入半個時鐘。 chipselect 可能使它變得可用。

  芯片規格並不老是說「使用SPI模式X」,但它們的時序圖將使CPOL和CPHA模式清晰。

  在SPI模式編號中,CPOL是高位,CPHA是低位。 所以,當芯片的時序圖顯示時鐘從低電平開始(CPOL = 0)而且數據在後沿時鐘邊沿(CPHA = 1)期間穩定採樣時,那就是SPI模式1。

  請注意,只要chipselect有效,時鐘模式就會相關(同一SPI總線上鏈接的不一樣的從設備的SPI的模式可能不一樣,由於SPI主控制其的SPI模式應該也須要跟誰這片選線而變化)。 所以,主器器必須在選擇從器件以前將時鐘設置爲無效,而且從器件能夠經過在其選擇線變爲有效時對時鐘電平進行採樣來告知所選極性。 這就是爲何許多設備支持例如模式0和3的緣由:它們不關心極性,而且老是在時鐘上升沿上移入/移出數據。

 

4. 這些驅動程序編程接口如何工做?
------------------------------------------------
<linux/spi/spi.h>頭文件包含kerneldoc,主源代碼也是如此,你固然應該閱讀內核API文檔的那一章。 這只是一個概述,所以您能夠在這些細節以前瞭解全局。

  SPI 請求老是進入 I/O 隊列。 對給定SPI設備的請求始終按FIFO順序執行,並經過完成回調異步完成。 這些調用還有一些簡單的同步包裝器,包括用於編寫命令而後讀取其響應的常見事務類型。

有兩種類型的SPI驅動程序,這裏稱爲:

- 控制器驅動:Controllers 能夠內置到 Soc 中,而且一般支持主從兩個角色。 這些驅動程序觸及硬件寄存器,可能使用DMA。 或者它們能夠是PIO bitbangers,只須要GPIO引腳。其實也就是SPI主機控制器驅動。

- 協議驅動程序:它們經過控制器驅動程序傳遞消息,以便與SPI鏈路另外一側的從設備或主設備通訊。其實也就是SPI設備驅動。

  所以,例如,一個spi設備驅動程序可能與MTD層通訊以將數據導出到存儲在SPI閃存上的文件系統,如DataFlash; 其餘spi設備驅動可能控制音頻接口,將觸摸屏傳感器做爲輸入接口,或在工業處理過程當中監控溫度和電壓水平。 這些設備驅動可能共享相同的SPI主機控制器驅動程序。

"struct spi_device" 封裝了這兩種類型的驅動程序之間的控制器端接口。

  SPI核心的編程接口不多,側重於使用驅動程序模型使用由板特定初始化代碼提供的設備表來鏈接控制器驅動和設備驅動程序。SPI在幾個位置的sysfs中顯示:

 

/sys/devices/.../CTLR     給定SPI控制器的物理節點

/sys/devices/.../CTLR/spiB.C    總線「B」上的spi_device,chipselect是C,經過CTLR訪問。

/sys/bus/spi/devices/spiB.C    符號連接到該物理設備/CTLR/spiB.C

/sys/devices/.../CTLR/spiB.C/modalias    標識應該與此設備一塊兒使用的驅動程序(用於hotplug/coldplug)

/sys/bus/spi/drivers/D     一個或多個設備spi*.*的驅動程序

/sys/class/spi_master/spiB    符號連接(或實際設備節點)到邏輯節點,該邏輯節點能夠保持SPI主控制器管理
總線「B」的類相關狀態。 全部spiB.* 器件共享一個具備SCLK,MOSI和MISO的物理SPI總線。

/sys/devices/.../CTLR/slave    用於爲從控制器註冊(或取消註冊)一個從屬設備的虛擬文件。 將SPI從設備驅動程序的
名稱寫入此文件會註冊從設備; 寫 "(null)" 取消註冊從設備。 從該文件讀,顯示從設備的名稱(若是未註冊,則爲"(null)")。

/sys/class/spi_slave/spiB    符號連接(或實際設備節點)到邏輯節點,該邏輯節點能夠在總線「B」上保持SPI從控制器的類相
關狀態。 註冊時,此處存在單個spiB.*設備,可能與其餘SPI從設備共享物理SPI總線。

  請注意,控制器類狀態的實際位置取決於您是否啓用了 CONFIG_SYSFS_DEPRECATED。 此時,惟一特定於類的狀態是總線 編號(「spiB」中的「B」),所以這些/sys/class條目僅用於快速識別總線。

 

5. 板特定的init代碼如何聲明SPI設備?
------------------------------------------------------
Linux須要多種信息才能正確配置SPI設備。 該信息一般由特定於板的代碼提供(引入設備樹後就在設備樹中提供),即便對於支持某些自動發現/枚舉的芯片也是如此。

DECLARE CONTROLLERS

  第一種信息是SPI控制器存在的列表。 對於基於片上系統(SOC)的板,這些板一般是平臺設備,而且控制器可能須要一些platform_data才能正常運行。 「struct platform_device」將包含諸如控制器的第一個寄存器的物理地址及其IRQ之類的資源。

  平臺一般會抽象 "register SPI controller" 操做,可能將它與代碼耦合以初始化引腳配置,這樣幾個電路板的 arch/.../mach-*/board-*.c 文件均可以共享相同的基本控制器設置代碼。 這是由於大多數SOC都有幾個支持SPI的控制器,一般只能設置和註冊實際可用於給定板的控制器。

 

So for example arch/.../mach-*/board-*.c files might have code like:

    #include <mach/spi.h>    /* for mysoc_spi_data */

    /* if your mach-* infrastructure doesn't support kernels that can
     * run on multiple boards, pdata wouldn't benefit from "__init".
     */
    static struct mysoc_spi_data pdata __initdata = { ... };

    static __init board_init(void)
    {
        ...
        /* this board only uses SPI controller #2 */
        mysoc_register_spi(2, &pdata);
        ...
    }

And SOC-specific utility code might look something like:

    #include <mach/spi.h>

    static struct platform_device spi2 = { ... };

    void mysoc_register_spi(unsigned n, struct mysoc_spi_data *pdata)
    {
        struct mysoc_spi_data *pdata2;

        pdata2 = kmalloc(sizeof *pdata2, GFP_KERNEL);
        *pdata2 = pdata;
        ...
        if (n == 2) {
            spi2->dev.platform_data = pdata2;
            register_platform_device(&spi2);

            /* also: set up pin modes so the spi2 signals are
             * visible on the relevant pins ... bootloaders on
             * production boards may already have done this, but
             * developer boards will often need Linux to do it.
             */
        }
        ...
    }

請注意,即便使用相同的SOC控制器,板的 platform_data 也可能不一樣。 例如,在一塊板上,SPI可能使用外部時鐘,而另外一塊板則從某些主時鐘的當前設置中獲取SPI時鐘。

DECLARE SLAVE DEVICES

第二種信息是目標板上存在的SPI從設備列表,一般包含驅動程序正常工做所需的一些特定於板的數據。

一般你的 arch/.../mach-*/board-*.c 文件會提供一個小表來列出每塊板上的SPI器件。(這一般只是少數幾個。)這可能看起來像:

    static struct ads7846_platform_data ads_info = {
        .vref_delay_usecs    = 100,
        .x_plate_ohms        = 580,
        .y_plate_ohms        = 410,
    };

    static struct spi_board_info spi_board_info[] __initdata = {
    {
        .modalias    = "ads7846",
        .platform_data    = &ads_info,
        .mode        = SPI_MODE_0,
        .irq        = GPIO_IRQ(31),
        .max_speed_hz    = 120000 /* max sample rate at 3V */ * 16,
        .bus_num    = 1,
        .chip_select    = 0,
    },
    };

  再次,請注意如何提供特定於單板的信息; 每一個芯片可能須要幾種類型。 此示例顯示了通用約束,例如容許的最快SPI時鐘(在這種狀況下是電路板電壓的函數)或IRQ引腳如何接線,以及特定於芯片的約束,例如由一個引腳上的電容改變的重要延遲。

(還有「controller_data」,這些信息可能對控制器驅動程序有用。例如,外設特定的DMA調優數據或chipselect回調。稍後會存儲在 spi_device 中。)

  board_info應提供足夠的信息,讓系統在沒有加載芯片驅動程序的狀況下工做。最麻煩的方面多是 spi_device.mode 字段中的 SPI_CS_HIGH 位,由於在基礎結構知道如何取消選擇它以前,不可能與一個 "backwards" 解釋chipselect的設備共享總線。

而後,您的電路板初始化代碼將使用SPI基礎結構註冊該表,以便稍後在SPI主控制器驅動程序註冊時可用:

spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));

與其餘靜態板特定設置同樣,您不會取消註冊。

  普遍使用的 "card" 式計算機將內存,CPU和其餘小東西捆綁到可能只有三十平方釐米的卡上。 在這樣的系統上,你的 arch/.../mach-.../board-*.c 文件主要提供有關插入這種卡的主板上的設備的信息。 這確定包括經過卡鏈接器鏈接的SPI設備!

NON-STATIC CONFIGURATIONS

  開發板一般採用與產品板不一樣的規則,一個例子是可能須要熱插拔SPI器件和/或控制器。

  對於這些狀況,您可能須要使用 spi_busnum_to_master() 來查找spi總線master,而且可能須要spi_new_device()來提供基於熱插拔板的板信息。 固然,在刪除該板後,您將至少要調用spi_unregister_device()。

  當Linux經過SPI支持 MMC / SD / SDIO / DataFlash 卡時,這些配置也將是動態的。 幸運的是,這些設備都支持基本的設備識別的probes,所以它們應該正常熱插拔。

 

6. 如何編寫「SPI協議(設備)驅動程序」?
----------------------------------------
  大多數SPI驅動程序目前是內核驅動程序,但也支持用戶空間驅動程序。 這裏咱們只討論內核驅動程序。SPI協議驅動程序有點像平臺設備驅動程序:

    static struct spi_driver CHIP_driver = {
        .driver = {
            .name        = "CHIP",
            .owner        = THIS_MODULE,
            .pm        = &CHIP_pm_ops,
        },

        .probe        = CHIP_probe,
        .remove        = CHIP_remove,
    };

驅動程序核心將自動嘗試將此驅動程序綁定到其 board_info.modalias 等於 "CHIP" 的任何SPI設備。 除非您正在建立一個管理總線的設備(出如今 /sys/class/spi_master 下),不然您的 probe() 代碼可能以下所示。

 

    static int CHIP_probe(struct spi_device *spi)
    {
        struct CHIP            *chip;
        struct CHIP_platform_data    *pdata;

        /* assuming the driver requires board-specific data: */
        pdata = &spi->dev.platform_data;
        if (!pdata)
            return -ENODEV;

        /* get memory for driver's per-chip state */
        chip = kzalloc(sizeof *chip, GFP_KERNEL);
        if (!chip)
            return -ENOMEM;
        spi_set_drvdata(spi, chip);

        ... etc
        return 0;
    }

一旦進入probe(),驅動程序就可使用 「struct spi_message」 向SPI設備發出 I/O 請求。 當 remove() 返回時,或者在 probe() 失敗後,驅動程序保證它再也不提交此類消息。

  - spi_message 是一系列協議操做,做爲一個原子序列執行。 SPI驅動程序控件包括:

    + 當雙向讀寫開始時... 按順序排列 spi_transfer 請求的順序;

    + 使用哪些 I/O 緩衝區... 每一個 spi_transfer 爲每一個傳輸方向包裝一個緩衝區,支持全雙工(兩個指針,在兩種狀況下多是相同的)和半雙工(一個指針爲NULL)傳輸;

    + 可選擇在傳輸後定義短延遲... 使用 spi_transfer.delay_usecs 設置(若是緩衝區長度爲零,此延遲多是惟一的協議效果);

    + 在傳輸和延遲後片選引腳是否變爲非active狀態... 經過 spi_transfer.cs_change 標誌來設置; ##############

    + 暗示下一條消息是否可能傳到同一設備... 在該原子組的最後一次傳輸中使用 spi_transfer.cs_change 標誌,並可能節省芯片取消選擇和選擇操做的成本。

譯者注:spi_message 是對 一個或多個 spi_transfer 的管理者,spi_message 裏面有有一個鏈表,掛接多個 spi_transfer。一個 spi_message 是一次原子的硬件操做(CS拉低,傳輸數據,CS拉高)

  - 遵循標準內核規則,並在消息中提供DMA安全緩衝區。 這樣,除非硬件須要,不然使用DMA的控制器驅動程序不會被強制執行額外的拷貝(例如,使用強制使用反彈緩衝的硬件勘誤表)。

    若是標準的 dma_map_single() 處理這些緩衝區不合適的話,則可使用 spi_message.is_dma_mapped 告訴控制器驅動程序您已經提供了相關的DMA地址。

  - 基本I / O原語是 spi_async()。 能夠在任何上下文(irq處理程序,任務等)中發出異步請求,並使用隨消息提供的回調來報告完成。 在檢測到任何錯誤以後,取消選擇芯片並停止該 spi_message 的處理。  

  - 還有像 spi_sync() 這樣的同步包裝器,以及 spi_read(),spi_write() 和 spi_write_then_read() 等包裝器。這些只能在能夠睡眠的上下文中調用,而且它們都是對 spi_async() 的包裝。

  - spi_write_then_read() 調用及其周圍的便利包裝器應僅用於少許數據,其中可忽略額外拷貝操做的成本。它旨在支持常見的 RP C樣式請求,例如寫入8位命令和讀取16位響應 - spi_w8r16()是其包裝器之一,正是這樣作的。

   某些驅動程序可能須要修改 spi_device 特性,如傳輸模式,字大小或時鐘速率。這是經過 spi_setup() 完成的,一般在第一次 I/O 到設備完成以前在 probe() 中調用。 可是,也能夠在任什麼時候候調用,只要沒有到該設備的pending的消息。

  雖然 「spi_device」 將是驅動程序的底部邊界,但上邊界可能包括sysfs(特別是傳感器讀數),input layer, ALSA, networking, MTD, 字符設備框架或其餘Linux子系統。

  請注意,驅動程序必須管理兩種類型的內存,做爲與SPI設備交互的一部分。

    - I/O 緩衝區使用一般的Linux規則,而且必須是DMA安全的。 您一般會從堆或空閒頁池中分配它們。 不要使用堆棧或任何聲明爲 "static" 的東西。

    - spi_message 和 spi_transfer 元數據被用於將這些 I/O 緩衝區粘合到一組協議事務中。這些能夠在任何方便的地方分配,包括做爲其餘一次分配驅動程序數據結構的一部分。將這些結構初始化爲零。

若是你願意,spi_message_alloc() 和 spi_message_free()方便例程可用於分配和初始化具備多個傳輸的 spi_message。

 

 7. 如何編寫「SPI主控制器驅動程序」?

-------------------------------------------------
  SPI控制器可能會在 platform_bus 上註冊; 寫一個驅動程序綁定到設備,不管涉及哪一種總線。

  這類驅動程序的主要任務是提供一個"spi_master"。 使用 spi_alloc_master()來分配一個master結構,使用 spi_master_get_devdata() 獲取爲該設備分配的驅動程序專用數據。

    struct spi_master    *master;
    struct CONTROLLER    *c;

    master = spi_alloc_master(dev, sizeof *c);
    if (!master)
        return -ENODEV;

    c = spi_master_get_devdata(master);

  驅動程序將初始化該 spi_master 的字段,包括總線編號(可能與平臺設備ID相同)以及用於與SPI內核和SPI協議(設備)驅動程序交互的三種方法。它還將初始化本身的內部狀態。(見下面關於總線編號和那些方法。)

#define spi_master        spi_controller

  初始化 spi_master 後,使用 spi_register_master() 將其發佈到系統的其他部分。 那時,控制器和任何預先聲明的spi設備的設備節點將可用,驅動程序核心將負責將它們綁定到驅動程序。

  若是你須要刪除SPI控制器驅動程序,spi_unregister_master() 將反轉 spi_register_master() 的效果。

BUS NUMBERING

   總線編號很重要,由於這是Linux識別給定SPI總線(共享SCK,MOSI,MISO)的方式。 有效的總線編號從零開始。 在SOC系統上,總線編號應與芯片製造商定義的編號匹配。 例如,硬件控制器SPI2將是總線編號2,鏈接到它的設備的 spi_board_info 將使用該編號。

  若是您沒有這種硬件分配的總線編號,而且因爲某種緣由您不能分配它們,那麼請提供負的總線編號。而後將由動態分配的號碼替換。 而後,您須要將其視爲非靜態配置(請參見上文)。

SPI MASTER METHODS

master->setup(struct spi_device * spi)

  這將設置設備時鐘速率,SPI模式和字大小。 驅動程序可能會更改 board_info 提供的默認值,而後調用 spi_setup(spi)來調用此例程。 它可能會睡覺。

除非每一個SPI從設備都有本身的配置寄存器,不然不要當即更改它們......不然驅動程序可能會破壞其餘SPI設備正在進行的 I/O.

** BUERT ALERT:因爲某種緣由,許多 spi_master 驅動程序的第一個版本彷佛弄錯了。 當您對 setup() 進行編碼時,ASSUME 控制器正在主動處理另外一個設備的傳輸。

master->cleanup(struct spi_device * spi)

  您的控制器驅動程序可使用 spi_device.controller_state 來保持它與該設備動態關聯的狀態。 若是這樣作,請確保提供 cleanup()方法以釋放該狀態。

master->prepare_transfer_hardware(struct spi_master * master)

  這將由隊列機制調用,以向驅動程序發出即將進入消息的信號,所以子系統經過發出此調用請求驅動程序準備傳輸硬件。 這可能會睡覺。

master->unprepare_transfer_hardware(struct spi_master * master)

  這將由隊列機制調用,以向驅動器發信號通知隊列中沒有待處理的消息,而且它能夠放鬆硬件(例如,經過電源管理調用)。 這可能會睡覺。

master-> transfer_one_message(struct spi_master * master,struct spi_message * mesg)

  子系統調用驅動程序來傳輸單個消息,同時排隊同時到達的傳輸。 當驅動程序完成此消息時,它必須調用spi_finalize_current_message(),以便子系統能夠發出下一條消息。 這可能會睡覺。

master->transfer_one(struct spi_master * master,struct spi_device * spi,struct spi_transfer * transfer)

  子系統調用驅動程序來傳輸單個transfer,同時排隊在此期間到達的傳輸。 當驅動程序完成此傳輸時,它必須調用 spi_finalize_current_transfer(),以便子系統能夠發出下一次傳輸。 這可能會睡覺。 注意:transfer_one 和 transfer_one_message 是互斥的; 當二者都設置時,通用子系統不會調用 transfer_one 回調。

返回值:失敗返回負的錯誤碼,成功返回 0:傳輸完成,1:轉移仍在進行中

DEPRECATED METHODS

master->transfer(struct spi_device * spi,struct spi_message * message)

  這必定不能睡眠。 它的職責是安排傳輸發生併發出 complete() 回調(也就意味着complete()回調不能休眠)。這兩個一般會在其餘傳輸完成後發生,若是控制器空閒,則須要啓動。此方法不在排隊控制器上使用,若是實現transfer_one_message() 和 (un)prepare_transfer_hardware(),則必須爲NULL。

SPI MESSAGE QUEUE

  若是您對SPI子系統提供的標準排隊機制感到滿意,只需實現上面指定的排隊方法便可。 使用消息隊列具備集中大量代碼和提供方法的純流程上下文執行的優勢。
消息隊列也能夠升級爲高優先級SPI流量的實時優先級

  除非選擇SPI子系統中的排隊機制,不然驅動程序的大部分將管理由現已棄用的函數transfer() 提供的 I/O 隊列。

  那個隊列可能純粹是概念性的。 例如,僅使用低頻傳感器訪問的驅動程序使用同步PIO更好。

  可是隊列可能很是真實,使用message->queue,PIO,一般是DMA(特別是若是根文件系統在SPI閃存中),以及執行上下文,如IRQ處理程序,tasklet或工做隊列(如keventd)。 您的驅動程序能夠根據您的須要而變得花哨或簡單。 這樣的transfer()方法一般只是將消息添加到隊列中,而後啓動一些異步傳輸引擎(除非它已經在運行)。

相關文章
相關標籤/搜索