首先看下spi驱动的大概构成:
下边看下编写spi驱动的大致流程(3.2及之前版本内核):
而在TI最新的sdk中内核版本为3.14, 使用了dts. 编写方法稍有不同.
我们先来了解一下3.2及之前版本内核的spi驱动编写方法:
spi上层驱动:
先编写spi_board_info结构体, 然后调用spi_register_board_info方法, 它会自动根据spi_board_info的bus_num成员匹配spi_master, 如果匹配成功则创建spi_device, 另外spi_device的名称就是根据spi_board_info结构体的名称来命名的, 同时如果查到系统中有同名的spi_driver则调用spi_driver的probe函数, 然后我们就可以在probe函数中做自己需要的工作, 由此可见spi_board_info的中的名称(.modalias)必须和spi_driver中的名称一样. 我们需要做的是编写两个文件, 一个是spi_board_info和spi_register_board_info, 这个文件要被编译到内核里, 因为spi_register_board_info并未被导出必须编译到系统中, 如果编译为模块会发现该函数未定义. 另外一个就是我们需要实现的具体驱动, 一般都在probe里创建chrdev然后用chrdev的read/write/ioctl里调用spi_read/spi_write.
spi核心层:
spi驱动上层中调用spi_write和spi_read, 然后spi核心层的spi.c中将它们处理之后转交为spi_master来处理, spi_master在io上发出时序信号. 我们不需要关心这部分的内容
spi驱动底层(控制器):
spi_master 负责跟芯片的spi控制器打交道, mster中的transfer就是产生时序信号的函数.spi_master使用了platform总线. 那么我们首先查看spi_master驱动中platform_driver的名称, 根据名称到板级初始化文件中创建platform_device结构体, 并把设备添加到板级初始化中, 到内核里使能spi主控驱动, 这样系统启动时候就能发现同名的platform driver和device, spi master随之初始化. 剩下的就是编写spi驱动来调用spi_writer和spi_read等工作. spi_master驱动一般由厂家提供, 我们只需要完善platform_device部分即可.
注意: spi上层是 spi_driver和spi_device spi底层是 platform_device 和platform_driver
在TI提供的系统中, spi_master驱动位于 sdk/board-support/linux-3.14.26-g2489c02/drivers/spi/spi-omap2-mcspi.c中, 而且在系统中已经创建了同名的设备, 所以只要一开机就会初始化spi_master驱动, 我们需要关心的只是去dts里配置spi的引脚即可.
根据之前的博客, 我们已经可以从tftp下载内核 并且挂载nfs为根文件系统了, 我们可以到 /tftp 目录下查看到启动系统使用的内核和设备数文件:
zImage-am335x-evm.bin 和 am335x-boneblack.dtb
然后再查看一下 /dev 下有没有spi设备( ls /dev ), sdk中的系统是没有开启spi设备的.
首先我们来编写注册spi_board_info的代码 (新建 sdk//board-support/linux-3.14.26-g2489c02/drivers/spi/bbb_spi_info.c):
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/gpio.h>
static struct spi_board_info spi_info_jz2440[] = {
{
.modalias = "spi_tst", /* 对应的spi_driver名字也是"oled" */
.max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */
.bus_num = 1, /* jz2440里OLED接在SPI CONTROLLER 1 */
.mode = SPI_MODE_0,
// .chip_s