内核版本:3.9.5
Linux中SPI驱动有俩个部分组成:controller驱动,直接和底层硬件打交道,protocol驱动,针对特定的设备,也是我们要做的.
这里只考虑SPI protocol驱动
在主线内核中有一个通用的字符型驱动范例spidev.本文不讨论spidev,而是探讨如何编写一个自定义SPI设备驱动.
为何要编写一个自定义驱动:
- 可以掌控性能;
- 无需给内核打补丁.SPI框架完整支持在可加载内核模块中进行驱动设置.这也就允许我们在内核源码树外进行编写代码;
Kernel Configuration
关掉SPIDEV选项以支持自定义的驱动
Device Drivers-->
SPI support-->
*** SPI Protocol Masters ***
<> User mode SPIdevice driver support
为使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添加到总线;
有个范例代码:
1 static int __init add_spike_device_to_bus(void) 2 { 3 struct spi_master *spi_master; 4 struct spi_device *spi_device; 5 struct device *pdev; 6 char buff[64]; 7 int status = 0; 8 9 spi_master = spi_busnum_to_master(SPI_BUS); 10 if (!spi_master) { 11 printk(KERN_ALERT "spi_busnum_to_master(%d) returned NULL\n", 12 SPI_BUS); 13 printk(KERN_ALERT "Missing modprobe omap2_mcspi?\n"); 14 return -1; 15 } 16 17 spi_device = spi_alloc_device(spi_master); 18 if (!spi_device) { 19 put_device(&spi_master->dev); 20 printk(KERN_ALERT "spi_alloc_device() failed\n"); 21 return -1; 22 } 23 24 /* specify a chip select line */ 25 spi_device->chip_select = SPI_BUS_CS1; 26 27 /* Check whether this SPI bus.cs is already claimed */ 28 snprintf(buff, sizeof(buff), "%s.%u", 29 dev_name(&spi_device->master->dev), 30 spi_device->chip_select); 31 32 pdev = bus_find_device_by_name(spi_device->dev.bus, NULL, buff); 33 if (pdev) { 34 /* We are not going to use this spi_device, so free it */ 35 spi_dev_put(spi_device); 36 37 /* 38 * There is already a device configured for this bus.cs combination. 39 * It's okay if it's us. This happens if we previously loaded then 40 * unloaded our driver. 41 * If it is not us, we complain and fail. 42 */ 43 if (pdev->driver && pdev->driver->name && 44 strcmp(this_driver_name, pdev->driver->name)) { 45 printk(KERN_ALERT 46 "Driver [%s] already registered for %s\n", 47 pdev->driver->name, buff); 48 status = -1; 49 } 50 } else { 51 spi_device->max_speed_hz = SPI_BUS_SPEED; 52 spi_device->mode = SPI_MODE_0; 53 spi_device->bits_per_word = 8; 54 spi_device->irq = -1; 55 spi_device->controller_state = NULL; 56 spi_device->controller_data = NULL; 57 strlcpy(spi_device->modalias, this_driver_name, SPI_NAME_SIZE); 58 status = spi_add_device(spi_device); 59 60 if (status < 0) { 61 spi_dev_put(spi_device); 62 printk(KERN_ALERT "spi_add_device() failed: %d\n", 63 status); 64 } 65 } 66 67 put_device(&spi_master->dev); 68 69 return status; 70 }
稍微有点复杂,这是个完整的样板.你完全可以只更改spi_device中指定域来服务你自己的驱动.
注册spi_driver,首先要用驱动名字还有些回调函数来初始化他.至少你得提供一个probe()函数,让他能够找到他的另一半spi_device.
范例:
1 static struct spi_driver spike_driver = { 2 .driver = { 3 .name =this_driver_name, 4 .owner =THIS_MODULE, 5 }, 6 .probe =spike_probe, 7 .remove =spike_remove, 8 };
具体的也可参考linux/spi/spi.h文件
接着就可一在某个地方调用spi_register_driver()进行注册了.
1 spi_register_driver(&spike_driver);
本文转自:http://blog.csdn.net/wuhzossibility/article/details/7831652