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); 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值