本文测试平台为zedboard,使用PS端SPI外设。根据wiki_xilinx中的说明,此驱动为 candence_spi.c ,现对此驱动程序做一个简单的分析。wiki_xilinx 中 SPI 的简略介绍在这个网址。
http://www.wiki.xilinx.com/SPI%20Zynq%20driver
根据wiki中的介绍,首先要的是配置内核以及相关设备树节点的编写。设备树节点编写方法我将在另外一篇博客中进行说明。
完整的candence_spi.c 在内核文件的 /driver/spi/ 路径下可以找到。
驱动程序涉及到 3 个关键数据结构体,分别为:( spi_master 结构体与 xspi 相似)
struct cdns_spi {} //驱动中的实例为 xspi;
struct spi_device {} //驱动中的实例为 spi;
struct xspi {} //驱动中的实例为 dev_id;
struct spi_master {} //与 xspi {} 结构体相似;实例为 master;
上述结构体相互转换方式如下:
struct spi_device *spi;
struct cdns_spi *xspi = spi_master_get_devdata(spi->master);
struct xspi *dev_id;
struct spi_master *master = dev_id;
struct cdns_spi *xspi = spi_master_get_devdata(master);
下面开始对驱动程序进行一下说明,部分代码如下:
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
/* Name of this driver */
#define CDNS_SPI_NAME "cdns-spi"
/* Register offset definitions */
#define CDNS_SPI_CR_OFFSET 0x00 /* Configuration Register, RW */
#define CDNS_SPI_ISR_OFFSET 0x04 /* Interrupt Status Register, RO */
#define CDNS_SPI_IER_OFFSET 0x08 /* Interrupt Enable Register, WO */
#define CDNS_SPI_IDR_OFFSET 0x0c /* Interrupt Disable Register, WO */
#define CDNS_SPI_IMR_OFFSET 0x10 /* Interrupt Enabled Mask Register, RO */
#define CDNS_SPI_ER_OFFSET 0x14 /* Enable/Disable Register, RW */
#define CDNS_SPI_DR_OFFSET 0x18 /* Delay Register, RW */
#define CDNS_SPI_TXD_OFFSET 0x1C /* Data Transmit Register, WO */
#define CDNS_SPI_RXD_OFFSET 0x20 /* Data Receive Register, RO */
#define CDNS_SPI_SICR_OFFSET 0x24 /* Slave Idle Count Register, RW */
#define CDNS_SPI_THLD_OFFSET 0x28 /* Transmit FIFO Watermark Register,RW */
首先是各种头文件,定义驱动的名字为“cdns-spi”,以及相关寄存器 offset 的定义(根据UG585文档中SPI寄存器的说明来编写)。此处不需要过多说明。
接下来定义了关键的结构体 cdns_spi 与SPI寄存器的读写函数。要理解此结构体,后面程序一直用得上。regs为SPI寄存器的初始地址,zynq中SPI初始地址为 0xe0007000,是通过设备树传递过来的常量。代码如下:
/**
* struct cdns_spi - This definition defines spi driver instance
* @regs: Virtual address of the SPI controller registers
* @ref_clk: Pointer to the peripheral clock
* @pclk: Pointer to the APB clock
*