基于S3C2440的嵌入式Linux驱动——SPI子系统解读(二)
扫描二维码
随时随地手机看文章
本文属于第二部分。
4. 主控制器驱动程序
4.1 定义 platform device
下列数据结构位于arch/arm/plat-s3c24XX/devs.c
/*SPI(0)*/
staticstructresources3c_spi0_resource[]={
[0]={
.start=S3C24XX_PA_SPI,
.end=S3C24XX_PA_SPI+0x1f,
.flags=IORESOURCE_MEM,
},
[1]={
.start=IRQ_SPI0,
.end=IRQ_SPI0,
.flags=IORESOURCE_IRQ,
}
};
staticu64s3c_device_spi0_dmamask=0xffffffffUL;
structplatform_devices3c_device_spi0={
.name="s3c2410-spi",
.id=0,
.num_resources=ARRAY_SIZE(s3c_spi0_resource),
.resource=s3c_spi0_resource,
.dev={
.dma_mask=&s3c_device_spi0_dmamask,
.coherent_dma_mask=0xffffffffUL
}
};
platform设备给出了spi0接口的寄存器地址资源以及IRQ资源。注意其设备名为s3c2410-spi。
4.2 定义platform driver
下列函数位于deivers/spi/s3c24xx.c。
MODULE_ALIAS("platform:s3c2410-spi");
staticstructplatform_drivers3c24xx_spi_driver={
.remove=__exit_p(s3c24xx_spi_remove),
.suspend=s3c24xx_spi_suspend,
.resume=s3c24xx_spi_resume,
.driver={
.name="s3c2410-spi",
.owner=THIS_MODULE,
},
};
staticint__inits3c24xx_spi_init(void)
{
returnplatform_driver_probe(&s3c24xx_spi_driver,s3c24xx_spi_probe);//设备不可热插拔,所以使用该函数,而不是platform_driver_register
}
staticvoid__exits3c24xx_spi_exit(void)
{
platform_driver_unregister(&s3c24xx_spi_driver);
}
module_init(s3c24xx_spi_init);
module_exit(s3c24xx_spi_exit);
调用了platform_driver_probe注册platform驱动,注册完成以后将会调用platform的s3c24xx_spi_probe函数。
NOTE:platform驱动的name和platform device的name是相同的。
4.2.1s3c24xx_spi_probe函数
下列函数位于deivers/spi/s3c24xx.c。
staticint__inits3c24xx_spi_probe(structplatform_device*pdev)
{
structs3c2410_spi_info*pdata;
structs3c24xx_spi*hw;
structspi_master*master;
structresource*res;
interr=0;
/*分配master结构体,其中包括s3c24xx_spi结构的内存空间,使用master.dev.driver_data指向它*/
master=spi_alloc_master(&pdev->dev,sizeof(structs3c24xx_spi));
if(master==NULL){
dev_err(&pdev->dev,"Nomemoryforspi_mastern");
err=-ENOMEM;
gotoerr_nomem;
}
/*获得s3c24xx_spi结构,并清0该结构*/
hw=spi_master_get_devdata(master);
memset(hw,0,sizeof(structs3c24xx_spi));
hw->master=spi_master_get(master);/*保存master结构体,同时增加引用计数*/
hw->pdata=pdata=pdev->dev.platform_data;/*获取s3c2410_spi_info结构体指针*/
hw->dev=&pdev->dev;/*保存platform设备的dev*/
if(pdata==NULL){
dev_err(&pdev->dev,"Noplatformdatasuppliedn");
err=-ENOENT;
gotoerr_no_pdata;
}
platform_set_drvdata(pdev,hw);/*让platform_devuce.dev.driver_data指向s3c24xx_spi*/
init_completion(&hw->done);/*初始化completion*/
/*setupthemasterstate.*//*填充master结构体的两个字段*/
master->num_chipselect=hw->pdata->num_cs;
master->bus_num=pdata->bus_num;
/*setupthestateforthebitbangdriver*//*填充bitbang字段*/
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%pn",&hw->bitbang);
/*findandmapourresources*/
res=platform_get_resource(pdev,IORESOURCE_MEM,0);/*获取IO资源*/
if(res==NULL){
dev_err(&pdev->dev,"CannotgetIORESOURCE_MEMn");
err=-ENOENT;
gotoerr_no_iores;
}
hw->ioarea=request_mem_region(res->start,(res->end-res->start)+1,/*申请IO内存*/
pdev->name);
if(hw->ioarea==NULL){
dev_err(&pdev->dev,"Cannotreserveregionn");
err=-ENXIO;
gotoerr_no_iores;
}
hw->regs=ioremap(res->start,(res->end-res->start)+1);/*建立映射*/
if(hw->regs==NULL){