最近在参考了很多的网络资源后编写调试了在mini2440开发板上的SPI驱动程序,因为急于使用也没有分析S3C2440在Linux下自带的源程序,编写程序的方式较为简单,只是实现了简单的字符发送和接收。
主要是配置一些寄存器。这些寄存器的配置按照S3C2440手册的说明来进行设置,根据mini2440开发板只有SPI0可以使用,SPI1被按键使用了。采用GPE和GPG来进行控制。
SPI 的编程步骤是当一个字节数据写入SPTDATn寄存器,如果ENSCK、SPCONn寄存器的MSTR被置位,SPI开始发送,可以采用以下不住来操作SPI:手册上的编程基本步骤:
(1)时钟波特率预定标器寄存器(SPPREn)
(2)设置SPCONn来合理配合SPI模块
(3)写数据0XFF到SPTDATn到SPTDATn 10次,目的是初始化MMC或SD卡
(4)设置一个GPTO引脚作为nSS,低电平是激活MMC或SD卡
(5)发送数据->检查传输准备标志(REDY=1)的状态,然后写数据到SPTDATn
(6)接收数据(1):SPCONn的TAGD位是无效=normal mode(0)->写0XFF 到SPTDATn,然后确认REDY置1,然后从读缓存读取数据
(7)接收数据(2):SPCONn的TAGD位是有效=Tx Auto Garbage Data mode->确认REDY置1,然后从读缓存读取数据(然后自动开始传输)
(8)设置一个GPIO引脚,其作为nSS,高电平是解除激活MMC或SD卡。
源代码如下,具体分析等以后有时间补上。这个程序在mini2440下直接编译即可运行。我在网上搜索的没有可以直接运行,也许是我分析的不够透彻,因为时间紧迫仅仅看了下大体的结构和自己需要的部分。希望大家多多给写意见和改进措施。
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/major.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>//printk()
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>//u8,u16,u3……
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/sched.h>//和任务相关
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>//copy_to_user(),copy_from_user()
#include <asm/atomic.h>
#include <asm/unistd.h>
#include <linux/spinlock.h>
#include <asm/system.h>
#include <asm/io.h>
//--------------------------------------------------------------------------------------------------------------
#define SPI_NAME "MINI2440_SPI"
static int SPI_MAJOR= 55;
//static int spi_major=0;//主设备号为0表示动态分配主设备号,自定义次设备号。MKDEV()表示主次合并为设备号
struct spi_dev
{
struct cdev cdev;
char dataTx[4];
char dataRx[4];
};
struct spi_dev *spi_devp;
//-------------------------------------------------------------------------------------------------------
//GPG and GPE control register setting
#define GPG_DEFAULT (S3C2410_GPG3_EINT11|S3C2410_GPG6_EINT14|S3C2410_GPG2_nSS0)
#define GPE_DEFAULT (S3C2410_GPE11_SPIMISO0|S3C2410_GPE12_SPIMOSI0|S3C2410_GPE13_SPICLK0)
#define SPI_CON_DEFAULT (0<<0|0<<1|1<<2|1<<3|1<<4|0<<5|0<<6)//具体设置根据情况确定
#define SPI_TXRX_READY ((readl(SPSTA0)&0x1)==0x1)//发送接收标志位判断
//-------------------------------------------------------------------------------------------------------
//GPG GPE SPI address declare
//GPG
#define GPGCON (unsigned long)ioremap(0x56000060,4)
#define GPGDAT (unsigned long)ioremap(0x56000064,4)
#define GPGUP (unsigned long)ioremap(0x56000068,4)
//GPE
#define GPECON (unsigned long)ioremap(0x56000040,4)
#define GPEDAT (unsigned long)ioremap(0x56000044,4)
#define GPEUP (unsigned long)ioremap(0x56000048,4)
//SPI
#define SPCON0 (unsigned long)ioremap(0x59000000,4)
#define SPSTA0 (unsigned long)ioremap(0x59000004,4)
#define SPPIN0 (unsigned long)ioremap(0x59000008,4)
#define SPPRE0 (unsigned long)ioremap(0x5900000c,4)
#define SPTDAT0 (unsigned long)ioremap(0x59000010,1)
#define SPRDAT0 (unsigned long)ioremap(0x59000014,1)
//CLK control
#define CLKCON (unsigned long)ioremap(0x4c00000c,4)
#define SCRPND (unsigned long)ioremap(0x4a000000,4)
#define INTPND (unsigned long)ioremap(0x4a000010,4)
#define INTMSK (unsigned long)ioremap(0x4a000008,4)
//----------------------------------------------------------------------------------------------------------------------------
//mini2440 SPI config
static void mini2440_spi_config(void)
{
unsigned int port_status;
if(!(CLKCON&(1<<18)))
{
port_status=readl(CLKCON);
port_status|=(1<<18);
writel(port_status,CLKCON);//时钟使能
}
port_status=readl(GPGCON);
port_status&=~GPG_DEFAULT;
port_status|=GPG_DEFAULT;//GPG control
writel(port_status,GPGCON);