基于S3C2440的嵌入式Linux驱动——SPI子系统解读(二)


该系列文章将分为四个部分:

第一部分,将对SPI子系统整体进行描述,同时给出SPI的相关数据结构,最后描述SPI总线的注册。基于S3C2440的嵌入式Linux驱动——SPI子系统解读(一)

第二部分,即本篇文章,该文将对SPI的主控制器(master)驱动进行描述。

第三部分,该文将对SPI设备驱动,也称protocol 驱动,进行讲解。基于S3C2440的嵌入式Linux驱动——SPI子系统解读(三)

第四部分,通过SPI设备驱动留给用户层的API,我们将从上到下描述数据是如何通过SPI的protocol 驱动,由bitbang中转,最后由master驱动将数据传输出去。 基于S3C2440的嵌入式Linux驱动——SPI子系统解读(四)

本文属于第二部分。

4. 主控制器驱动程序

4.1 定义 platform device

下列数据结构位于arch/arm/plat-s3c24XX/devs.c

  1. /* SPI (0) */  
  2.   
  3. static struct resource s3c_spi0_resource[] = {  
  4.     [0] = {  
  5.         .start = S3C24XX_PA_SPI,  
  6.         .end   = S3C24XX_PA_SPI + 0x1f,  
  7.         .flags = IORESOURCE_MEM,  
  8.     },  
  9.     [1] = {  
  10.         .start = IRQ_SPI0,  
  11.         .end   = IRQ_SPI0,  
  12.         .flags = IORESOURCE_IRQ,  
  13.     }  
  14.   
  15. };  
  16.   
  17. static u64 s3c_device_spi0_dmamask = 0xffffffffUL;  
  18.   
  19. struct platform_device s3c_device_spi0 = {  
  20.     .name         = "s3c2410-spi",  
  21.     .id       = 0,  
  22.     .num_resources    = ARRAY_SIZE(s3c_spi0_resource),  
  23.     .resource     = s3c_spi0_resource,  
  24.         .dev              = {  
  25.                 .dma_mask = &s3c_device_spi0_dmamask,  
  26.                 .coherent_dma_mask = 0xffffffffUL  
  27.         }  
  28. };  

platform设备给出了spi0接口的寄存器地址资源以及IRQ资源。注意其设备名为s3c2410-spi。

4.2 定义platform driver

下列函数位于deivers/spi/s3c24xx.c。

  1. MODULE_ALIAS("platform:s3c2410-spi");  
  2. static struct platform_driver s3c24xx_spi_driver = {  
  3.     .remove        = __exit_p(s3c24xx_spi_remove),  
  4.     .suspend    = s3c24xx_spi_suspend,  
  5.     .resume        = s3c24xx_spi_resume,  
  6.     .driver        = {  
  7.         .name    = "s3c2410-spi",  
  8.         .owner    = THIS_MODULE,  
  9.     },  
  10. };  
  11.   
  12. static int __init s3c24xx_spi_init(void)  
  13. {  
  14.         return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);//设备不可热插拔,所以使用该函数,而不是platform_driver_register   
  15. }  
  16.   
  17. static void __exit s3c24xx_spi_exit(void)  
  18. {  
  19.         platform_driver_unregister(&s3c24xx_spi_driver);  
  20. }  
  21.   
  22. module_init(s3c24xx_spi_init);  
  23. module_exit(s3c24xx_spi_exit);  

调用了platform_driver_probe注册platform驱动,注册完成以后将会调用platform的s3c24xx_spi_probe函数。

NOTE:platform驱动的name和platform device的name是相同的。

4.2.1  s3c24xx_spi_probe函数

下列函数位于deivers/spi/s3c24xx.c。

  1. static int __init s3c24xx_spi_probe(struct platform_device *pdev)  
  2. {  
  3.     struct s3c2410_spi_info *pdata;  
  4.     struct s3c24xx_spi *hw;  
  5.     struct spi_master *master;  
  6.     struct resource *res;  
  7.     int err = 0;  
  8.   
  9.     /*分配master结构体,其中包括s3c24xx_spi结构的内存空间,使用master.dev.driver_data指向它*/  
  10.     master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));  
  11.     if (master == NULL) {  
  12.         dev_err(&pdev->dev, "No memory for spi_master\n");  
  13.         err = -ENOMEM;  
  14.         goto err_nomem;  
  15.     }  
  16.     /*获得s3c24xx_spi结构,并清0该结构*/  
  17.     hw = spi_master_get_devdata(master);  
  18.     memset(hw, 0, sizeof(struct s3c24xx_spi));  
  19.       
  20.     hw->master = spi_master_get(master); /*保存master结构体,同时增加引用计数*/  
  21.     hw->pdata = pdata = pdev->dev.platform_data;  /*获取s3c2410_spi_info结构体指针*/  
  22.     hw->dev = &pdev->dev;                 /*保存platform设备的dev*/  
  23.   
  24.     if (pdata == NULL) {  
  25.         dev_err(&pdev->dev, "No platform data supplied\n");  
  26.         err = -ENOENT;  
  27.         goto err_no_pdata;  
  28.     }  
  29.   
  30.     platform_set_drvdata(pdev, hw); /*让platform_device.dev.driver_data 指向 s3c24xx_spi*/  
  31.     init_completion(&hw->done);      /*初始化completion*/  
  32.   
  33.     /* setup the master state. */ /*填充master结构体的两个字段*/  
  34.       
  35.     master->num_chipselect = hw->pdata->num_cs;  
  36.     master->bus_num = pdata->bus_num;  
  37.   
  38.     /* setup the state for the bitbang driver */    /*填充bitbang字段*/  
  39.   
  40.     hw->bitbang.master         = hw->master;            
  41.     hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;  
  42.     hw->bitbang.chipselect     = s3c24xx_spi_chipsel;  
  43.     hw->bitbang.txrx_bufs      = s3c24xx_spi_txrx;  
  44.     hw->bitbang.master->setup  = s3c24xx_spi_setup;  
  45.   
  46.     dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);  
  47.   
  48.     /* find and map our resources */  
  49.   
  50.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);   /*获取IO资源*/  
  51.     if (res == NULL) {  
  52.         dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");  
  53.         err = -ENOENT;  
  54.         goto err_no_iores;  
  55.     }  
  56.   
  57.     hw->ioarea = request_mem_region(res->start, (res->end - res->start)+1,  /*申请IO内存*/  
  58.                     pdev->name);  
  59.   
  60.     if (hw->ioarea == NULL) {  
  61.         dev_err(&pdev->dev, "Cannot reserve region\n");  
  62.         err = -ENXIO;  
  63.         goto err_no_iores;  
  64.     }  
  65.   
  66.     hw->regs = ioremap(res->start, (res->end - res->start)+1);      /*建立映射*/  
  67.     if (hw->regs == NULL) {  
  68.         dev_err(&pdev->dev, "Cannot map IO\n");  
  69.         err = -ENXIO;  
  70.         goto err_no_iomap;  
  71.     }  
  72.   
  73.     hw->irq = platform_get_irq(pdev, 0);         /*获取irq号*/  
  74.     if (hw->irq < 0) {  
  75.         dev_err(&pdev->dev, "No IRQ specified\n");  
  76.         err = -ENOENT;  
  77.         goto err_no_irq;  
  78.     }  
  79.   
  80.     err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw);   /*申请spi中断,ISR为 s3c24xx_spi_irq*/  
  81.     if (err) {  
  82.         dev_err(&pdev->dev, "Cannot claim IRQ\n");  
  83.         goto err_no_irq;  
  84.     }  
  85.   
  86.     hw->clk = clk_get(&pdev->dev, "spi"); /*获取spi时钟*/  
  87.     if (IS_ERR(hw->clk)) {  
  88.         dev_err(&pdev->dev, "No clock for device\n");  
  89.         err = PTR_ERR(hw->clk);  
  90.         goto err_no_clk;  
  91.     }  
  92.   
  93.     /* setup any gpio we can */  
  94.   
  95.     if (!pdata->set_cs) {        /*没有定义分配CS管脚的函数*/  
  96.         if (pdata->pin_cs < 0) {  /*pin_cs为cs管脚*/  
  97.             dev_err(&pdev->dev, "No chipselect pin\n");  
  98.             goto err_register;  
  99.         }  
  100.   
  101.         err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev));/*申请IO地址*/  
  102.         if (err) {  
  103.             dev_err(&pdev->dev, "Failed to get gpio for cs\n");  
  104.             goto err_register;  
  105.         }  
  106.   
  107.         hw->set_cs = s3c24xx_spi_gpiocs; /*给出分配cs管脚函数*/  
  108.         gpio_direction_output(pdata->pin_cs, 1);/*设置该管脚为输出模式*/  
  109.     } else  
  110.         hw->set_cs = pdata->set_cs;  
  111.   
  112.     s3c24xx_spi_initialsetup(hw);   /*spi控制器初始化*/  
  113.   
  114.     /* register our spi controller */  
  115.   
  116.     err = spi_bitbang_start(&hw->bitbang);  
  117.     if (err) {  
  118.         dev_err(&pdev->dev, "Failed to register SPI master\n");  
  119.         goto err_register;  
  120.     }  
  121.   
  122.     return 0;  
  123.   
  124.  err_register:  
  125.     if (hw->set_cs == s3c24xx_spi_gpiocs)  
  126.         gpio_free(pdata->pin_cs);  
  127.   
  128.     clk_disable(hw->clk);  
  129.     clk_put(hw->clk);  
  130.   
  131.  err_no_clk:  
  132.     free_irq(hw->irq, hw);  
  133.   
  134.  err_no_irq:  
  135.     iounmap(hw->regs);  
  136.   
  137.  err_no_iomap:  
  138.     release_resource(hw->ioarea);    /*先释放资源*/  
  139.     kfree(hw->ioarea);               /*再释放空间*/  
  140.   
  141.  err_no_iores:  
  142.  err_no_pdata:  
  143.     spi_master_put(hw->master);; /*减少引用计数*/  
  144.   
  145.  err_nomem:  
  146.     return err;  
  147. }  

该函数首先为spi_master结构体以及s3c24xx_spi结构体分配了空间,同时,spi_master.dev.driver_data指向了s3c24xx_spi。

s3c24xx_spi结构如下:

  1. struct s3c24xx_spi {  
  2.     /* bitbang has to be first */  
  3.     struct spi_bitbang   bitbang;  
  4.     struct completion    done;  
  5.   
  6.     void __iomem        *regs;  
  7.     int          irq;  
  8.     int          len;  
  9.     int          count;  
  10.   
  11.     void            (*set_cs)(struct s3c2410_spi_info *spi,  
  12.                       int cs, int pol);  
  13.   
  14.     /* data buffers */  
  15.     const unsigned char *tx;  
  16.     unsigned char       *rx;  
  17.   
  18.     struct clk      *clk;  
  19.     struct resource     *ioarea;  
  20.     struct spi_master   *master;  
  21.     struct spi_device   *curdev;  
  22.     struct device       *dev;  
  23.     struct s3c2410_spi_info *pdata;  
  24. };  

接着执行了该条语句:

hw->pdata = pdata = pdev->dev.platform_data;    /*获取s3c2410_spi_info结构体指针*/

NOTE:在这里获取platform_device.dev.platform_data,也就是平台设备的相关数据,而在4.1小结中的arch/arm/plat-s3c24XX/devs.c文件中并没有发现platform_data的身影,因此这正式需要我们移植的地方。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 下一页

相关内容