硬件平台:本人自行开发的基于S3C2440核心板的集中采集一体化设备
linux内核版本:2.6.30.4
目的:通添加spi接口来控制zlg zm470sx-m模块
一、spi驱动移植和测试
在2.6.30.4内核源码中,已经给出了S3C2440的SPI驱动,因此要在arch/arm/mach-s3c2440/mach-smdk2440.c中加入SPI的支持,由于S3C2440具有两个spi master接口,因此这里的驱动移植同时支持两个spi master接口。
1、添加头文件
#include <../mach-s3c2410/include/mach/spi.h>
#include <linux/spi/spi.h>
2、增加如下结构定义
/*增加两个spi设备*/
static struct spi_board_info s3c2410_spi0_board[] = {
[0] = {
.modalias = "spidev",
.bus_num = 0,
.chip_select = 0,
.irq = IRQ_EINT10,
.max_speed_hz = 500*1000,
},
};
static struct s3c2410_spi_info s3c2410_spi0_platdata = {
.pin_cs = S3C2410_GPG2,
.num_cs = 1,
.bus_num = 0,
};
static struct spi_board_info s3c2410_spi1_board[] = {
[0] = {
.modalias = "spidev",
.bus_num = 1,
.chip_select = 0,
.irq = IRQ_EINT11,
.max_speed_hz = 500*1000,
},
};
static struct s3c2410_spi_info s3c2410_spi1_platdata = {
.pin_cs = S3C2410_GPG3,
.num_cs = 1,
.bus_num = 1,
};
这几个结构与前述参考内容不太一样,主要对pin_cs进行了修改,将其改回S3C2440的两个nSS脚。另外,spi1的配置需要将bus_num改为1,否则后面装载驱动会出错,另外,将两个中断源改为相应的nSS脚占用的外部中断号,但尚未验证其不同选择对驱动的影响。
3、在smdk2440_devices中增加下面两行:
&s3c_device_spi0,
&s3c_device_spi1,
这两个结构体在内核源码arch/arm/plat-s3c24xx/devs.c中定义,主要负责将S3C2440的SPI控制寄存器及中断资源进行描述。
static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_spi0,
&s3c_device_spi1,
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&s3c_device_dm9000,
&s3c_device_rtc,
};
4、在smdk2440_machine_init函数中增加SPI设备注册代码:
static void __init smdk2440_machine_init(void)
{
s3c24xx_fb_set_platdata(&smdk2440_fb_info);
s3c_i2c0_set_platdata(NULL);
platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
smdk_machine_init();
//增加SPI设备注册代码
s3c_device_spi0.dev.platform_data= &s3c2410_spi0_platdata;
spi_register_board_info(s3c2410_spi0_board, ARRAY_SIZE(s3c2410_spi0_board));
s3c_device_spi1.dev.platform_data= &s3c2410_spi1_platdata;
spi_register_board_info(s3c2410_spi1_board, ARRAY_SIZE(s3c2410_spi1_board));
}
5、完成上述修改后就可以编译内核了。
当然,这样编译的内核是不能支持spi的,还需要对SPI设备驱动进行编译。make menuconfig,进入Device Drivers-->SPI Support,将下述三项都选上:
当然,如果想将这三个模块都编译进内核就将其标注为*。保存退出后make modules,在drivers/spi目录生成三个ko文件:spi_bitbang.ko spidev.ko spi_s3c24xx.ko。spi_bitbang.ko是基础驱动,spi_s3c24xx.ko依赖于这个驱动提供的功能,spi_s3c24xx.ko是S3C2440 SPI的核心驱动,基本功能都由这个驱动实现,但是这个是SPI Master驱动,只有它还无法完成SPI的操作,spidev.ko实现了/dev/spidevX.X设备,依赖于spi_s3c24xx.ko提供的功能,在用户侧可以进行调用。
这几个驱动编译完毕后,下载到单板进行装载,由于驱动之间存在依存关系,所以一定要按照下面顺序装载:
insmod spi_bitbang.ko
insmod spi_s3c24xx.ko
insmod spidev.ko
装载完毕后,如果能够在/dev下看到spidev0.0和spidev1.0就OK了。
6、spi驱动测试
硬件电路上分别将spi0和spi1的miso和mosi引脚环回连接进行自测试。
在内核源码中的Documents/spi目录下有SPI驱动测试程序,将里面的设备名称修改为上面两个设备名称:
static const char *device = "/dev/spidev0.0";
// static const char *device = "/dev/spidev1.0";
进入目录直接用gcc命令进行编译得到spidev_test测试文件,编译后下载到单板分别进行验证,在SPI输入输出环回的情况下,验证OK:
7、spi驱动在产品中的使用情况
从上面的移植过程可以看出驱动是可以使用的了,但在具体的跟zm470模块调试的时候并没有调试成功,本人根据上面的spi驱动测试程序编写了read,write函数,但read的数据始终为零,最后没有办法就找了几个gpio管脚来模拟spi的通信,顺利调试通过。下面是一个使用场景:本人开发的集中采集一体化设备连接了一个zm470模块做为主机、另外有两个zm470的开发板;zm470模块主机不停在470M频点上发送数据,可以看到两个zm470开发板上的led指示灯在闪烁表示接收到数据,如果按zm470开发板上的s2键就可以看到主机由数据打印输出,表示主机接收到数据。