Linux中SPI系統概覽
Contents
Part 1 - Linux中SPI子系統概覽
Part 3 - 異步寫
Overview
SPI框架的內核文檔是個好的開始。在你的內核源碼中Documentation/目錄下,這裏有個連接:SPI-概覽。
Linux中SPI驅動有倆個部分組成:controller驅動,直接和底層硬件打交道,protocol驅動,針對特定的設備,也是我麼要做的。
這裏只考慮SPIprotocol驅動
在主線內核中有一個通用的字符型驅動範例spidev。本文不討論spidev,而是探討如何編寫一個自定義SPI設備驅動。
爲何要編寫一個自定義驅動:
1. 可以掌控性能;
2.無需給內核打補丁。SPI框架完整支持在可加載內核模塊中進行驅動設置。這也就允許我們在內核源碼樹外進行編寫代碼。
Kernel Configuration
關掉SPIDEV選項以支持自定義的驅動
Device Drivers
SPI support
User mode SPIdevice driver support
Driver setup
爲使linuxSPI系統識別你的驅動,需要做兩步準備。
1.在特定的SPI總線(一個master就是一條總線)上註冊SPI slave設備。可以是內核初始化的時候亦或是在你的驅動代碼中動態的進行。設備名稱在這步中必須指定。
2. 註冊SPI protocol驅動。使用的名字必須和步驟1中的一致,這樣kernel就可以將它們鏈接在一起了。
兩個步驟可以以任意次序進行,但是得知道當他們完成之後,SPI框架就可以響應你驅動中的probe()調用了。你將得到一個spi_device用來和SPI系統進行交互了。一旦你的probe函數調用成功,你就可以開始使用SPI總線了。
靜態註冊SPI設備涵蓋在spidev中了。
動態主冊SPI設備的步驟如下:
1.得到管理總線的spi_master控制器指針(句柄);
2. 爲總線分配spi_device結構;
3.驗證沒有其他的設備已經在這條總線bus.cs上註冊過了;
4.使用設備特定的值(speed,datasize,etc)來填充spi_device;
5.將新的spi_device添加到總線。
有個範例代碼:
static int __init add_spike_device_to_bus(void)
{
struct spi_master *spi_master;
struct spi_device *spi_device;
struct device *pdev;
char buff[64];
int status = 0;
spi_master = spi_busnum_to_master(SPI_BUS);
if (!spi_master) {
printk(KERN_ALERT "spi_busnum_to_master(%d) returned NULL\n",
SPI_BUS);
printk(KERN_ALERT "Missing modprobe omap2_mcspi?\n");
return -1;
}
spi_device = spi_alloc_device(spi_master);
if (!spi_device) {
put_device(&spi_master->dev);
printk(KERN_ALERT "spi_alloc_device() failed\n");
return -1;
}
/* specify a chip select line */
spi_device->chip_select = SPI_BUS_CS1;
/* Check whether this SPI bus.cs is already claimed */
snprintf(buff, sizeof(buff), "%s.%u",
dev_name(&spi_device->master->dev),
spi_device->chip_select);
pdev = bus_find_device_by_name(spi_device->dev.bus, NULL, buff);
if (pdev) {
/* We are not going to use this spi_device, so free it */
spi_dev_put(spi_device);
/*
* There is already a device configured for this bus.cs combination.
* It's okay if it's us. This happens if we previously loaded then
* unloaded our driver.
* If it is not us, we complain and fail.
*/
if (pdev->driver && pdev->driver->name &&
strcmp(this_driver_name, pdev->driver->name)) {
printk(KERN_ALERT
"Driver [%s] already registered for %s\n",
pdev->driver->name, buff);
status = -1;
}
} else {
spi_device->max_speed_hz = SPI_BUS_SPEED;
spi_device->mode = SPI_MODE_0;
spi_device->bits_per_word = 8;
spi_device->irq = -1;
spi_device->controller_state = NULL;
spi_device->controller_data = NULL;
strlcpy(spi_device->modalias, this_driver_name, SPI_NAME_SIZE);
status = spi_add_device(spi_device);
if (status < 0) {
spi_dev_put(spi_device);
printk(KERN_ALERT "spi_add_device() failed: %d\n",
status);
}
}
put_device(&spi_master->dev);
return status;
}
稍微有點複雜,這是個完整的樣板。你完全可以只更改spi_device中指定域來服務你自己的驅動。
註冊spi_driver,首先要用驅動名字還有些回調函數來初始化他。至少你得提供一個probe()函數,讓他能夠找到他的另一半spi_device。
範例:
static struct spi_driver spike_driver = {
.driver = {
.name =this_driver_name,
.owner =THIS_MODULE,
},
.probe =spike_probe,
.remove =spike_remove,
};
具體的也可參考linux/spi/spi.h文件接着就可一在某個地方調用spi_register_driver()進行註冊了.
spi_register_driver(&spike_driver);