⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s3c2410_spi.c

📁 三星ARM9 2410 SPI接口驱动源代码 for linux 2.4 内核
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
    s3c2410_spi.c - spi driver, char device interface  

    Copyright (C) 2004-06-07  Leequng <leequng@mail.sc.cninfo.net>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/* $Id: s3c2410_spi.c,v 1.0 2004/06/07 01:28:01 mds Exp $ */

#ifndef __KERNEL__
#define __KERNEL__
#endif

#ifndef MODULE
#define MODULE
#endif

#include <linux/config.h>
#include <linux/module.h>

#include <linux/kernel.h>		// printk()
#include <linux/malloc.h>		// kmalloc()
#include <linux/fs.h>			// everything support file struct
#include <linux/errno.h>		// error codes
#include <linux/types.h>		// size_t
#include <linux/proc_fs.h>
#include <linux/ioport.h>               // kernel mem access
#include <linux/fcntl.h>		// O_ACCMODE
#include <asm/system.h>			// cli(), *_flags
#include <asm/io.h>
#include <asm/ioctl.h>
#include <asm/uaccess.h>
#include "s3c2410_spi.h"
#include <linux/init.h>
#include <linux/devfs_fs_kernel.h>

#define SDEBUG
// define macro for debug
#ifdef SDEBUG
  #define SPI_DEBUG(fmt, args...)   printk(fmt, ## args)
#else
  #define SPI_DEBUG(fmt, args...)
#endif


// 定义 SPI 的主设备号
int spi_drv_major=0;
devfs_handle_t dev_handle;
unsigned char conf_val8;
unsigned short int conf_val16;
unsigned int conf_val32;
struct spi_dev My_SPI_Local,*spi_local=&My_SPI_Local;
unsigned char boot[60*1024];
int modem_reset,enable_config;
int powerCTL_EN;

static int spi_baudrate_set(unsigned int spi_channel_num, unsigned int baud_rate)
{
    unsigned char prescaler_val;
    
    prescaler_val = PCLK/2/ baud_rate -1;
    outb(prescaler_val,SPPRE);

    return ACCESS_OK;
}



static int spi_config(unsigned char SelectSM)
{
    // 设置 SPI 工作模式
    conf_val8 = inb(SPCON);
    conf_val8|=(SPCON_SMOD_INT);                         //interrupt rx/tx mode
    if(SelectSM==0){
      conf_val8&=~SPCON_MSTR;                          //slave mode,disable clock
      conf_val8&=~SPCON_ENSCK;                         
    }
    else{
      conf_val8|=SPCON_MSTR;
      conf_val8|=SPCON_ENSCK;                          //master mode,enable clock
    }
    conf_val8&=~(SPCON_CPOL);                 //active low,Format B,Tx auto mode
    conf_val8|=(SPCON_CPHA|SPCON_TAGD);                     
    outb(conf_val8,SPCON);

    return ACCESS_OK;
}


static int spi_pin_config(unsigned int spi_channel_num)
{

    // 设置 SPI 引脚控制寄存器
    conf_val8 = inb(SPPIN);
    conf_val8 &= ~(SPPIN_KEEP|SPPIN_ENMUL);     //disable multi master error detect,release MOSI drive
    conf_val8 |=0x2;                            //set reserve bit=1
    outb(conf_val8,SPPIN);
    return 0;
}


static int spi_open(struct inode *inode, struct file *p_file)
{

    MOD_INC_USE_COUNT;
    printk(KERN_INFO "SPI open....!!\n");  	
    p_file->private_data = spi_local;            // 让 file 的数据字段指向已经分配的数据
    return 0;
	
} // end of static int spi_open



static int spi_close(struct inode *inode, struct file *p_file)
{
    // 得到 spi 接口指针
    SPI_Status=Status_Send_Packet;
    DisInt_SPI;
    MOD_DEC_USE_COUNT;
    printk(KERN_INFO "SPI close!!!\n");  	
    return 0;
	
} // end of static int spi_close

static void BackReverse(struct spi_dev *pdev,unsigned int num)
{
    pdev->recv_buf.size-=num;
    if(pdev->recv_buf.tail-num>=0)
      pdev->recv_buf.tail-=num;
    else
      pdev->recv_buf.tail=BUF_SIZE-num+pdev->recv_buf.tail;
    return;
} 

 
static void powerOff(int irq, void *private, struct pt_regs *regs)
{
      if(powerCTL_EN){
	write_gpio_bit(GPIO_G8,0);
	while(1);
      }
   
      return;
}



volatile unsigned int counter=0,PacketFound=0,prc=0;
volatile unsigned long Tout=0;
volatile int TimeOut;
 
static void spi_intr(int irq, void *private, struct pt_regs *regs)
{
    struct spi_dev *spi_local = private;
    int head,tail;
    
    cli();
    if(!read_gpio_bit(nSS))
      write_gpio_bit(nSS,1);
	if(SPSTA&SPSTA_DCOL)
	  SPI_DEBUG("Data collision\n");
	switch(SPI_Status){
	case Status_Send_Packet:
	  if(HaveSendPacket){                   //如果有包传送,发送/接收中断
	    //		SPI_DEBUG("S");
	    if(spi_local->send_buf.size>0){   //有包,未发送完毕
	      head=spi_local->send_buf.head;
	      write_gpio_bit(nSS,0);
	      while(!(SPSTA&SPSTA_READY));
	      outb(spi_local->send_buf.buffer[head],SPTDAT);
	      spi_local->send_buf.head=(head+1)%BUF_SIZE;
	      spi_local->send_buf.size--;
	      break;
	    }
	    else{//有包,但传送完毕,应是接收中断
	      SPI_DEBUG("\n");
	      HaveSendPacket=NO;
	      if(ADSL_Packet.CmdType!=StopTest&&ADSL_Packet.CmdType!=MasterModeTest&&ADSL_Packet.CmdType!=CalibrateMode){
		SPI_Status=Status_Receive_Packet;
		inb(SPRDAT);
	      }
	      TimeOut=NO;
	      Tout=jiffies+1000*(HZ/100);
	      if(ADSL_Packet.TestType==SPI_ADSL_PSD)
		Tout+=1000*(HZ/100);
	    }
	  }
	  break;
	case Status_Receive_Packet:
	  if((!read_gpio_bit(IO4))||PacketFound){
	    //		SPI_DEBUG("R");
	    write_gpio_bit(nSS,0);
	    while(!(SPSTA&SPSTA_READY));
	    ByteIn=inb(SPRDAT);
	    //		SPI_DEBUG("%2X ",ByteIn);
	    tail=spi_local->recv_buf.tail;
	    switch(RxSta){
	    case RxSta_head55:
	      if(ByteIn==0xaa)
		RxSta=RxSta_headAA;
	      break;
	    case RxSta_headAA:
	      if(ByteIn==0x55)
		RxSta=RxSta_len0;
	      else
		RxSta=RxSta_head55;
	      break;
	    case RxSta_len0:
	      RxCounter=ByteIn;
	      RxSta=RxSta_len1;
	      break;
	    case RxSta_len1:
	      RxCounter=RxCounter+ByteIn*256;
	      RxSta=RxSta_comtype;
	      break;
	    case RxSta_comtype:
	      if(ByteIn!=DataPacket)
		RxSta=RxSta_head55;
	      else
		RxSta=RxSta_testtype;
	      break;
	    case RxSta_testtype:
	      if(ByteIn==CurTestType&&spi_local->recv_buf.size<BUF_SIZE-6){
		PacketFound=1;
		SPI_Status=Status_Receive_Packet;
		RxCounters[RxPacketTail]=RxCounter;
		spi_local->recv_buf.buffer[tail++]=0xaa;
		tail%=BUF_SIZE;
		spi_local->recv_buf.buffer[tail++]=0x55;
		tail%=BUF_SIZE;
		spi_local->recv_buf.buffer[tail++]=RxCounter%256;       //length lower byte
		tail%=BUF_SIZE;
		spi_local->recv_buf.buffer[tail++]=RxCounter/256;       //length high byte
		tail%=BUF_SIZE;
		spi_local->recv_buf.buffer[tail++]=DataPacket;
		tail%=BUF_SIZE;
		spi_local->recv_buf.buffer[tail++]=CurTestType;
		tail%=BUF_SIZE;
		spi_local->recv_buf.tail=tail;
		spi_local->recv_buf.size+=6;
		RxCounter-=6;
		RxSta=RxSta_data;
	      }
	      else
		RxSta=RxSta_head55;
	      break;
	      
	    case RxSta_data:
	      if(!(RxData%15))
		SPI_DEBUG("\n");
	      if(spi_local->recv_buf.size<BUF_SIZE){
		spi_local->recv_buf.buffer[tail++]=ByteIn;
		tail%=BUF_SIZE;
		spi_local->recv_buf.tail=tail;
		spi_local->recv_buf.size++;
		if(!(--RxCounter)){        //complete receive one packet
		  SPI_DEBUG("\nReceive over,not loss data\n");
		  if(RxCounters[RxPacketTail]!=0&&RxPacketNum!=1024){  //未丢失数据
		    RxPacketTail++;
		    RxPacketTail%=1024;
		    RxPacketNum++;
		  }
		  else                            //loss data....
		    BackReverse(spi_local,RxData+6);
		  RxSta=RxSta_head55;
		  SPI_Status=Status_Send_Packet;
		  RxData=0;
		  PacketFound=0;
		  break;
		}
		RxData++;
	      }
	      else{
		SPI_DEBUG("Receive buffer overflow!\n");
		if(!(--RxCounter)){        //complete receive one packet,but loss data
		  SPI_DEBUG("receive over,not loss data\n");
		  RxSta=RxSta_head55;
		  SPI_Status=Status_Send_Packet;
		  BackReverse(spi_local,RxData+6);
		  RxData=0;
		  PacketFound=0;
		}
		RxCounters[RxPacketTail]=0;
	      }
	      break;
	      
	    default:
	      break;
	      
	    }
	  }
	  else{
	    if(Tout<jiffies){
	      SPI_DEBUG("Receive packet time out!\n");
	      RxSta=RxSta_head55;
	      SPI_Status=Status_Send_Packet;
	      RxData=0;
	      HaveSendPacket=NO;
	      PacketFound=0;
	      TimeOut=YES;
	    }
	    inb(SPRDAT);
	  }
	  break;
	  
	default:
	  break;
	}
	sti();
	return ;
} 



// Define file operation set for s3c2410

static struct file_operations spi_fops = 
{
    owner   :  THIS_MODULE,
    open    :  spi_open,
    release :  spi_close,
    ioctl   :  spi_ioctl
};

static int __init spi_init_module(void)
{
    int result;
    modem_reset = 0;
    enable_config = 0;
    powerCTL_EN = 0;
    write_gpio_bit(RESET,1);
    set_gpio_ctrl(RESET|GPIO_MODE_OUT|GPIO_PULLUP_EN);  //Set DSP RESET PIN to Low,output
    write_gpio_bit(IO4,1);
    set_gpio_ctrl(IO4|GPIO_MODE_IN|GPIO_PULLUP_EN);     //Set DSP IO4 as input;
    write_gpio_bit(nSS,1);
    set_gpio_ctrl(nSS|GPIO_MODE_OUT|GPIO_PULLUP_EN);     //Set DSP nSS to High,output;
    
    write_gpio_bit(GPIO_G9,1);                           //2005-5-8
    set_gpio_ctrl(GPIO_G9|GPIO_MODE_IN|GPIO_PULLUP_EN);    //set MODEM ready signal monitor, input;
    
    write_gpio_bit(GPIO_G8,1);
    set_gpio_ctrl(GPIO_G8|GPIO_MODE_OUT|GPIO_PULLUP_EN);    

    write_gpio_bit(GPIO_A21,1);
    set_gpio_ctrl(GPIO_A21|GPIO_MODE_OUT|GPIO_PULLUP_EN);    
    write_gpio_bit(GPIO_G4,1);
    set_gpio_ctrl(GPIO_G4|GPIO_MODE_OUT|GPIO_PULLUP_EN);    
    
    /*
      set_gpio_ctrl(GPIO_G5|GPIO_MODE_SPIMISO|GPIO_PULLUP_EN);
      set_gpio_ctrl(GPIO_G6|GPIO_MODE_SPIMOSI|GPIO_PULLUP_EN);
      set_gpio_ctrl(GPIO_G7|GPIO_MODE_SPICLK|GPIO_PULLUP_EN);
      
    */
    
    set_gpio_ctrl(GPIO_H4|GPIO_MODE_OUT|GPIO_PULLUP_EN);
    //write_gpio_bit(GPIO_H4,0);
    //	Delay10ms(200);
    //write_gpio_bit(GPIO_H4,1);
    
    // 设定 file_operations 结构的 owner 字段
    SET_MODULE_OWNER(&spi_fops);
    SPI_DEBUG("Module SPI is initing!!!\n");  
    // 将 SPI 作为字符设备注册,采用设备文件系统
    result = devfs_register_chrdev(spi_drv_major, "spi_drv", &spi_fops);
    if (result < 0){
      SPI_DEBUG("spi_drv: Couldn't get a major number.\n");
      SPI_DEBUG("spi_drv: Spi driver register failure !\n");
      SPI_DEBUG("spi_drv: Error in calling devfs_register_chrdev\n");
      return result;
    }
    dev_handle=devfs_register(NULL,"spi_drv",DEVFS_FL_DEFAULT,result,0,S_IFCHR,&spi_fops,NULL);
    
    if ( 0 == spi_drv_major )
      spi_drv_major = result;
    
    // 初始化设备中的相关变量(发送缓冲区,接收缓冲区相关数据)
    
    spi_local->send_buf.head = 0;
    spi_local->send_buf.tail = 0;
    spi_local->send_buf.size = 0;
    spi_local->recv_buf.head = 0;
    spi_local->recv_buf.tail = 0;
    spi_local->recv_buf.size = 0;
    // 初始化发送缓冲区和接收缓冲区使用的信号量
    sema_init(&spi_local->send_buf.sem, 1);
    sema_init(&spi_local->recv_buf.sem, 1);
    
    // 注册成功后开始向 SPI 控制寄存器写控制字
	
    // 首先设置通信的波特率
    spi_baudrate_set(0, 2000000);
    
    // 设置 SPI0 的工作模式
    spi_config(1);	
    spi_pin_config(0);
    

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -