简单的说就是写几个寄存器,其实非常简单的,呵呵
一、配置IO脚为SPI接口
我用的是(s3c2440)SPI1通道,所有的IO都在GPG脚上,故配置的是GPGCON,
将对应的位置为SPI
然后是GPGUP寄存器
二、开始SPI寄存器的配置
1、
SPPRE,设置传送频率,即SPICLK的频率
SPI_CLK=PCLK/2/(
SPPRE+1)
根据S3C2440的资料,PCLK=48M,我要配置SPI_CLK为 1M,
1=48/2/(
SPPRE+1)=>
SPPRE=23=>
SPPRE=0x18
(个人理解,有错请指出,呵呵)
2、SPCON 寄存器
该寄存器有 7
位,对应的控制包括:SPIMOD(6:5),SCK enable (4),master/slave
(3),CPOL(2),CPHA(1),TAGD(0).具体怎么设置根据自己的需要设置就OK。
3、SPPIN 寄存器
就三个寄存器,都设置好后就可以写和接收数据 啦
写之前记得要检查SPSTA的 REDY位是否为 1 .
NOTE:
我的配置好IO之后,发现写SPCON寄存器无效,郁闷了两天终于找到原因,就CLKCON寄存器的SPI位没有
激活,所以写寄存器之前记得要检查CLKCON的状态
一点点经验,留个记号,呵呵
代码写的有点乱,测试的时候弄的,不好意思^_^
code :
/************************************************/
#ifndef
MODULE
#define MODULE
#endif
#include
#include
#include
#include
#include
#include
/*---------- spi
---------------*/
/*----------------- addr ---------- note
--------*/
#define GPG_CON 0x56000060 /* port G control */
#define
GPG_DAT 0x56000064 /* port G data */
#define GPG_UP 0x56000068
/* pull up port G control */
#define SPCON_1 0x59000020 /*SPI1
control */
#define SPSTA_1 0x59000024 /* SPI1 status */
#define
SPPIN_1 0x59000028 /* SPI1 pin control */
#define SPPRE_1 0X5900002C /* spi1 baud
rate prescaler */
#define SPTDAT_1 0x59000030 /* spi1 Tx data
*/
#define SPRDAT_1 0x59000034 /* spi1 Rx data */
/* GPGCON */
#define nSS1 (1<<6 | 1<<7)
/* GPG3 */
#define SPICLK1 (1<<14 | 1<<15) /*
GPG7 */
#define SPIMOSI1 (1<<12 | 1<<13) /* GPG6
*/
#define SPIMISO1 (1<<10 | 1<<11) /* GPG5
*/
#define SPI_USE (nSS1 | SPICLK1 | SPIMOSI1
|SPIMISO1)
//static int spi_major;
#define spi_name
"S3C2440_SPI"
#define spi_minor 1
#ifdef
CONFIG_DEVFS_FS
static devfs_handle_t
devfs_spi_dir,devfs_spi_raw;
#endif
MODULE_LICENSE("GPL");
#if
1
#define SPI_SPPRE1
(*(volatile unsigned long *)SPPRE1) /* spi1 baud rate prescaler
*/
#define SPI_GPGCON (*(volatile unsigned long *)GPGCON) /*
port-G control */
#define SPI_SPCON1 (*(volatile unsigned long
*)SPCON1) /* spi1 control */
#define SPI_SPSTA1 (*(volatile
unsigned long *)SPSTA1) /* spi1 status */
#define SPI_SPPIN1
(*(volatile unsigned long *)SPPIN1) /* spi1 pin control */
#define
SPI_SPTDAT1 (*(volatile unsigned long *)SPTDAT1) /* spi1 Tx data
*/
#define SPI_SPRDAT1 (*(volatile unsigned long *)SPRDAT1) /*
spi1 Rx data */
#define SPTDAT1_READ (*(volatile unsigned long
*)SPTDAT1) /* spi1 Tx data */
#define SPI_GPGDAT (*(volatile
unsigned long *)GPGDAT) /* port-G data */
#define CLKCON
(*(volatile unsigned long *)ADDR_CLKCON)
#endif
unsigned long
GPGCON;
unsigned long GPGDAT;
unsigned long
GPGUP;
unsigned long SPCON1;
unsigned long
SPSTA1;
unsigned long SPPIN1;
unsigned long SPPRE1;
unsigned long
SPTDAT1;
unsigned long SPRDAT1;
unsigned long ADDR_CLKCON;
static
void get_sys_addr(void)
{
GPGCON =(unsigned
long)ioremap(GPG_CON,4);
GPGDAT =(unsigned
long)ioremap(GPG_DAT,4);
GPGUP =(unsigned long)ioremap(GPG_UP,4);
SPCON1 =(unsigned long)ioremap(SPCON_1,4);
SPSTA1 =(unsigned
long)ioremap(SPSTA_1,4);
SPPIN1 =(unsigned
long)ioremap(SPPIN_1,4);
SPPRE1 =(unsigned long)ioremap(SPPRE_1,4);
SPTDAT1=(unsigned
long)ioremap(SPTDAT_1,4);
SPRDAT1=(unsigned
long)ioremap(SPRDAT_1,4);
ADDR_CLKCON=(unsigned long
)ioremap(0x4c00000c,4);
}
#if 1
static int spi_open(struct inode
*inode,struct file *filp)
{
unsigned int port_state;
int
i=0;
#if 1
/*=============== start init spi regiser ============*/
/* 时钟使能 */
printk("CLKCON: %x \n",(unsigned int )CLKCON);
if
(!(CLKCON&(1<<18)))
CLKCON|=(1<<18);
printk("CLKCON: %x \n",(unsigned int )CLKCON);
/* 配置IO 脚为 SPI
*/
port_state = readl(GPGCON);
printk("<1>only read
:port_state= %x \n",port_state);
port_state &= ~SPI_USE;
port_state |= SPI_USE;
/* printk("<1>port_state= %x
\n",port_state); */
SPI_GPGCON = port_state;
//
writel(SPI_USE,GPGCON);
/* printk("<1> after write :readl(GPGCON)=
%x \n",SPI_GPGCON); */
/* IO 脚使能 */
port_state=0x0;
port_state = readl(GPGUP);
/* printk("<1> GPGUP before write: %x
\n",port_state); */
port_state &=~(1<<3 | 1<<5 |
1<<6 | 1<<7);
writel(port_state,GPGUP);
/*
printk("<1>after write :GPGUP= %x \n",readl(GPGUP)); */
#endif
#if 1
port_state = readl(SPPRE1);
//
writel(value,SPPRE1); /* if
PCLK=50MHz PCLK/2/(value+1) =SPICLK */
SPI_SPPRE1=0x18; /* set Baud rate 1M
.get it in net.note: PCLE=48MHz ,SPICLK=48/2/(0x18+1)=1M */
/*
set spi module */
/* printk("<1>before write :readl(SPCON1)=%x
\n",readl(SPCON1)); */
port_state = readl(SPCON1);
port_state &= ~0x03f;
port_state |= (0<<0 | 0<<1 |
1<<2 | 1<<3 | 1<<4 | 0<<5 );
/* 0<<0
normal mode , 0<<1 format A,1<<2 active low ,1<<3
master
* 1<<4 SCK enable (master only), 0<<5 polling
mode
*/
// writel(port_state,SPCON1);
SPI_SPCON1=(0<<0 | 0<<1 | 1<<2 | 1<<3 | 1<<4 |
0<<5 );
port_state = readl(SPPIN1);
port_state
&= ~(1<<0 | 1<<1 | 1<<2);
port_state |= (0<<2
| 1<<1 | 0<<0);
/* 0<<0:release 1<<1:SBO
0<<2:dis-ENMUL*/
// writel(port_state,SPPIN1);
SPI_SPPIN1=(0<<2 | 1<<1 | 0<<0);
printk("<1>SPI_SPPIN1 = %x \n",(unsigned int )SPI_SPPIN1);
//
SPI_GPGDAT &= ~1<<3;
printk("SPSTA1=%x
\n",readl(SPSTA1));
/*================== end init spiregister
=========================*/
#if 0 // use for test spi wave ...
while (1)
{
// printk("<1> readl(SPSTA1)&0X01: %x
\n",readl(SPSTA1)&0x01);
if (readl(SPSTA1)&0x01)
{
SPTDAT1_READ=0x1234;
// writel(a,SPTDAT1);
//
SPI_SPTDAT1='a';
}
printk("<1>writel \n");
//
printk("<1>readl(SPRDAT1)=%x \n",readl(SPRDAT1));
printk("<1>
readl(SPTDAT1)=%s \n",readl(SPTDAT1));
i++;
//
printk("<1>readl(SPRDAT1)=%c \n",readl(SPRDAT1));
//
printk("<1> readl(SPTDAT1)=%c \n",readl(SPTDAT1));
}
#endif
// test spi wave
#endif
// writel(~(1<<4),SPCON1);//
dis-SCK
// printk("<1>is the OPEN readl(GPGUP)=%x
\n",readl(GPGUP));
return 0;
}
static int
spi_release(struct inode *inode,struct file *filp)
{
//
MOD_DEC_USE_COUNT;
printk("<1> release \n");
return
0;
}
#endif
#if 1
static ssize_t spi_write(struct file *filp,const
char *buf,size_t count,loff_t *f_ops)
{
int i=0;
// int
config;
char string;
char str[20];
char
*txStr,*rxStr;
volatile char *spiTxStr,*spiRxStr;
volatile int
endSpiTx;
unsigned int port_state=0;
endSpiTx=0;
spiTxStr="spi123456test";
spiRxStr=str;
txStr=(char
*)spiTxStr;
rxStr=(char *)spiRxStr;
/* Determine SPI clock
rate.
* Baud rate = PCLK / 2 / (Prescaler value + 1)
* Baud rate <
25 M HZ
* */
#if 0 // init spi in open ()
port_state =
readl(SPPRE1);
writel(0x18,SPPRE1); /* SPPRE1= 0x18 ,Baud rate = 1MHz
*/
printk("<1> spi_write\n");
/* set spi
module */
port_state = readl(SPCON1);
port_state &=
~0x07f;
port_state |= (0<<0 | 0<<1 | 1<<2 | 1<<3
| 1<<4 | 0<<5);
/* 0<<0 normal mode , 0<<1
format A,1<<2 active low ,1<<3 master
* 1<<4 SCK
enable (master only), 0<<5 | 0<<6 polling mode
*/
writel(port_state,SPCON1);
printk("<1>set
SPCON1\n");
/* SPI : master,nSS pin :multi-master error */
port_state = readl(SPPIN1);
port_state &= ~(1<<0 | 1<<1 |
1<<2);
port_state |= (1<<2 | 0<<1 | 1<<0);
/* 1<<0: Drive the previous level; 1<<2:Multi master error detect
enable*/ writel(port_state,SPPIN1);
printk("<1>set SPCON1
\n");
#endif // init spi in open()
while (endSpiTx == 0)
{
printk("SPSTA1=%x \n",readl(SPSTA1));
if((readl(SPSTA1)
& 0X01) == 0)
{
if (*spiTxStr != '\0')
{
writel(*spiTxStr,SPTDAT1);
string =
readl(SPTDAT1);
spiTxStr++;
}
else
{
endSpiTx=1;
}
str[i]=readl(SPRDAT1);
printk("receive char = %c
\n",str[i]);
i++;
}
}
port_state =
readl(SPCON1);
port_state &= ~0x07f;
port_state |= (0<<1
| 0<<1 | 1<<2 | 0<<4 | 0<<5 );
writel(port_state,SPCON1);
*(spiRxStr-1)='\0';
printk("<1>
Tx string : %s \n",txStr);
printk("<1> Rx string : %s
\n",rxStr);
return 0;
}
#endif
static struct
file_operations spi_fops ={
.owner = THIS_MODULE,
.open =
spi_open,
.release = spi_release,
.write =
spi_write,
};
static struct miscdevice spi_dev=
{
123,
"spi",
&spi_fops,
};
static int __init
spi_init(void)
{
// unsigned int value;
// int ret;
get_sys_addr();
misc_register(&spi_dev);
#if 0
ret =
register_chrdev(0,spi_name,&spi_fops);
if(ret<0)
{
printk("<1> cannot get major number \n");
return
ret;
}
spi_major=ret;
#ifdef CONFIG_DEVFS_FS
devfs_spi_dir = devfs_mk_dir(NULL,"spi",NULL);
devfs_spi_raw =
devfs_register(devfs_spi_dir,"0",DEVFS_FL_DEFAULT,spi_major,spi_minor,S_IFCHR |
S_IRUSR | S_IWUSR,&spi_fops,NULL);
#endif
#endif
printk(KERN_ALERT "hello,world \n");
printk("<1> readl(SPTDAT1)=%x
, SPTDAT1_READ = %x \n",readl(SPTDAT1),(unsigned int)SPTDAT1_READ);
return 0;
}
static void __exit spi_exit(void)
{
#if 0
#ifdef
CONFIG_DEVFS_FS
devfs_unregister(devfs_spi_raw);
devfs_unregister(devfs_spi_dir);
#endif
unregister_chrdev(spi_major,spi_name);
#endif
misc_deregister(&spi_dev);
printk(KERN_ALERT "goodbye ,cruel world
\n");
}
module_init(spi_init);
module_exit(spi_exit);