SPI驱动程序S3C2440.docx
- 文档编号:12815438
- 上传时间:2023-06-08
- 格式:DOCX
- 页数:20
- 大小:23.88KB
SPI驱动程序S3C2440.docx
《SPI驱动程序S3C2440.docx》由会员分享,可在线阅读,更多相关《SPI驱动程序S3C2440.docx(20页珍藏版)》请在冰点文库上搜索。
SPI驱动程序S3C2440
SPI驱动流程(S3C2440)
2007-12-2722:
50:
25
简单的说就是写几个寄存器,其实非常简单的,呵呵
一、配置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),SCKenable(4),master/slave(3),CPOL
(2),CPHA
(1),TAGD(0).具体怎么设置根据自己的需要设置就OK。
3、SPPIN寄存器
就三个寄存器,都设置好后就可以写和接收数据啦
写之前记得要检查SPSTA的REDY位是否为1.
NOTE:
我的配置好IO之后,发现写SPCON寄存器无效,郁闷了两天终于找到原因,就CLKCON寄存器的SPI位没有
激活,所以写寄存器之前记得要检查CLKCON的状态
一点点经验,留个记号,呵呵
代码写的有点乱,测试的时候弄的,不好意思^_^
code:
#ifndefMODULE
#defineMODULE
#endif
#include
#include
#include
#include
#include
#include
#defineGPG_CON0x56000060
#defineGPG_DAT0x56000064
#defineGPG_UP0x56000068
#defineSPCON_10x59000020
#defineSPSTA_10x59000024
#defineSPPIN_10x59000028
#defineSPPRE_10X5900002C
#defineSPTDAT_10x59000030
#defineSPRDAT_10x59000034
#definenSS1(1<<6|1<<7)
#defineSPICLK1(1<<14|1<<15)
#defineSPIMOSI1(1<<12|1<<13)
#defineSPIMISO1(1<<10|1<<11)
#defineSPI_USE(nSS1|SPICLK1|SPIMOSI1|SPIMISO1)
//staticintspi_major;
#definespi_name"S3C2440_SPI"
#definespi_minor1
#ifdefCONFIG_DEVFS_FS
staticdevfs_handle_tdevfs_spi_dir,devfs_spi_raw;
#endif
MODULE_LICENSE("GPL");
#if1
#defineSPI_SPPRE1(*(volatileunsignedlong*)SPPRE1)
#defineSPI_GPGCON(*(volatileunsignedlong*)GPGCON)
#defineSPI_SPCON1(*(volatileunsignedlong*)SPCON1)
#defineSPI_SPSTA1(*(volatileunsignedlong*)SPSTA1)
#defineSPI_SPPIN1(*(volatileunsignedlong*)SPPIN1)
#defineSPI_SPTDAT1(*(volatileunsignedlong*)SPTDAT1)
#defineSPI_SPRDAT1(*(volatileunsignedlong*)SPRDAT1)
#defineSPTDAT1_READ(*(volatileunsignedlong*)SPTDAT1)
#defineSPI_GPGDAT(*(volatileunsignedlong*)GPGDAT)
#defineCLKCON(*(volatileunsignedlong*)ADDR_CLKCON)
#endif
unsignedlongGPGCON;
unsignedlongGPGDAT;
unsignedlongGPGUP;
unsignedlongSPCON1;
unsignedlongSPSTA1;
unsignedlongSPPIN1;
unsignedlongSPPRE1;
unsignedlongSPTDAT1;
unsignedlongSPRDAT1;
unsignedlongADDR_CLKCON;
staticvoidget_sys_addr(void)
{
GPGCON=(unsignedlong)ioremap(GPG_CON,4);
GPGDAT=(unsignedlong)ioremap(GPG_DAT,4);
GPGUP=(unsignedlong)ioremap(GPG_UP,4);
SPCON1=(unsignedlong)ioremap(SPCON_1,4);
SPSTA1=(unsignedlong)ioremap(SPSTA_1,4);
SPPIN1=(unsignedlong)ioremap(SPPIN_1,4);
SPPRE1=(unsignedlong)ioremap(SPPRE_1,4);
SPTDAT1=(unsignedlong)ioremap(SPTDAT_1,4);
SPRDAT1=(unsignedlong)ioremap(SPRDAT_1,4);
ADDR_CLKCON=(unsignedlong)ioremap(0x4c00000c,4);
}
#if1
staticintspi_open(structinode*inode,structfile*filp)
{
unsignedintport_state;
inti=0;
#if1
printk("CLKCON:
%x\n",(unsignedint)CLKCON);
if(!
(CLKCON&(1<<18)))
CLKCON|=(1<<18);
printk("CLKCON:
%x\n",(unsignedint)CLKCON);
port_state=readl(GPGCON);
printk("<1>onlyread:
port_state=%x\n",port_state);
port_state&=~SPI_USE;
port_state|=SPI_USE;
SPI_GPGCON=port_state;
//writel(SPI_USE,GPGCON);
port_state=0x0;
port_state=readl(GPGUP);
port_state&=~(1<<3|1<<5|1<<6|1<<7);
writel(port_state,GPGUP);
#endif
#if1
port_state=readl(SPPRE1);
//writel(value,SPPRE1);
SPI_SPPRE1=0x18;
port_state=readl(SPCON1);
port_state&=~0x03f;
port_state|=(0<<0|0<<1|1<<2|1<<3|1<<4|0<<5);
//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);
//writel(port_state,SPPIN1);
SPI_SPPIN1=(0<<2|1<<1|0<<0);
printk("<1>SPI_SPPIN1=%x\n",(unsignedint)SPI_SPPIN1);
//SPI_GPGDAT&=~1<<3;
printk("SPSTA1=%x\n",readl(SPSTA1));
#if0//usefortestspiwave...
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//testspiwave
#endif
//writel(~(1<<4),SPCON1);//dis-SCK
//printk("<1>istheOPENreadl(GPGUP)=%x\n",readl(GPGUP));
return0;
}
staticintspi_release(structinode*inode,structfile*filp)
{
//MOD_DEC_USE_COUNT;
printk("<1>release\n");
return0;
}
#endif
#if1
staticssize_tspi_write(structfile*filp,constchar*buf,size_tcount,loff_t*f_ops)
{
inti=0;
//intconfig;
charstring;
charstr[20];
char*txStr,*rxStr;
volatilechar*spiTxStr,*spiRxStr;
volatileintendSpiTx;
unsignedintport_state=0;
endSpiTx=0;
spiTxStr="spi123456test";
spiRxStr=str;
txStr=(char*)spiTxStr;
rxStr=(char*)spiRxStr;
#if0//initspiinopen()
port_state=readl(SPPRE1);
writel(0x18,SPPRE1);
printk("<1>spi_write\n");
port_state=readl(SPCON1);
port_state&=~0x07f;
port_state|=(0<<0|0<<1|1<<2|1<<3|1<<4|0<<5);
writel(port_state,SPCON1);
printk("<1>setSPCON1\n");
port_state=readl(SPPIN1);
port_state&=~(1<<0|1<<1|1<<2);
port_state|=(1<<2|0<<1|1<<0);
writel(port_state,SPPIN1);
printk("<1>setSPCON1\n");
#endif//initspiinopen()
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("receivechar=%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>Txstring:
%s\n",txStr);
printk("<1>Rxstring:
%s\n",rxStr);
return0;
}
#endif
staticstructfile_operationsspi_fops={
.owner=THIS_MODULE,
.open=spi_open,
.release=spi_release,
.write=spi_write,
};
staticstructmiscdevicespi_dev=
{
123,
"spi",
&spi_fops,
};
staticint__initspi_init(void)
{
//unsignedintvalue;
//intret;
get_sys_addr();
misc_register(&spi_dev);
#if0
ret=register_chrdev(0,spi_name,&spi_fops);
if(ret<0)
{
printk("<1>cannotgetmajornumber\n");
returnret;
}
spi_major=ret;
#ifdefCONFIG_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),(unsignedint)SPTDAT1_READ);
return0;
}
staticvoid__exitspi_exit(void)
{
#if0
#ifdefCONFIG_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,cruelworld\n");
}
module_init(spi_init);
module_exit(spi_exit);
2410_SPI接口与linux驱动
2.6.18内核下已经添加了完整的spi子系统了,参考mtd的分析,将从下到上层,再从上到下层的对其进行分析。
以下先从下到上的进行分析:
driver/spi下有两个底层相关的spi驱动程序:
spi_s3c24xx.c和spi_s3c24xx_gpio.c
其中spi_s3c24xx.c是基于s3c24xx下相应的spi接口的驱动程序,spi_s3c24xx_gpio.c允许用户指定3个gpio口,分别充当spi_clk、spi_mosi和spi_miso接口,模拟标准的spi总线。
s3c2410自带了两个spi接口(spi0和spi1),在此我只研究基于s3c2410下spi接口的驱动程序spi_s3c24xx.c。
首先从spi驱动的检测函数进行分析:
staticints3c24xx_spi_probe(structplatform_device*pdev)
{
structs3c24xx_spi*hw;
structspi_master*master;
structspi_board_info*bi;
structresource*res;
interr=0;
inti;
master=spi_alloc_master(&pdev->dev,sizeof(structs3c24xx_spi));
if(master==NULL){
dev_err(&pdev->dev,"Nomemoryforspi_master\n");
err=-ENOMEM;
gotoerr_nomem;
}
hw=spi_master_get_devdata(master);
memset(hw,0,sizeof(structs3c24xx_spi));
hw->master=spi_master_get(master);
hw->pdata=pdev->dev.platform_data;
hw->dev=&pdev->dev;
if(hw->pdata==NULL){
dev_err(&pdev->dev,"Noplatformdatasupplied\n");
err=-ENOENT;
gotoerr_no_pdata;
}
platform_set_drvdata(pdev,hw);//dev_set_drvdata(&pdev->dev,hw)
init_completion(&hw->done);
hw->bitbang.master=hw->master;
hw->bitbang.setup_transfer=s3c24xx_spi_setupxfer;
hw->bitbang.chipselect=s3c24xx_spi_chipsel;
hw->bitbang.txrx_bufs=s3c24xx_spi_txrx;
hw->bitbang.master->setup=s3c24xx_spi_setup;
dev_dbg(hw->dev,"bitbangat%p\n",&hw->bitbang);
res=platform_get_resource(pdev,IORESOURCE_MEM,0);
if(res==NULL){
dev_err(&pdev->dev,"CannotgetIORESOURCE_MEM\n");
err=-ENOENT;
gotoerr_no_iores;
}
hw->ioarea=request_mem_region(res->start,(res->end-res->start)+1,
pdev->name);
if(hw->ioarea==NULL){
dev_err(&pdev->dev,"Cannotreserveregion\n");
err=-ENXIO;
gotoerr_no_iores;
}
hw->regs=ioremap(res->start,(res->end-res->start)+1);
if(hw->regs==NULL){
dev_err(&pdev->dev,"CannotmapIO\n");
err=-ENXIO;
gotoerr_no_iomap;
}
hw->irq=platform_get_irq(pdev,0);
if(hw->irq<0){
dev_err(&pdev->dev,"NoIRQspecified\n");
err=-ENOENT;
gotoerr_no_irq;
}
err=request_irq(hw->irq,s3c24xx_spi_irq,0,pdev->name,hw);
if(err){
dev_err(&pdev->dev,"CannotclaimIRQ\n");
gotoerr_no_irq;
}
hw->clk=clk_get(&pdev->dev,"spi");
if(IS_ERR(hw->clk)){
dev_err(&pdev->dev,"Noclockfordevice\n");
err=PTR_ERR(hw->clk);
gotoerr_no_clk;
}
clk_enable(hw->clk);
writeb(0xff,hw->regs+S3C2410_SPPRE);
writeb(SPPIN_DEFAULT,hw->regs+S3C2410_SPPIN);
writeb(SPCON_DEFAULT,hw->regs+S3C2410_SPCON);
s3c2410_gpio_setpin(S3C2410_GPE13,0);
s3c2410_gpio_setpin(S3C2410_GPE12,0);
s3c2410_gpio_cfgpin(S3C2410_GPE13,S3C2410_GPE13_SPICLK0);
s3c2410_gpio_cfgpin(S3C2410_GPE12,S3C2410_GPE12_SPIMOSI0);
s3c2410_
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- SPI 驱动程序 S3C2440