SPI protocol 驅動編寫 Part 1

LinuxSPI系統概覽

Contents

        Part 1 - LinuxSPI子系統概覽

        Part 2 - SPI message基礎

        Part 3 - 異步寫

Overview

SPI框架的內核文檔是個好的開始。在你的內核源碼中Documentation/目錄下,這裏有個連接:SPI-概覽

LinuxSPI驅動有倆個部分組成: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.使用設備特定的值(speeddatasizeetc)來填充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); 

發佈了29 篇原創文章 · 獲贊 55 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章