首页 / 操作系统 / Linux / mini2440 spi驱动总结
最近在参考了很多的网络资源后编写调试了在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); port_status=readl(GPECON); port_status&=~GPE_DEFAULT; port_status|=GPE_DEFAULT; writel(port_status,GPECON);//GPE control port_status=0x0; port_status=readl(GPEUP); port_status&=~(1<<13|1<<12|1<<11); writel(port_status,GPEUP);//GPE_UP port_status=0x0; port_status=readl(GPGUP); port_status&=~(1<<2|1<<3|1<<6); writel(port_status,GPGUP);//GPG_UP //disable_irq(IRQ_SPI0); port_status=readl(SPPRE0);//SPI Baud speed port_status=0x31;//PCLK=50MHz SPICLK=PCLK/2/(value+1)=1MHz,对于CC2500最大支持500K,一般采用250K writel(port_status,SPPRE0); port_status=readl(SPCON0); port_status=SPI_CON_DEFAULT; writel(port_status,SPCON0);//SPI control port_status=readl(SPPIN0); port_status&=~(0<<0|1<<1|1<<2); port_status|=(1<<2|1<<1|0<<0); writel(port_status,SPPIN0);//SPI pin setting port_status=readl(SCRPND); port_status|=(1<<22); writel(port_status,SCRPND); port_status=readl(INTPND); port_status|=(1<<22); writel(port_status,INTPND); //enable_irq(IRQ_SPI0); } //----------------------------------------------------------------------------------------------------------------- static int spi_open(struct inode *inode,struct file *filp) { filp->private_data=spi_devp; mini2440_spi_config(); //filep->private_data=spi_devp; s3c2410_gpio_setpin(S3C2410_GPG(2),0); printk("-----------------------------------
"); printk("MINI2440 SPI GPG GPE CLK set over
"); printk("-----------------------------------
"); return 0; }static int spi_release(struct inode *inode,struct file *filp) { printk("-----------------------------
"); printk("S3C2440-mini2440_spi closed
"); printk("------------------------------
"); return 0; } //----------------------------------------------------------------------------------------------------------- static ssize_t spi_read(struct file *filp,char __user *buf,size_t count) { //char *spiRxData; struct spi_dev *dev=filp->private_data; copy_to_user(buf,dev->dataRx,count); return 0; }static ssize_t spi_write(struct file *filp,char __user *buf,size_t count) { volatile int endSpiTx=0; volatile char spiTxData[4]; //int config; int i=0; //char str[20]; //char *txStr,*rxStr; //volatile char *spiTxStr,*spiRxStr; unsigned char string; unsigned int port_status; struct spi_dev *dev=filp->private_data; //filp->private_data; //获得设备结构体的指针 copy_from_user(dev->dataTx,buf,count); for(i=0;i<4;i++) { spiTxData[i]=dev->dataTx[i]; } printk("receive form user is %s
",spiTxData); while(endSpiTx==0) { //if(*spiTxData!=" ") while(!SPI_TXRX_READY) printk("SPI TXRX unready
"); for(i=0;i<4;i++) { //s3c2410_gpio_setpin(S3C2410_GPG(2),0);//使能从SPI writeb(spiTxData[i],SPTDAT0);//=*(spiTxData++); string=readb(SPTDAT0); printk("transfer char=%c
",string); //while(!SPI_TXRX_READY); dev->dataRx[i]=readb(SPRDAT0); printk("----------------------------
"); printk("receive char=%c
",dev->dataRx[i]); printk("----------------------------
"); //s3c2410_gpio_setpin(S3C2410_GPG(2),1);//解除使能从SPI //i++; } endSpiTx=1; } port_status=readl(SPCON0); port_status|=((0<<5)|(0<<4)|(1<<3)|(1<<2)|(0<<1)|(0<<0)); writel(port_status,SPCON0); return 0; } //--------------------------------------------------------------------------------------------------------------- static const struct file_operations spi_fops={ .owner=THIS_MODULE, .open=spi_open, .release=spi_release, .read=spi_read, .write=spi_write, }; static void spi_interrupt(int irq,void *dev_id,struct pt_regs *reg) { unsigned int port_status; unsigned int i=0; volatile int endSpiRx=0; port_status=readl(SCRPND); port_status|=(1<<22); writel(port_status,SCRPND); port_status=readl(INTPND); port_status|=(1<<22); writel(port_status,INTPND); //SCRPND|=(1<<22); //INTPND|=(1<<22); disable_irq(IRQ_SPI0); // SPCON0|=(0<<6)|(0<<5)|(0<<4)|(0<<3)|(1<<2)|(0<<1)|(1<<0); while(endSpiRx==0) { while (!SPI_TXRX_READY); writeb(0xff,SPTDAT0); while(!SPI_TXRX_READY); spi_devp->dataRx[i]=SPRDAT0; i++; if(i>4) { endSpiRx=1; } } port_status=readl(SPCON0); port_status|=((0<<6)|(1<<5)|(0<<4)|(1<<3)|(1<<2)|(0<<1)|(0<<0)); writel(port_status,SPCON0); enable_irq(IRQ_SPI0); printk("SPI irq end
"); } static void spi_setup_cdev(struct spi_dev *dev,int index) { int err,devno=MKDEV(SPI_MAJOR,index); cdev_init(&dev->cdev,&spi_fops); //cdev_init(&spi_dev,&spi_fops); dev->cdev.owner=THIS_MODULE; dev->cdev.ops=&spi_fops; err=cdev_add(&dev->cdev,devno,1); if(err) printk("error
"); printk("-----------------------------------
"); } static int __init spi_init(void) { int ret; dev_t devno=MKDEV(SPI_MAJOR,0); if(SPI_MAJOR)//申请设备号 ret=register_chrdev_region(devno,1,SPI_NAME); else//动态申请设备号 { ret=alloc_chrdev_region(&devno,0,1,SPI_NAME); SPI_MAJOR=MAJOR(devno); } if(ret<0) return ret; //动态申请设备结构体的内存 spi_devp=kmalloc(sizeof(struct spi_dev),GFP_KERNEL); if(!spi_devp)//申请失败 { ret=-ENOMEM; goto fail_malloc; } memset(spi_devp,0,sizeof(struct spi_dev)); spi_setup_cdev(spi_devp,0); printk("init spi success
"); return 0; fail_malloc: unregister_chrdev_region(devno,1); return ret; } static void __exit spi_exit(void) { free_irq(IRQ_SPI0,NULL); unregister_chrdev(SPI_MAJOR,SPI_NAME); } //----------------------------------------------------------------------------------------------------------------------- module_init(spi_init); module_exit(spi_exit);MODULE_LICENSE("GPL"); MODULE_AUTHOR("Gflytu"); MODULE_DESCRIPTION("SPI DRIVER FOR MINI_S3C2440");
收藏该网址