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

来源:互联网 发布:投资 知乎 编辑:程序博客网 时间:2024/04/28 16:12
该系列文章将分为四个部分:

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

   第二部分,该文将对SPI的主控制器(master)驱动进行描述。          基于S3C2440的嵌入式Linux驱动——SPI子系统解读(二)

   第三部分,该文将对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

[html] view plaincopy
  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。

[cpp] view plaincopy
  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。

[cpp] view plaincopy
  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_devuce.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); /*设置该管脚为输出,貌似多次一举,在probe已经调用过该函数*/    
  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. }  

[cpp] view plaincopy
  1. /** 
  2.  * spi_alloc_master - allocate SPI master controller 
  3.  * @dev: the controller, possibly using the platform_bus 
  4.  * @size: how much zeroed driver-private data to allocate; the pointer to this 
  5.  *  memory is in the driver_data field of the returned device, 
  6.  *  accessible with spi_master_get_devdata(). 
  7.  * Context: can sleep 
  8.  * 
  9.  * This call is used only by SPI master controller drivers, which are the 
  10.  * only ones directly touching chip registers.  It's how they allocate 
  11.  * an spi_master structure, prior to calling spi_register_master(). 
  12.  * 
  13.  * This must be called from context that can sleep.  It returns the SPI 
  14.  * master structure on success, else NULL. 
  15.  * 
  16.  * The caller is responsible for assigning the bus number and initializing 
  17.  * the master's methods before calling spi_register_master(); and (after errors 
  18.  * adding the device) calling spi_master_put() to prevent a memory leak. 
  19.  */  
  20. struct spi_master *spi_alloc_master(struct device *dev, unsigned size)  
  21. {  
  22.     struct spi_master   *master;  
  23.   
  24.     if (!dev)  
  25.         return NULL;  
  26.   
  27.     master = kzalloc(size + sizeof *master, GFP_KERNEL);  
  28.     if (!master)  
  29.         return NULL;  
  30.   
  31.     device_initialize(&master->dev);  
  32.     master->dev.class = &spi_master_class;  
  33.     master->dev.parent = get_device(dev);  
  34.     spi_master_set_devdata(master, &master[1]);  
  35.   
  36.     return master;  
  37. }  
  38. EXPORT_SYMBOL_GPL(spi_alloc_master);  

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

 s3c24xx_spi结构如下:

[cpp] view plaincopy
  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的身影,因此这正式需要我们移植的地方。

  随后初始化了completion,这个东东将用于实现同步I/O,详见下文。之后,为master定义了setup方法,为bitbang定义了3个方法。

  接着获取了一系列的资源,同时注册了中断服务程序。接着调用s3c24xx_spi_initialsetup初始化控制器。我们来看下该函数。

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

[cpp] view plaincopy
  1. static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw)  
  2. {  
  3.     /* for the moment, permanently enable the clock */  
  4.   
  5.     clk_enable(hw->clk);     /*使能时钟*/  
  6.   
  7.     /* program defaults into the registers */  
  8.   
  9.     writeb(0xff, hw->regs + S3C2410_SPPRE);  /*设置预分频系数,baudrate=pclk/2/(prescaler value+1)*/  
  10.     writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);/*使能master out keep*/  
  11.     writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);/*master, interrupt mode*/  
  12.   
  13.     if (hw->pdata) {  
  14.         if (hw->set_cs == s3c24xx_spi_gpiocs)      /*set_cs 在probe方法中设置为s3c24xx_spi_gpiocs*/  
  15.             gpio_direction_output(hw->pdata->pin_cs, 1);  /*设置该管脚为输出,貌似多次一举,在probe已经调用过该函数*/      
  16. */  
  17.         if (hw->pdata->gpio_setup)  
  18.             hw->pdata->gpio_setup(hw->pdata, 1);         
  19.     }  
  20. }  
注意,这里设置了SPI0主控制器工作在master方式,使用中断模式。

最后调用了spi_bitbang_start函数,该函数非常重要,在下一小节中单独讲解。

4.2.2 spi_bitbang_start函数

  下列函数位于drivers/spi/spi_bitbang.c

[cpp] view plaincopy
  1. /** 
  2.  * spi_bitbang_start - start up a polled/bitbanging SPI master driver 
  3.  * @bitbang: driver handle 
  4.  * 
  5.  * Caller should have zero-initialized all parts of the structure, and then 
  6.  * provided callbacks for chip selection and I/O loops.  If the master has 
  7.  * a transfer method, its final step should call spi_bitbang_transfer; or, 
  8.  * that's the default if the transfer routine is not initialized.  It should 
  9.  * also set up the bus number and number of chipselects. 
  10.  * 
  11.  * For i/o loops, provide callbacks either per-word (for bitbanging, or for 
  12.  * hardware that basically exposes a shift register) or per-spi_transfer 
  13.  * (which takes better advantage of hardware like fifos or DMA engines). 
  14.  * 
  15.  * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup, 
  16.  * spi_bitbang_cleanup and spi_bitbang_setup_transfer to handle those spi 
  17.  * master methods.  Those methods are the defaults if the bitbang->txrx_bufs 
  18.  * routine isn't initialized. 
  19.  * 
  20.  * This routine registers the spi_master, which will process requests in a 
  21.  * dedicated task, keeping IRQs unblocked most of the time.  To stop 
  22.  * processing those requests, call spi_bitbang_stop(). 
  23.  */  
  24. int spi_bitbang_start(struct spi_bitbang *bitbang)  
  25. {  
  26.     int status;  
  27.   
  28.     if (!bitbang->master || !bitbang->chipselect)  
  29.         return -EINVAL;  
  30.   
  31.     INIT_WORK(&bitbang->work, bitbang_work); /*初始化工作,工作为bitbang_work*/  
  32.     spin_lock_init(&bitbang->lock);              /*初始化自旋锁*/  
  33.     INIT_LIST_HEAD(&bitbang->queue);         /*初始化链表头,链表为双向循环链表*/  
  34.   
  35.     if (!bitbang->master->transfer)   /*master的transfer方法没有定义过*/  
  36.         bitbang->master->transfer = spi_bitbang_transfer; /*使用spi_bitbang_transfe方法*/  
  37.     if (!bitbang->txrx_bufs) {       /*如果bitbang没有txrx_bufs方法,在probe函数中定义过该方法*/  
  38.         bitbang->use_dma = 0;  
  39.         bitbang->txrx_bufs = spi_bitbang_bufs;  
  40.         if (!bitbang->master->setup) {  
  41.             if (!bitbang->setup_transfer)  
  42.                 bitbang->setup_transfer =  
  43.                      spi_bitbang_setup_transfer;  
  44.             bitbang->master->setup = spi_bitbang_setup;  
  45.             bitbang->master->cleanup = spi_bitbang_cleanup;  
  46.         }  
  47.     } else if (!bitbang->master->setup)   /*setup方法在probe函数中有定义*/  
  48.         return -EINVAL;  
  49.   
  50.     /* this task is the only thing to touch the SPI bits */  
  51.     bitbang->busy = 0;  
  52.     bitbang->workqueue = create_singlethread_workqueue(      /*创建工作队列*/  
  53.             dev_name(bitbang->master->dev.parent));  
  54.     if (bitbang->workqueue == NULL) {  
  55.         status = -EBUSY;  
  56.         goto err1;  
  57.     }  
  58.   
  59.     /* driver may get busy before register() returns, especially 
  60.      * if someone registered boardinfo for devices 
  61.      */  
  62.     status = spi_register_master(bitbang->master);   /*注册spi控制器*/  
  63.     if (status < 0)  
  64.         goto err2;  
  65.   
  66.     return status;  
  67.   
  68. err2:  
  69.     destroy_workqueue(bitbang->workqueue);  
  70. err1:  
  71.     return status;  
  72. }  
  73. EXPORT_SYMBOL_GPL(spi_bitbang_start);  
  在这里,定义了控制器的transfer方法为spi_bitbang_transfer。创建了一个工作队列和一个工作bitbang_work,同时创建了一个链表。这些东东的作用将在后面介绍。

  最后,调用了spi_register_master函数,该函数将完成SPI控制器的注册,其中还牵涉到spi_device的注册。因此该函数也非常重要。我们来看看这个函数

  下列函数位于drivers/spi/spi_bitbang.c

[cpp] view plaincopy
  1. /** 
  2.  * spi_register_master - register SPI master controller 
  3.  * @master: initialized master, originally from spi_alloc_master() 
  4.  * Context: can sleep 
  5.  * 
  6.  * SPI master controllers connect to their drivers using some non-SPI bus, 
  7.  * such as the platform bus.  The final stage of probe() in that code 
  8.  * includes calling spi_register_master() to hook up to this SPI bus glue. 
  9.  * 
  10.  * SPI controllers use board specific (often SOC specific) bus numbers, 
  11.  * and board-specific addressing for SPI devices combines those numbers 
  12.  * with chip select numbers.  Since SPI does not directly support dynamic 
  13.  * device identification, boards need configuration tables telling which 
  14.  * chip is at which address. 
  15.  * 
  16.  * This must be called from context that can sleep.  It returns zero on 
  17.  * success, else a negative error code (dropping the master's refcount). 
  18.  * After a successful return, the caller is responsible for calling 
  19.  * spi_unregister_master(). 
  20.  */  
  21. int spi_register_master(struct spi_master *master)  
  22. {  
  23.     static atomic_t     dyn_bus_id = ATOMIC_INIT((1<<15) - 1);  
  24.     struct device       *dev = master->dev.parent;  
  25.     int         status = -ENODEV;  
  26.     int         dynamic = 0;  
  27.   
  28.     if (!dev)  
  29.         return -ENODEV;  
  30.   
  31.     /* even if it's just one always-selected device, there must 
  32.      * be at least one chipselect 
  33.      */  
  34.     if (master->num_chipselect == 0)  
  35.         return -EINVAL;  
  36.   
  37.     /* convention:  dynamically assigned bus IDs count down from the max */  
  38.     if (master->bus_num < 0) {  
  39.         /* FIXME switch to an IDR based scheme, something like 
  40.          * I2C now uses, so we can't run out of "dynamic" IDs 
  41.          */  
  42.         master->bus_num = atomic_dec_return(&dyn_bus_id);  
  43.         dynamic = 1;  
  44.     }  
  45.   
  46.     /* register the device, then userspace will see it. 
  47.      * registration fails if the bus ID is in use. 
  48.      */  
  49.     dev_set_name(&master->dev, "spi%u", master->bus_num);  
  50.     status = device_add(&master->dev);   /*注册设备*/  
  51.     if (status < 0)  
  52.         goto done;  
  53.     dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),  
  54.             dynamic ? " (dynamic)" : "");  
  55.   
  56.     /* populate children from any spi device tables */  
  57.     scan_boardinfo(master);  
  58.     status = 0;  
  59. done:  
  60.     return status;  
  61. }  
  62. EXPORT_SYMBOL_GPL(spi_register_master);  

   该函数中,执行了相关的检查,然后注册了master设备,随后调用了scan_boardinfo。函数如下:

   下列函数位于drivers/spi/spi.c

[cpp] view plaincopy
  1. /* FIXME someone should add support for a __setup("spi", ...) that 
  2.  * creates board info from kernel command lines 
  3.  */  
  4.   
  5. static void scan_boardinfo(struct spi_master *master)  
  6. {  
  7.     struct boardinfo    *bi;  
  8.   
  9.     mutex_lock(&board_lock);  
  10.     /*以board_list为链表头,遍历所有的boardinfo结构,链表由spi_register_board_info添加*/  
  11.     list_for_each_entry(bi, &board_list, list) {      
  12.         struct spi_board_info    *chip = bi->board_info;  
  13.         unsigned        n;  
  14.         /*遍历该boardinfo指向的spi_board_info数组*/  
  15.         for (n = bi->n_board_info; n > 0; n--, chip++) {  
  16.             if (chip->bus_num != master->bus_num) /*通过bus_num对spi设备和master进行匹配*/  
  17.                 continue;  
  18.             /* NOTE: this relies on spi_new_device to 
  19.              * issue diagnostics when given bogus inputs 
  20.              */  
  21.              /*执行到此,表示匹配完成,SPI设备由该SPI接口来控制,开始创建spi_device*/  
  22.             (void) spi_new_device(master, chip);  
  23.         }  
  24.     }  
  25.     mutex_unlock(&board_lock);  
  26. }  

  NOTE:这个函数通过boardinfo遍历的spi_board_info数组,而spi_board_info是在内核初始化过程中由spi_register_board_info进行注册的,在

               linux/arch/arm/mach-s3c2440/mach-smdk2440.c中并没有调用过该函数,因此这也是需要移植的地方。

  S3C2440共有两个接口:spi0和spi1。chip->bus_num表示该设备使用哪个spi接口,而master->bus_num正好表示了当前的接口。

  该函数中,遍历spi_board_info,通过bus_num完成SPI设备和SPI控制器的匹配,匹配成功则开始建立spi_device设备,该过程通过调用spi_new_device实现。我们接着看下这个函数。

  下列函数位于drivers/spi/spi.c

[cpp] view plaincopy
  1. /** 
  2.  * spi_new_device - instantiate one new SPI device 
  3.  * @master: Controller to which device is connected 
  4.  * @chip: Describes the SPI device 
  5.  * Context: can sleep 
  6.  * 
  7.  * On typical mainboards, this is purely internal; and it's not needed 
  8.  * after board init creates the hard-wired devices.  Some development 
  9.  * platforms may not be able to use spi_register_board_info though, and 
  10.  * this is exported so that for example a USB or parport based adapter 
  11.  * driver could add devices (which it would learn about out-of-band). 
  12.  * 
  13.  * Returns the new device, or NULL. 
  14.  */  
  15. struct spi_device *spi_new_device(struct spi_master *master,  
  16.                   struct spi_board_info *chip)  
  17. {  
  18.     struct spi_device   *proxy;  
  19.     int         status;  
  20.   
  21.     /* NOTE:  caller did any chip->bus_num checks necessary. 
  22.      * 
  23.      * Also, unless we change the return value convention to use 
  24.      * error-or-pointer (not NULL-or-pointer), troubleshootability 
  25.      * suggests syslogged diagnostics are best here (ugh). 
  26.      */  
  27.   
  28.     proxy = spi_alloc_device(master);   /*分配spi_device结构,并初始化一些字段*/  
  29.     if (!proxy)  
  30.         return NULL;  
  31.   
  32.     WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));  
  33.     /*从spi_board_info获取SPI从设备的参数*/  
  34.     proxy->chip_select = chip->chip_select;  
  35.     proxy->max_speed_hz = chip->max_speed_hz;  
  36.     proxy->mode = chip->mode;  
  37.     proxy->irq = chip->irq;  
  38.     strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));  
  39.     proxy->dev.platform_data = (void *) chip->platform_data;  
  40.     proxy->controller_data = chip->controller_data;  
  41.     proxy->controller_state = NULL;  
  42.   
  43.     status = spi_add_device(proxy);  
  44.     if (status < 0) {  
  45.         spi_dev_put(proxy);  
  46.         return NULL;  
  47.     }  
  48.   
  49.     return proxy;  
  50. }  
  51. EXPORT_SYMBOL_GPL(spi_new_device);  
  52.    

   首先,创建了spi_device结构,让后通过板级信息spi_board_info将SPI从设备的相关信息复制给spi_device结构,从而完成了spi_device结构的定义,最后调用spi_add_device,完成spi_device的注册。

   看下spi_add_device函数,该函数位于drivers/spi/spi.c

[cpp] view plaincopy
  1. /** 
  2.  * spi_add_device - Add spi_device allocated with spi_alloc_device 
  3.  * @spi: spi_device to register 
  4.  * 
  5.  * Companion function to spi_alloc_device.  Devices allocated with 
  6.  * spi_alloc_device can be added onto the spi bus with this function. 
  7.  * 
  8.  * Returns 0 on success; negative errno on failure 
  9.  */  
  10. int spi_add_device(struct spi_device *spi)  
  11. {  
  12.     static DEFINE_MUTEX(spi_add_lock);  
  13.     struct device *dev = spi->master->dev.parent;  
  14.     int status;  
  15.   
  16.     /* Chipselects are numbered 0..max; validate. */  
  17.     if (spi->chip_select >= spi->master->num_chipselect) {  
  18.         dev_err(dev, "cs%d >= max %d\n",  
  19.             spi->chip_select,  
  20.             spi->master->num_chipselect);  
  21.         return -EINVAL;  
  22.     }  
  23.   
  24.     /* Set the bus ID string */  
  25.     dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),  
  26.             spi->chip_select);  
  27.   
  28.   
  29.     /* We need to make sure there's no other device with this 
  30.      * chipselect **BEFORE** we call setup(), else we'll trash 
  31.      * its configuration.  Lock against concurrent add() calls. 
  32.      */  
  33.     mutex_lock(&spi_add_lock);  
  34.   
  35.     if (bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev))  
  36.             != NULL) {  
  37.         dev_err(dev, "chipselect %d already in use\n",  
  38.                 spi->chip_select);  
  39.         status = -EBUSY;  
  40.         goto done;  
  41.     }  
  42.   
  43.     /* Drivers may modify this initial i/o setup, but will 
  44.      * normally rely on the device being setup.  Devices 
  45.      * using SPI_CS_HIGH can't coexist well otherwise... 
  46.      */  
  47.     status = spi->master->setup(spi); /*调用setup方法,即s3c24xx_spi_setup函数*/  
  48.     if (status < 0) {  
  49.         dev_err(dev, "can't %s %s, status %d\n",  
  50.                 "setup", dev_name(&spi->dev), status);  
  51.         goto done;  
  52.     }  
  53.   
  54.     /* Device may be bound to an active driver when this returns */  
  55.     status = device_add(&spi->dev);        /*注册SPI_device*/  
  56.     if (status < 0)  
  57.         dev_err(dev, "can't %s %s, status %d\n",  
  58.                 "add", dev_name(&spi->dev), status);  
  59.     else  
  60.         dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));  
  61.   
  62. done:  
  63.     mutex_unlock(&spi_add_lock);  
  64.     return status;  
  65. }  
  66. EXPORT_SYMBOL_GPL(spi_add_device);  

  在注册spi_device之前,调用了master的setup方法,该方法又将调用s3c24xx_spi_setupxfer和s3c24xx_spi_chipsel函数。

  s3c24xx_spi_setupxfer函数计算预分频系数并写入寄存器。

  s3c24xx_spi_chipsel函数用于禁止或使能CS信号。当使能CS信号时,要设置控制寄存器。这里调用是禁止CS信号。

  下列代码位于deivers/spi/s3c24xx.c。
[cpp] view plaincopy
  1. #define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT)  
  2. #define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP)  
  3.   
  4. static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev)  
  5. {  
  6.     return spi_master_get_devdata(sdev->master);  
  7. }  
  8.   
  9. static void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol)  
  10. {  
  11.     gpio_set_value(spi->pin_cs, pol);  
  12. }  
  13.   
  14. static void s3c24xx_spi_chipsel(struct spi_device *spi, int value)  
  15. {  
  16.     struct s3c24xx_spi *hw = to_hw(spi);  
  17.     unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;  
  18.     unsigned int spcon;  
  19.   
  20.     switch (value) {  
  21.     case BITBANG_CS_INACTIVE:   /*CS无效时*/  
  22.         hw->set_cs(hw->pdata, spi->chip_select, cspol^1);/*即调用s3c24xx_spi_gpiocs使CS无效*/  
  23.         break;  
  24.   
  25.     case BITBANG_CS_ACTIVE:     /*CS有效时*/  
  26.         spcon = readb(hw->regs + S3C2410_SPCON); /*获取目前SPCON寄存器的值*/  
  27.   
  28.         /*开始设置工作模式*/  
  29.         if (spi->mode & SPI_CPHA)      
  30.             spcon |= S3C2410_SPCON_CPHA_FMTB;  
  31.         else  
  32.             spcon &= ~S3C2410_SPCON_CPHA_FMTB;  
  33.   
  34.         if (spi->mode & SPI_CPOL)  
  35.             spcon |= S3C2410_SPCON_CPOL_HIGH;  
  36.         else  
  37.             spcon &= ~S3C2410_SPCON_CPOL_HIGH;  
  38.         /*激活时钟sck输出*/  
  39.         spcon |= S3C2410_SPCON_ENSCK;  
  40.   
  41.         /* write new configration */  
  42.   
  43.         writeb(spcon, hw->regs + S3C2410_SPCON); /*保存新的配置*/  
  44.         hw->set_cs(hw->pdata, spi->chip_select, cspol);/*即调用s3c24xx_spi_gpiocs使CS有效*/  
  45.   
  46.         break;  
  47.     }  
  48. }  
  49.   
  50. static int s3c24xx_spi_setupxfer(struct spi_device *spi,  
  51.                  struct spi_transfer *t)  
  52. {  
  53.     struct s3c24xx_spi *hw = to_hw(spi);  
  54.     unsigned int bpw;  
  55.     unsigned int hz;  
  56.     unsigned int div;  
  57.   
  58.     /*没有transfer,则使用spi_device进行配置*/  
  59.     bpw = t ? t->bits_per_word : spi->bits_per_word;  
  60.     hz  = t ? t->speed_hz : spi->max_speed_hz;  
  61.   
  62.     if (bpw != 8) {  
  63.         dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);  
  64.         return -EINVAL;  
  65.     }  
  66.   
  67.     div = clk_get_rate(hw->clk) / hz;  
  68.   
  69.     /* is clk = pclk / (2 * (pre+1)), or is it 
  70.      *    clk = (pclk * 2) / ( pre + 1) */  
  71.     /*计算预分频系数*/  
  72.     div /= 2;  
  73.   
  74.     if (div > 0)  
  75.         div -= 1;  
  76.   
  77.     if (div > 255)   /*只有8位*/  
  78.         div = 255;  
  79.   
  80.     dev_dbg(&spi->dev, "setting pre-scaler to %d (hz %d)\n", div, hz);  
  81.     writeb(div, hw->regs + S3C2410_SPPRE);   /*设置预分频系数*/  
  82.   
  83.     spin_lock(&hw->bitbang.lock); /*自旋锁加锁*/  
  84.     if (!hw->bitbang.busy) {     /*如果不忙*/  
  85.         hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);/*即调用s3c24xx_spi_chipsel使CS无效*/  
  86.         /* need to ndelay for 0.5 clocktick ? */  
  87.     }  
  88.     spin_unlock(&hw->bitbang.lock);  
  89.   
  90.     return 0;  
  91. }  
  92.   
  93. /* the spi->mode bits understood by this driver: */  
  94. #define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)  
  95.   
  96. static int s3c24xx_spi_setup(struct spi_device *spi) /*maser.setup方法*/  
  97. {  
  98.     int ret;  
  99.   
  100.     if (!spi->bits_per_word)  
  101.         spi->bits_per_word = 8;  /*没有设置则使用8位*/  
  102.   
  103.     if (spi->mode & ~MODEBITS) { /*检查mode是否有错*/  
  104.         dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",  
  105.             spi->mode & ~MODEBITS);  
  106.         return -EINVAL;  
  107.     }  
  108.   
  109.     ret = s3c24xx_spi_setupxfer(spi, NULL);  
  110.     if (ret < 0) {  
  111.         dev_err(&spi->dev, "setupxfer returned %d\n", ret);  
  112.         return ret;  
  113.     }  
  114.   
  115.     dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n",  
  116.         __func__, spi->mode, spi->bits_per_word,  
  117.         spi->max_speed_hz);  
  118.   
  119.     return 0;  
  120. }  

至此,在probe函数中, 由spi_bitbang_start调用所引起的一系列函数调用都已讲解完毕。下面总结下整个调用过程:

  可以看到,调用spi_bitbang_start以后,spi_master和spi_device都将被注册到内核中。

  下面来看下platform driver的其他几个方法。

4.2.3 remove,suspend以及resume方法

[cpp] view plaincopy
  1. static int __exit s3c24xx_spi_remove(struct platform_device *dev)  
  2. {  
  3.     struct s3c24xx_spi *hw = platform_get_drvdata(dev);  
  4.   
  5.     platform_set_drvdata(dev, NULL);  
  6.   
  7.     spi_unregister_master(hw->master);   /*注销spi主控制器*/  
  8.   
  9.     clk_disable(hw->clk);            /*禁止时钟*/  
  10.     clk_put(hw->clk);            /*释放CLK*/  
  11.   
  12.     free_irq(hw->irq, hw);           /*注销IRQ*/  
  13.     iounmap(hw->regs);           /*解除映射*/  
  14.   
  15.     if (hw->set_cs == s3c24xx_spi_gpiocs)  
  16.         gpio_free(hw->pdata->pin_cs); /*释放用于cs的gpio*/  
  17.   
  18.     release_resource(hw->ioarea);  
  19.     kfree(hw->ioarea);                     
  20.   
  21.     spi_master_put(hw->master);      /*减少master引用计数*/  
  22.     return 0;  
  23. }  
  24.   
  25.   
  26. #ifdef CONFIG_PM    /*如果定义了电源管理*/  
  27.   
  28. static int s3c24xx_spi_suspend(struct platform_device *pdev, pm_message_t msg)  
  29. {  
  30.     struct s3c24xx_spi *hw = platform_get_drvdata(pdev);  
  31.   
  32.     if (hw->pdata && hw->pdata->gpio_setup)  
  33.         hw->pdata->gpio_setup(hw->pdata, 0);  
  34.   
  35.     clk_disable(hw->clk);  
  36.     return 0;  
  37. }  
  38.   
  39. static int s3c24xx_spi_resume(struct platform_device *pdev)  
  40. {  
  41.     struct s3c24xx_spi *hw = platform_get_drvdata(pdev);  
  42.   
  43.     s3c24xx_spi_initialsetup(hw);  
  44.     return 0;  
  45. }  
  46.   
  47. #else  
  48. #define s3c24xx_spi_suspend NULL  
  49. #define s3c24xx_spi_resume  NULL  
  50. #endif  
  至此,master 驱动的大体结构都已分析完毕,随后第三篇文章将介绍spi设备驱动
0 0
原创粉丝点击