1. 程式人生 > >Linux spi驅動分析(一)----匯流排驅動

Linux spi驅動分析(一)----匯流排驅動

一、SPI匯流排驅動介紹

        SPI匯流排總共需要四根線,包括MOSI、MISO、CLK和CS。本文首先從SPI設備註冊開始來講述SPI匯流排驅動。

二、設備註冊

        在系統啟動的時候,會按照順序執行一些初始化程式,比如device_initcall和module_init等巨集。這些巨集是按照順序執行的,
比如device_initcall的優先順序高於module_init,現在我們看下在系統啟動的時候註冊的spi裝置資訊。

        程式如下:

點選(此處)摺疊或開啟

  1. /* SPI controller */
  2. #if defined(CONFIG_GSC3280_SPI)
  3. #ifdef CONFIG_SPI1
  4. static struct resource spi1_resources[] = {
  5.         [0] = {
  6.                 .start    = GSC3280_SPI1_BASEADDR & 0x1fffffff,
  7.                 .end    = (GSC3280_SPI1_BASEADDR & 0x1fffffff)+ 0x54 - 1 ,
  8.                 .flags    = IORESOURCE_MEM,

  9.         },
  10.         [1] = {
  11.                 .start    = EXT_GSC3280_SPI1_IRQ,
  12.                 .end    = EXT_GSC3280_SPI1_IRQ,
  13.                 .flags    = IORESOURCE_IRQ,
  14.         },
  15. };
  16. static struct platform_device gsc3280_spi1_device = {
  17.         .name            = "gsc3280-spi",
  18.         .id                =
    1,
  19. #ifdef CONFIG_GSC3280_SPI_DMA
  20.         .dev            = {
  21.         .dma_mask            = NULL,
  22.         .coherent_dma_mask    = DMA_BIT_MASK(32),
  23.         .platform_data        = NULL,
  24.         },
  25. #endif
  26.         .resource        = spi1_resources,
  27.         .num_resources    = ARRAY_SIZE(spi1_resources),
  28. };
  29. #endif
  30. /* SPI devices */
  31. #if defined(CONFIG_SPI_FLASH_W25Q)
  32.  static struct gsc3280_spi_info w25q_spi1_dev_platdata = {
  33.     .pin_cs            = 87,
  34.     .num_cs            = 1,
  35.     .cs_value            = 0,
  36.     .lsb_flg            = 0,
  37.     .bits_per_word    = 8,
  38. };
  39. #endif
  40. static struct spi_board_info gsc3280_spi_devices[] = {
  41. #if defined(CONFIG_SPI_FLASH_W25Q)
  42.     {
  43.         .modalias        = "spi-w25q",
  44.         .bus_num        = 1,
  45.         .chip_select        = 3,
  46.         .mode            = SPI_MODE_3,
  47.         .max_speed_hz    = 5 * 1000 * 1000,
  48.         .controller_data    = &w25q_spi1_dev_platdata,
  49.     },
  50. #endif
  51. };
  52. static int __init gsc3280_spi_devices_init(void)
  53. {
  54.     spi_register_board_info(gsc3280_spi_devices, ARRAY_SIZE(gsc3280_spi_devices));
  55.     return 0;
  56. }
  57. device_initcall(gsc3280_spi_devices_init);
  58. #endif    //end #if defined(CONFIG_GSC3280_SPI)
        注意到此處共定義兩個裝置,使用spi_register_board_info()函式對spi裝置進行註冊,程式如下:

點選(此處)摺疊或開啟

  1. int __init
  2. spi_register_board_info(struct spi_board_info const *info, unsigned n)
  3. {
  4.     struct boardinfo *bi;
  5.     int i;
  6.     bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
  7.     if (!bi)
  8.         return -ENOMEM;
  9.     for (i = 0; i < n; i++, bi++, info++) {
  10.         struct spi_master *master;
  11.         memcpy(&bi->board_info, info, sizeof(*info));
  12.         mutex_lock(&board_lock);
  13.         list_add_tail(&bi->list, &board_list);
  14.         list_for_each_entry(master, &spi_master_list, list)
  15.             spi_match_master_to_boardinfo(master, &bi->board_info);
  16.         mutex_unlock(&board_lock);
  17.     }
  18.     return 0;
  19. }

        對於此處,n為1,在程式中首先建立相應的記憶體,在for迴圈中,將資訊儲存到記憶體中,然後插入board_list連結串列,接著遍歷
spi_master_list連結串列,注意此處,由於device_initcall
的優先順序高於module_init,所以此時spi_master_list連結串列為空,那麼還
不能呼叫spi_match_master_to_boardinfo函式建立spi裝置,具體的建立裝置將在spi匯流排驅動的探測函式中,使用spi_register_master()
函式建立裝置。

三、匯流排驅動探測、退出和電源管理函式

3.1、探測函式gsc3280_spi_probe

    程式如下:

點選(此處)摺疊或開啟

  1. static int __init gsc3280_spi_probe(struct platform_device *pdev)
  2. {
  3.     int ret = 0;
  4.     struct gsc3280_spi *gscs;
  5.     struct spi_master *master;
  6.     struct resource *mem, *ioarea;
  7.     DBG("############\n");
  8.     DBG("gsc3280 spi probe start\n");
  9.     master = spi_alloc_master(&pdev->dev, sizeof(struct gsc3280_spi));
  10.     if (!master) {
  11.         ret = -ENOMEM;
  12.         DBG("!!!!spi_alloc_master error\n");
  13.         goto exit;
  14.     }
  15.     gscs = spi_master_get_devdata(master);
  16.     memset(gscs, 0, sizeof(struct gsc3280_spi));
  17.     gscs->master = spi_master_get(master);
  18.     mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  19.     if (!mem) {
  20.         DBG("!!!!no mem resource!\n");
  21.         ret = -EINVAL;
  22.         goto err_kfree;
  23.     }
  24.     ioarea = request_mem_region(mem->start, resource_size(mem), pdev->name);
  25.     if (!ioarea) {
  26.         DBG("!!!!SPI region already claimed!\n");
  27.         ret = -EBUSY;
  28.         goto err_kfree;
  29.     }
  30.     gscs->regs = ioremap_nocache(mem->start, resource_size(mem));
  31.     if (!gscs->regs) {
  32.         DBG("!!!!SPI ioremap error!\n");
  33.         ret = -ENOMEM;
  34.         goto err_release_reg;
  35.     }
  36.     DBG("gscs->regs = 0x%p\n", gscs->regs);
  37.     gscs->irq = platform_get_irq(pdev, 0);
  38.     if (gscs->irq < 0) {
  39.         DBG("!!!!no irq resource!\n");
  40.         ret = gscs->irq;
  41.         goto err_unmap;
  42.     }
  43.     ret = request_irq(gscs->irq, gsc3280_spi_irq, IRQF_DISABLED, dev_name(&pdev->dev), gscs);
  44.     if (ret < 0) {
  45.         DBG("!!!!can not get IRQ!\n");
  46.         goto err_irq;
  47.     }
  48.     gscs->clk = clk_get(NULL, "spi1");
  49.     if (IS_ERR(gscs->clk)) {
  50.         DBG("!!!!failed to find spi1 clock source!\n");
  51.         ret = PTR_ERR(gscs->clk);
  52.         goto err_irq;
  53.     }
  54.     gscs->max_freq = clk_get_rate(gscs->clk);
  55.     DBG("rate is %d\n", gscs->max_freq);
  56.     clk_enable(gscs->clk);
  57.     gscs->bus_num = pdev->id;
  58.     gscs->num_cs = 4;
  59.     gscs->prev_chip = NULL;
  60.     INIT_LIST_HEAD(&gscs->queue);
  61.     spin_lock_init(&gscs->slock);
  62. #ifdef CONFIG_GSC3280_SPI_DMA
  63.     gscs->dma_priv = pdev->dev.platform_data = &spi_platform_data;
  64.     if (!gscs->dma_priv)
  65.         goto err_clk;    //return -ENOMEM;
  66.     gscs->dma_ops = &gscs_dma_ops;
  67.     gscs->dma_inited = 0;
  68.     gscs->dma_addr = (dma_addr_t)(gscs->regs + 0x24) & 0x1fffffff;
  69. #endif
  70.     platform_set_drvdata(pdev, master);
  71.     master->mode_bits = SPI_CPOL | SPI_CPHA;
  72.     master->bus_num = gscs->bus_num;
  73.     master->num_chipselect = gscs->num_cs;
  74.     master->cleanup = gsc3280_spi_cleanup;
  75.     master->setup = gsc3280_spi_setup;
  76.     master->transfer = gsc3280_spi_transfer;
  77.     gsc3280_spi_hw_init(gscs);
  78. #ifdef CONFIG_SPI_GSC3280_DMA
  79.     if (gscs->dma_ops && gscs->dma_ops->dma_init) {
  80.         ret = gscs->dma_ops->dma_init(gscs);
  81.         if (ret) {
  82.             dev_warn(&master->dev, "DMA init failed\n");
  83.             gscs->dma_inited = 0;
  84.         }
  85.     }
  86. #endif
  87.     ret = gsc3280_init_queue(gscs);
  88.     if (ret != 0) {
  89.         DBG("!!!!problem initializing queue!\n");
  90.         goto err_diable_hw;
  91.     }
  92.     ret = gsc3280_start_queue(gscs);
  93.     if (ret != 0) {
  94.         DBG("!!!!problem starting queue!\n");
  95.         goto err_queue_alloc;
  96.     }
  97.     ret = spi_register_master(master);
  98.     if (ret != 0) {
  99.         DBG("!!!!register spi master error!\n");
  100.         goto err_queue_alloc;
  101.     }
  102.     DBG("gsc3280 spi probe success\n");
  103.     DBG("############\n");
  104.     return 0;
  105. //err_free_master:
  106.     //spi_master_put(master);
  107. err_queue_alloc:
  108.     gsc3280_spi_destroy_queue(gscs);
  109. #ifdef CONFIG_SPI_GSC3280_DMA
  110.     if (gscs->dma_ops && gscs->dma_ops->dma_exit)
  111.         gscs->dma_ops->dma_exit(gscs);
  112. #endif
  113. err_diable_hw:
  114.     gsc3280_enable_spi(gscs, GSC_SPI_DISABLE);
  115. //err_clk:
  116.     clk_disable(gscs->clk);
  117.     clk_put(gscs->clk);
  118. err_irq:
  119.     free_irq(gscs->irq, gscs);
  120. err_unmap:
  121.     iounmap(gscs->regs);
  122. err_release_reg:
  123.     release_mem_region(mem->start, resource_size(mem));
  124. err_kfree:
  125.     kfree(gscs);
  126.     kfree(master);
  127. exit:
  128.     printk(KERN_ERR "!!!!!!gsc3280 probe error!!!!!!\n");
  129.     return ret;
  130. }
        說明:

        1) 首先是匯流排資源的註冊,包括申請IO空間和中斷。

        2) 接下來註冊了中斷函式。

        3) 然後註冊了spi_master所需要的函式,包括清除、設定和傳輸等函式,在四中會講述。

        4) gsc3280_spi_hw_init函式初始化了SPI匯流排暫存器,接下來講述。

        5) 匯流排驅動採用queue機制實現多裝置SPI讀寫,接下來初始化和啟動了queue,接下來講述。

6) 使用spi_register_master函式註冊master,此函式即實現建立了SPI裝置結構體,接下來講述。

        SPI匯流排暫存器初始化函式gsc3280_spi_hw_init:

點選(此處)摺疊或開啟

  1. /* Restart the controller, disable all interrupts, clean fifo */
  2. static void gsc3280_spi_hw_init(struct gsc3280_spi *gscs)
  3. {
  4.     gsc3280_enable_spi(gscs, GSC_SPI_DISABLE);
  5.     gsc3280_spi_mask_intr(gscs, GSC_SPI_SR_MASK);
  6.     if (!gscs->fifo_len) {
  7.         gscs->fifo_len = 0x10;
  8.         __raw_writew(0x00, gscs->regs + GSC_SPI_TXFTLR);
  9.         __raw_writew(0x00, gscs->regs + GSC_SPI_RXFTLR);
  10.     }
  11.     gsc3280_enable_spi(gscs, GSC_SPI_ENABLE);
  12. }

        由程式可以看出,此函式首先禁止SPI,遮蔽中斷,然後設定fifo深度,最後使能SPI。

        初始化queue函式gsc3280_init_queue:

點選(此處)摺疊或開啟

  1. static int __devinit gsc3280_init_queue(struct gsc3280_spi *gscs)
  2. {
  3.     gscs->queue_state = GSC_SPI_QUEUE_STOP;
  4.     gscs->busy = 0;
  5.     tasklet_init(&gscs->pump_transfers, gsc3280_spi_pump_transfers, (unsigned long)gscs);
  6.     INIT_WORK(&gscs->pump_messages, gsc3280_spi_pump_messages);
  7.     gscs->workqueue = create_singlethread_workqueue(dev_name(gscs->master->dev.parent));
  8.     if (gscs->workqueue == NULL) {
  9.         DBG("!!!!create_singlethread_workqueue error!\n");
  10.         return -EBUSY;
  11.     }
  12.     else
  13.         return 0;
  14. }
        由程式看出,此函式主要完成初始化佇列的作用,包括對queue函式的初始化,最後建立了queue。
        開始queue函式gsc3280_start_queue

點選(此處)摺疊或開啟

  1. static int gsc3280_start_queue(struct gsc3280_spi *gscs)
  2. {
  3.     unsigned long flags;
  4.     spin_lock_irqsave(&gscs->lock, flags);
  5.     if ((gscs->run == GSC_SPI_QUEUE_RUN) || gscs->busy) {
  6.         spin_unlock_irqrestore(&gscs->lock, flags);
  7.         return -EBUSY;
  8.     }
  9.     gscs->run = GSC_SPI_QUEUE_RUN;
  10.     gscs->cur_msg = NULL;
  11.     gscs->cur_transfer = NULL;
  12.     gscs->cur_chip = NULL;
  13.     gscs->prev_chip = NULL;
  14.     spin_unlock_irqrestore(&gscs->lock, flags);
  15.     queue_work(gscs->workqueue, &gscs->pump_messages);
  16.     return 0;
  17. }

        此函式首先對queue的狀態進行判斷,然後初始化相關成員變數,最後排程queue。

        最後看下master註冊函式spi_register_master:

點選(此處)摺疊或開啟

  1. int spi_register_master(struct spi_master *master)
  2. {
  3.     static atomic_t        dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
  4.     struct device        *dev = master->dev.parent;
  5.     struct boardinfo    *bi;
  6.     int            status = -ENODEV;
  7.     int            dynamic = 0;
  8.     if (!dev)
  9.         return -ENODEV;
  10.     /* even if it's just one always-selected device, there must
  11.      * be at least one chipselect
  12.      */
  13.     if (master->num_chipselect == 0)
  14.         return -EINVAL;
  15.     /* convention: dynamically assigned bus IDs count down from the max */
  16.     if (master->bus_num < 0) {
  17.         /* FIXME switch to an IDR based scheme, something like
  18.          * I2C now uses, so we can't run out of "dynamic" IDs
  19.          */
  20.         master->bus_num = atomic_dec_return(&dyn_bus_id);
  21.         dynamic = 1;
  22.     }
  23.     spin_lock_init(&master->bus_lock_spinlock);
  24.     mutex_init(&master->bus_lock_mutex);
  25.     master->bus_lock_flag = 0;
  26.     /* register the device, then userspace will see it.
  27.      * registration fails if the bus ID is in use.
  28.      */
  29.     dev_set_name(&master->dev, "spi%u", master->bus_num);
  30.     status = device_add(&master->dev);
  31.     if (status < 0)
  32.         goto done;
  33.     dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
  34.             dynamic ? " (dynamic)" : "");
  35.     mutex_lock(&board_lock);
  36.     list_add_tail(&master->list, &spi_master_list);
  37.     list_for_each_entry(bi, &board_list, list)
  38.         spi_match_master_to_boardinfo(master, &bi->board_info);
  39.     mutex_unlock(&board_lock);
  40.     status = 0;
  41.     /* Register devices from the device tree */
  42.     of_register_spi_devices(master);
  43. done:
  44.     return status;
  45. }
  46. EXPORT_SYMBOL_GPL(spi_register_master);

        說明:

        1) 首先對master成員變數進行檢查。

        2) 初始化成員變數。

        3) 將master->list插入到spi_master_list連結串列中。

        4) 語句list_for_each_entry(bi, &board_list, list)實現遍歷board_list連結串列,在二設備註冊中已經講述了將裝置插入到
board_list連結串列中。此時的board_list連結串列不為空,已經有相應裝置結構體資訊了。

        5) 語句spi_match_master_to_boardinfo(master, &bi->board_info);實現裝置的建立,函式程式如下:

點選(此處)摺疊或開啟

  1. static void spi_match_master_to_boardinfo(struct spi_master *master,
  2.                 struct spi_board_info *bi)
  3. {
  4.     struct spi_device *dev;
  5.     if (master->bus_num != bi->bus_num)
  6.         return;
  7.     dev = spi_new_device(master, bi);
  8.     if (!dev)
  9.         dev_err(master->dev.parent, "can't create new device for %s\n",
  10.             bi-