Linux kernel
本文以Beaglebone版子為例,linux 4.19.142
為了找到內核與SPI相關的程式碼,利用以下步驟
選擇Device Drivers
-> <*>SPI support
找到預設已勾選的選項,輸入'?'紀錄第一行CONFIG_xxxxx
查找上一步驟所記錄的CONFIG_xxxxx,就可以知道那個檔案會被使用到
列出如下
與Makefile定義的一樣
第140行
There are two types of SPI driver, here called:
Controller drivers … controllers may be built into System-On-Chip
processors, and often support both Master and Slave roles.
These drivers touch hardware registers and may use DMA.
Or they can be PIO bitbangers, needing just GPIO pins.Protocol drivers … these pass messages through the controller
driver to communicate with a Slave or Master device on the
other side of an SPI link.
由以上步驟以及spi-summary說明,可以推測出SPI是由core(spi.c)、protocol driver(spidev.c)、master controller driver(spi-omap2-mcspi.c)、spi device(由device tree載入)所構成。
比起一般的linux驅動架構,增加了spi_master(spi_controller)結構,一般由BSP提供,驅動工程師則負責針對spi driver進行開發。
而各個區塊主要負責的工作
檔案 | struct | 說明 |
---|---|---|
spi.c | N/A | spi_bus總線,負責管理設備、驅動、控制器 |
spi-omap2-mcspi.c | spi_master | spi控制器,可以想像成am335x晶片有spi0、spi1兩個控制器,藉由spi_master設定spi硬體控制器,進行SPI資料傳輸 |
spidev.c | spi_driver | spi驅動,根據連接硬體裝置的datasheet,撰寫所需傳輸的資料內容,例如flash driver主要功能有flash讀/寫/擦除等操作,皆可以透過ioctrl實現 |
dts | spi_device | 硬體設備相關資訊,定義在device tree裡 |
在撰寫spi驅動時,建議參考內核提供的spidev.c以及Documentation\spi\spidev說明文件 |
內核載入時會自動安裝spi-omap2-mcspi.c的module,註冊名為omap2_mcspi_driver的platform_driver
而當設備樹的compatile屬性與omap2_mcspi_driver裡的omap_mcspi_of_match裡compatible定義的名子相同時,就會調用omap2_mcspi_probe函數。
如同如何使用linux內核提供SPI設備驅動Spidev文章,am335x-boneblack-wireless.dts裡定義的
並在am33xx.dtsi裡找到spi0節點的定義
發現compatible定義與spi-omap2-mcspi.c裡的omap_mcspi_of_match相同,所以會調用omap2_mcspi_probe
補充:雖然在spi0節點裡的status是disabled,但在am335x-boneblack-wireless.dts裡將其enabled,所以會重新enabled
omap2_mcspi_probe主要將設備樹裡定義的硬體資訊匯入到spi_master
第87行devm_spi_register_master()會調用到spi_register_controller向內核註冊spi_master。
spi controller(spi-omap2-mcspi.c)是由BSP提供,因此只需瞭解struct spi_master結構即可。
在前面spi controller註冊時,會調用到spi_register_controller向內核註冊spi_master
spi_register_controller會呼叫of_register_spi_devices,最終會調用spi_add_device。
第53行spi_setup會調用到controller的setup函數,設定該設備等mode、max frequency。
第61行spi_add_device則會將device加入內核中,並找尋是否有合適driver進行綁定。
安裝spidev驅動時會呼叫入口函數spidev_init()
在第20行spi_register_driver函式會向內核註冊"struct spidriver spidev_spi_driver",而若spidev_spi_driver裡的.of_match_table的compatile或是spidev_spi_driver裡的.name與設備樹定義的相同,則會調用probe函數,因此最終會調用到spidev_probe。
spidev_probe會建立設備節點/dev/spidev*.*,應用層可開啟此設備節點並操作設備
透過spi.h提供的spi_write/spi_read/spi_write_then_read函式
第20行的spi_sync:將多個spi_transfer組成的spi_message送出spi同步傳輸,最終會調用spi_master提供的transfer相關函數。