Tiny6410 SPI驱动源码

/******************************************** 
 *说明:本实验是针对tiny6410的SPI驱动程序   * 
 *      简单读取操作        * 
 *内核选取:linux-2.6.38                    * 
 *硬件要求:SPI1 MISO和MOSI互联                 * 
 *写作时间:2014/6/10                       * 
 *编辑作者:gflytu@163.com                          * 
********************************************/  
  
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>


#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>


#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/regs-timer.h>
#include <plat/regs-adc.h>
  
                                                     
#define SPI_NAME "tiny6410_spi1"  
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;  
static void __iomem *base_addr0;  
static void __iomem *base_addr1;  
static void __iomem *base_addr2;  
static void __iomem *base_addr3;   
//IO 物理地址  
#define S3C6410_PCLK    0x7e00f034  
#define S3C6410_SCLK    0x7e00f038  
#define S3C6410_GPC     0x7f008040  
#define S3C6410_SPI     0x7f00c000  
  
//S3C6410_CLKCON 部分  
#define SPI_PCLK    (*(volatile unsigned long *)(base_addr0 + 0x00))  
#define SPI_SCLK    (*(volatile unsigned long *)(base_addr1 + 0x00))  
//GPC 控制寄存器部分   
//GPC 11、12、13 脚分别对应SPI的MISO、MOSI、CLK 端口  
#define GPCCON      (*(volatile unsigned long *)(base_addr2 + 0x00))  
#define GPCDAT      (*(volatile unsigned long *)(base_addr2 + 0x04))  
#define GPCUP       (*(volatile unsigned long *)(base_addr2 + 0x08))  
  
//SPI 控制寄存器部分          
#define CH_CFG      (*(volatile unsigned long *)(base_addr3 + 0x00))  
#define CLK_CFG     (*(volatile unsigned long *)(base_addr3 + 0x04))  
#define MODE_CFG    (*(volatile unsigned long *)(base_addr3 + 0x08))  
#define SLAVE_SEL   (*(volatile unsigned long *)(base_addr3 + 0x0c))  
#define SPI_INT_EN  (*(volatile unsigned long *)(base_addr3 + 0x10))  
#define SPI_STATUS  (*(volatile unsigned long *)(base_addr3 + 0x14))  
#define SPI_TX_DATA (*(volatile unsigned long *)(base_addr3 + 0x18))  
#define SPI_RX_DATA (*(volatile unsigned long *)(base_addr3 + 0x1c))  
#define PACKET_CNT  (*(volatile unsigned long *)(base_addr3 + 0x20))  
#define SWAP_CONFIG (*(volatile unsigned long *)(base_addr3 + 0x28))  
  
//打开SPI RX TX 通道  
#define SPI_TXRX_ON()       (CH_CFG |=  0x3)  
#define SPI_TXRX_OFF()      (CH_CFG &= ~0x3)  
  
//SPI 输入输出的判忙状态引脚  
//#define SPI_TX_READY        (((SPI_STATUS) & 0x1) == 0x1)  
//#define SPI_RX_READY        (((SPI_STATUS >> 1) & 0x1) == 0x1)  
  
#define SPI_TX_DONE         (((SPI_STATUS >> 21) & 0x1) == 0x1)  
  
#define SPI_CS_LOW()        (SLAVE_SEL &= ~0x01)  //有效选择
#define SPI_CS_HIGH()       (SLAVE_SEL |=  0x01)  //无效选择
 


/********************************************************/  
static void delay(unsigned int i)  
{  
    volatile unsigned int x = 0;  
    for(; x < i; x++);  
}  
static void spi_init_function(void)  
{  
    //使能GPC 11、12、13对应的 MISO0,MOSI0,SCK0 = 11 0x0000FC00*/  
    GPCCON &= ~((7 << 16) | (7 << 20) | (7 << 24) | (7 << 28));  
    GPCCON |=  ((2 << 16) | (2 << 20) | (2 << 24) | (2 << 28));  
      
    //GPCUP 设置;全部disable  
    GPCUP  &=  ~(0xff << 0);  
    //GPCDAT 设置位0  
    GPCDAT &=  ~(0xff << 0);  
  
    //使能时钟控制寄存器CLKCON 21位使能SPI0  
    SPI_PCLK |= (1 << 22);  
    SPI_SCLK |= (1 << 21);  
  
    printk("s3c6410_pclk=%08lu\n",SPI_PCLK);  
    printk("s3c6410_sclk=%08lu\n",SPI_SCLK);  
    /*SPI 寄存器部分*/  
    //高速模式关闭 选择主控 以及传递方式  
    CH_CFG   = ((0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2));  
    //设置PCLK模式 enable CLK 以及频率设置  
    CLK_CFG  = ((0 << 9) | (1 << 8) | (0x20 << 0));  
    //  
    MODE_CFG = ((0 << 29) | (0 << 19) | (0 << 17) | (1 << 11) | (1 << 5)   
                                        | (0 << 2) | (0 << 1) | (0 << 0));  
    SLAVE_SEL   = (0x01);  
    SPI_INT_EN  = (0x00);  
    PACKET_CNT  = (1 << 16);  
    //SWAP_CONFIG = ((0 << 4) | (1 << 5) | (0 << 0) | (1 << 1));  
}  
static int spi_open(struct inode *inode,struct file *filp)  
{  
filp->private_data=spi_devp;
spi_init_function();  
    //SPI_TXRX_ON();  
printk("-----------------------------------\n");
printk("tiny6410 SPI Init  over!\n");
printk("-----------------------------------\n");
    return 0;  
}  
   
   
static int spi_release(struct inode *inode,struct file *filp)  
{  
    //释放掉在写函数操作里面申请的缓存空间  
    printk("SPI1 release OK!\n");  
    return 0;  
}  
#if 1   
//向SPI寄存器SPI_SPTDAT1中写数据   
static void writeByte(const char data)  
{  
    volatile int j = 0; 
//printk("write data is %c\n",data);
    SPI_TX_DATA = data;  
    while(!SPI_TX_DONE);  
    //for(j = 0; j < 0xff; j++);  
}  
  
//从SPI寄存器SPI_SPRDAT1中读取数据  
static char readByte(void)  
{  
    char ch = 0;  
    ch = SPI_RX_DATA;  
    return ch;  
}  
static void write_buffer(const char *datatx,char *datarx, int count)  
{  
    int i;  
    struct spi_dev *dev; 
    //启动SPI的TX RX通道  
    SPI_TXRX_ON();  
    SPI_CS_LOW();  
    delay(100);  
//writeByte(reg);
    //从info中读取数据  
    for(i=0; i < count; i++){  
        writeByte(datatx[i]); 
delay(1000);  
datarx[i]=readByte();
printk("receive data %d is %c\n",i,datarx[i]);
        delay(1000);  
    }  
    //关掉SPI的通道  
    SPI_CS_HIGH();  
    SPI_TXRX_OFF(); 
}  
static void clear_info(void)  
{  
    int count = 0;  
    int i = 0;  
    count =(SPI_STATUS >> 13) & 0x7f;  
    printk("In clear_info RX_INFO_SIZE is:%d\n",count);  
    //释放掉无关的数据  
    for(i = 0; i < count; i++)  
        printk("clear info %d is:%02X\n", i, readByte());  
}  
#endif  
  
//接收数据并把数据发送到应用空间  
static ssize_t spi_read(struct file *filp,char __user *buf,size_t count)  
{  
struct spi_dev *dev=filp->private_data;
/*volatile char spiRxData[4];
int i;
for(i=0;i<4;i++)
{
if((SPI_INT_EN>>1)&0x1)
dev->dataRx[i]=readByte();
spiRxData[i]=dev->dataRx[i];
printk("read data %d is %c\n",i,dev->dataRx[i]);
}*/
copy_to_user(buf,dev->dataRx,count);
return 0;/* struct spi_dev *dev=filp->private_data;
int i;
int count1=0;
//启动SPI的TX RX通道  
    SPI_TXRX_ON();  
    SPI_CS_LOW();  
    //delay(5000);  
    clear_info(); 
count1 =(PACKET_CNT) & 0xff;  
    printk("RX_INFO_SIZE is:%d\n",count1);  
if(count1) {  
        //从RX_INFO寄存器中读取数据  
        for(i = 0; i < 4; i++) {  
            dev->dataRx[i] = readByte();  
            //data = (data << 8) +(unsigned long)save_data;  
            printk("dev->dataRx=%02X\n",dev->dataRx[i]);  
        }  
    }else {  
        count1 = 0;  
    }  
copy_to_user(buf,dev->dataRx,count);
    //关掉SPI的通道  
    SPI_CS_HIGH();  
    SPI_TXRX_OFF();


    return 0;   */
}  
//发送数据并把数据从用户空间发送到内核  
static ssize_t spi_write(struct file *filp,const char __user *buf,  
                                            size_t count)  

volatile int endSpiTx=0;
//volatile char spiTxData[4];
//int config;
int i=0;
//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);
write_buffer(dev->dataTx,dev->dataRx,count);
printk("receive form user is %s\n",dev->dataTx); 
    return 0;  
}  


static const struct file_operations spi_fops =  
{  
    .owner          = THIS_MODULE,  
    .open           = spi_open,  
    .read           = spi_read,  
    .release        = spi_release,  
    .write          = spi_write,   
};  
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\n");
printk("-----------------------------------\n");
}
  
static int __init spi_init(void)  
{  
    int ret;  
//映射时钟控制寄存器CLKCON   
    if((base_addr0 = ioremap(S3C6410_PCLK, 0x04)) == NULL){  
        printk(" base_addr0 ioremap failed\n");  
        return -1;  
    }  
    //映射部分  
    if((base_addr1 = ioremap(S3C6410_SCLK, 0x04)) == NULL){  
        printk(" base_addr1 ioremap failed\n");  
        return -1;  
    }      
    //映射GPC 寄存器地址  
    if((base_addr2 = ioremap(S3C6410_GPC, 0x10)) == NULL){  
        printk(" base_addr2 ioremap failed\n");  
        return -1;  
    }  
  
    //映射SPI 寄存器地址  
    if((base_addr3 = ioremap(S3C6410_SPI, 0x30)) == NULL){  
        printk(" base_addr3 ioremap failed\n");  
        return -1;  
    }  
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!\n");
return 0;
fail_malloc:
unregister_chrdev_region(devno,1);
return ret;
}  
  
static void __exit spi_exit(void)  
{  
unregister_chrdev(SPI_MAJOR,SPI_NAME);  
}  
   
module_init(spi_init);  
module_exit(spi_exit);  
   
MODULE_LICENSE("GPL");  
MODULE_AUTHOR("GFLYTU");
MODULE_DESCRIPTION("SPI_DRIVRE");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值