Linux設備驅動剖析之SPI(四)


781行之前沒什么好說的,直接看783行,將work投入到工作隊列里,然后就返回,在這里就可以回答之前為什么是異步的問題。以后在某個合適的時間里CPU會執行這個work指定的函數,這里是s3c64xx_spi_work函數,看它的定義:

00000723 static void s3c64xx_spi_work(struct work_struct *work)
00000724 {
00000725     struct s3c64xx_spi_driver_data *sdd = container_of(work,
00000726                     struct s3c64xx_spi_driver_data, work);
00000727     unsigned long flags;
00000728 
00000729     /* Acquire DMA channels */
00000730     while (!acquire_dma(sdd))
00000731         msleep(10);
00000732 
00000733     spin_lock_irqsave(&sdd->lock, flags);
00000734 
00000735     while (!list_empty(&sdd->queue)
00000736                 && !(sdd->state & SUSPND)) {
00000737 
00000738         struct spi_message *msg;
00000739 
00000740         msg = container_of(sdd->queue.next, struct spi_message, queue);
00000741 
00000742         list_del_init(&msg->queue);
00000743 
00000744         /* Set Xfer busy flag */
00000745         sdd->state |= SPIBUSY;
00000746 
00000747         spin_unlock_irqrestore(&sdd->lock, flags);
00000748 
00000749         handle_msg(sdd, msg);
00000750 
00000751         spin_lock_irqsave(&sdd->lock, flags);
00000752 
00000753         sdd->state &= ~SPIBUSY;
00000754     }
00000755 
00000756     spin_unlock_irqrestore(&sdd->lock, flags);
00000757 
00000758     /* Free DMA channels */
00000759     s3c2410_dma_free(sdd->tx_dmach, &s3c64xx_spi_dma_client);
00000760     s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
00000761 }

730行,申請DMA,關於DMA的就不說,一是我對DMA沒什么了解,二是這里基本上用不到,后面就知道什么時候才會用到DMA。

735至754行,循環取出隊列里的message並調用749行的handle_msg函數進行處理,handle_msg函數的定義如下:

00000568 static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
00000569                     struct spi_message *msg)
00000570 {
00000571     struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
00000572     struct spi_device *spi = msg->spi;
00000573     struct s3c64xx_spi_csinfo *cs = spi->controller_data;
00000574     struct spi_transfer *xfer;
00000575     int status = 0, cs_toggle = 0;
00000576     u32 speed;
00000577     u8 bpw;
00000578 
00000579     /* If Master's(controller) state differs from that needed by Slave */
00000580     if (sdd->cur_speed != spi->max_speed_hz
00000581             || sdd->cur_mode != spi->mode
00000582             || sdd->cur_bpw != spi->bits_per_word) {
00000583         sdd->cur_bpw = spi->bits_per_word;
00000584         sdd->cur_speed = spi->max_speed_hz;
00000585         sdd->cur_mode = spi->mode;
00000586         s3c64xx_spi_config(sdd);
00000587     }
00000588 
00000589     /* Map all the transfers if needed */
00000590     if (s3c64xx_spi_map_mssg(sdd, msg)) {
00000591         dev_err(&spi->dev,
00000592             "Xfer: Unable to map message buffers!\n");
00000593         status = -ENOMEM;
00000594         goto out;
00000595     }
00000596 
00000597     /* Configure feedback delay */
00000598     writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
00000599 
00000600     list_for_each_entry(xfer, &msg->transfers, transfer_list) {
00000601 
00000602         unsigned long flags;
00000603         int use_dma;
00000604 
00000605         INIT_COMPLETION(sdd->xfer_completion);
00000606 
00000607         /* Only BPW and Speed may change across transfers */
00000608         bpw = xfer->bits_per_word ? : spi->bits_per_word;
00000609         speed = xfer->speed_hz ? : spi->max_speed_hz;
00000610 
00000611         if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
00000612             sdd->cur_bpw = bpw;
00000613             sdd->cur_speed = speed;
00000614             s3c64xx_spi_config(sdd);
00000615         }
00000616 
00000617         /* Polling method for xfers not bigger than FIFO capacity */
00000618         
00000619         if (xfer->len <= ((sci->fifo_lvl_mask >> 1) + 1))
00000620             use_dma = 0;
00000621         else
00000622             use_dma = 1;
00000623 
00000624         spin_lock_irqsave(&sdd->lock, flags);
00000625 
00000626         /* Pending only which is to be done */
00000627         sdd->state &= ~RXBUSY;
00000628         sdd->state &= ~TXBUSY;
00000629 
00000630         enable_datapath(sdd, spi, xfer, use_dma);
00000631 
00000632         /* Slave Select */
00000633         enable_cs(sdd, spi);
00000634 
00000635         /* Start the signals */
00000636         S3C64XX_SPI_ACT(sdd);
00000637 
00000638         spin_unlock_irqrestore(&sdd->lock, flags);
00000639 
00000640         status = wait_for_xfer(sdd, xfer, use_dma);
00000641 
00000642         /* Quiese the signals */
00000643         S3C64XX_SPI_DEACT(sdd);
00000644 
00000645         if (status) {
00000646             dev_err(&spi->dev, "I/O Error: "
00000647                 "rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
00000648                 xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
00000649                 (sdd->state & RXBUSY) ? 'f' : 'p',
00000650                 (sdd->state & TXBUSY) ? 'f' : 'p',
00000651                 xfer->len);
00000652 
00000653             if (use_dma) {
00000654                 if (xfer->tx_buf != NULL
00000655                         && (sdd->state & TXBUSY))
00000656                     s3c2410_dma_ctrl(sdd->tx_dmach,
00000657                             S3C2410_DMAOP_FLUSH);
00000658                 if (xfer->rx_buf != NULL
00000659                         && (sdd->state & RXBUSY))
00000660                     s3c2410_dma_ctrl(sdd->rx_dmach,
00000661                             S3C2410_DMAOP_FLUSH);
00000662             }
00000663 
00000664             goto out;
00000665         }
00000666 
00000667         if (xfer->delay_usecs)
00000668             udelay(xfer->delay_usecs);
00000669 
00000670         if (xfer->cs_change) {
00000671             /* Hint that the next mssg is gonna be
00000672                for the same device */
00000673             if (list_is_last(&xfer->transfer_list,
00000674                         &msg->transfers))
00000675                 cs_toggle = 1;
00000676             else
00000677                 disable_cs(sdd, spi);
00000678         }
00000679 
00000680         msg->actual_length += xfer->len;
00000681 
00000682         flush_fifo(sdd);
00000683     }
00000684 
00000685 out:
00000686     if (!cs_toggle || status)
00000687         disable_cs(sdd, spi);
00000688     else
00000689         sdd->tgl_spi = spi;
00000690 
00000691     s3c64xx_spi_unmap_mssg(sdd, msg);
00000692 
00000693     msg->status = status;
00000694 
00000695     if (msg->complete)
00000696         msg->complete(msg->context);
00000697 }

函數很長,580至587行,如果一路走來speed、bpw和mode的值與spi設備的不一致就調用s3c64xx_spi_config函數重新配置,s3c64xx_spi_config函數里面就是對SPI寄存器進行設置的。

590至595行,關於DMA映射的,略過。

598行,設置feedback寄存器。

600行,遍歷每一個transfer。605行,又初始化一個完成量,注意這里與之前的那個完成量是不一樣的,這里的完成量只有使用DMA傳輸時才會用得到,接下來很快就可以看到。

608至615行,也是一些關於設置值的檢查。

619至622行,只有發送或者接收的數據長度大於fifo的深度(這里是64個字節)設置use_dma為1,也即使用DMA進行傳輸,否則不使用DMA。

630行,enable_datapath函數的定義為:

00000232 static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
00000233                 struct spi_device *spi,
00000234                 struct spi_transfer *xfer, int dma_mode)
00000235 {
00000236     struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
00000237     void __iomem *regs = sdd->regs;
00000238     u32 modecfg, chcfg;
00000239 
00000240     modecfg = readl(regs + S3C64XX_SPI_MODE_CFG);
00000241     modecfg&=~(S3C64XX_SPI_MODE_TXDMA_ON|S3C64XX_SPI_MODE_RXDMA_ON);
00000242 
00000243     chcfg = readl(regs + S3C64XX_SPI_CH_CFG);
00000244     chcfg &= ~S3C64XX_SPI_CH_TXCH_ON;
00000245 
00000246     if (dma_mode) {
00000247         chcfg &= ~S3C64XX_SPI_CH_RXCH_ON;
00000248     } else {
00000249         /* Always shift in data in FIFO, even if xfer is Tx only,
00000250          * this helps setting PCKT_CNT value for generating clocks
00000251          * as exactly needed.
00000252          */
00000253         chcfg |= S3C64XX_SPI_CH_RXCH_ON;
00000254         writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
00000255                     | S3C64XX_SPI_PACKET_CNT_EN,
00000256                     regs + S3C64XX_SPI_PACKET_CNT);
00000257     }
00000258 
00000259     if (xfer->tx_buf != NULL) {
00000260         sdd->state |= TXBUSY;
00000261         chcfg |= S3C64XX_SPI_CH_TXCH_ON;
00000262         if (dma_mode) {
00000263             modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
00000264             s3c2410_dma_config(sdd->tx_dmach, 1);
00000265             s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd,
00000266                         xfer->tx_dma, xfer->len);
00000267             s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START);
00000268         } else {
00000269             unsigned char *buf = (unsigned char *) xfer->tx_buf;
00000270             int i = 0;
00000271             while (i < xfer->len)
00000272                 writeb(buf[i++], regs + S3C64XX_SPI_TX_DATA);
00000273         }
00000274     }
00000275 
00000276     if (xfer->rx_buf != NULL) {
00000277         sdd->state |= RXBUSY;
00000278 
00000279         if (sci->high_speed && sdd->cur_speed >= 30000000UL
00000280                     && !(sdd->cur_mode & SPI_CPHA))
00000281             chcfg |= S3C64XX_SPI_CH_HS_EN;
00000282 
00000283         if (dma_mode) {
00000284             modecfg |= S3C64XX_SPI_MODE_RXDMA_ON;
00000285             chcfg |= S3C64XX_SPI_CH_RXCH_ON;
00000286             writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
00000287                     | S3C64XX_SPI_PACKET_CNT_EN,
00000288                     regs + S3C64XX_SPI_PACKET_CNT);
00000289             s3c2410_dma_config(sdd->rx_dmach, 1);
00000290             s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd,
00000291                         xfer->rx_dma, xfer->len);
00000292             s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START);
00000293         }
00000294     }
00000295 
00000296     writel(modecfg, regs + S3C64XX_SPI_MODE_CFG);
00000297     writel(chcfg, regs + S3C64XX_SPI_CH_CFG);
00000298 }

240至244行,讀取模式配置和通道配置寄存器。

246至257行,根據是否采用DMA模式設置接收計數寄存器。

259行,很早就為tx_buf分配內存,因此條件成立。因為不考慮DMA模式,因此略過262至268行。

269至272行,循環將發送數據寫入到發送寄存器。

276至294行,由於rx_buf為NULL,因此直接略過277至294行。

296、297行,將之前的值寫入到寄存器中。

      回到handle_msg函數,633行,選中從設備。636行,設置寄存器,開始數據傳輸。

640行,wait_for_xfer函數的定義:

00000319 static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
00000320                 struct spi_transfer *xfer, int dma_mode)
00000321 {
00000322     struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
00000323     void __iomem *regs = sdd->regs;
00000324     unsigned long val;
00000325     int ms;
00000326 
00000327     /* millisecs to xfer 'len' bytes @ 'cur_speed' */
00000328     ms = xfer->len * 8 * 1000 / sdd->cur_speed;
00000329     ms += 10; /* some tolerance */
00000330 
00000331     if (dma_mode) {
00000332         val = msecs_to_jiffies(ms) + 10;
00000333         val = wait_for_completion_timeout(&sdd->xfer_completion, val);
00000334     } else {
00000335         u32 status;
00000336         val = msecs_to_loops(ms);
00000337         do {
00000338             status = readl(regs + S3C64XX_SPI_STATUS);
00000339         } while (RX_FIFO_LVL(status, sci) < xfer->len && --val);
00000340     }
00000341 
00000342     if (!val)
00000343         return -EIO;
00000344 
00000345     if (dma_mode) {
00000346         u32 status;
00000347 
00000348         /*
00000349          * DmaTx returns after simply writing data in the FIFO,
00000350          * w/o waiting for real transmission on the bus to finish.
00000351          * DmaRx returns only after Dma read data from FIFO which
00000352          * needs bus transmission to finish, so we don't worry if
00000353          * Xfer involved Rx(with or without Tx).
00000354          */
00000355         if (xfer->rx_buf == NULL) {
00000356             val = msecs_to_loops(10);
00000357             status = readl(regs + S3C64XX_SPI_STATUS);
00000358             while ((TX_FIFO_LVL(status, sci)
00000359                 || !S3C64XX_SPI_ST_TX_DONE(status, sci))
00000360                     && --val) {
00000361                 cpu_relax();
00000362                 status = readl(regs + S3C64XX_SPI_STATUS);
00000363             }
00000364 
00000365             if (!val)
00000366                 return -EIO;
00000367         }
00000368     } else {
00000369         unsigned char *buf;
00000370         int i;
00000371 
00000372         /* If it was only Tx */
00000373         if (xfer->rx_buf == NULL) {
00000374             sdd->state &= ~TXBUSY;
00000375             return 0;
00000376         }
00000377 
00000378         i = 0;
00000379         buf = xfer->rx_buf;
00000380         while (i < xfer->len)
00000381             buf[i++] = readb(regs + S3C64XX_SPI_RX_DATA);
00000382 
00000383         sdd->state &= ~RXBUSY;
00000384     }
00000385 
00000386     return 0;
00000387 }

328行,根據發送速率計算需要等待的時間。331至334行,與DMA相關的,略過。

335至339行,不斷地讀狀態寄存器,如果接收到的數據長度等於發送數據的長度或超時則退出循環。

342、343行,如果是超時退出循環的,則返回出錯。

345至368行,DMA相關的,略過。

369至383行,如果只是發送數據,則直接返回0。否則從接收寄存器里將接收到的數據讀出來。

      回到handle_msg函數,643行,停止傳輸。645至665行,如果之前wait_for_xfer函數返回大於0的值,則表示出錯,這里就打印一些信息。

667、668行,之前如果有設置延時的話這里就延時。

670至678行,是否需要每個transfer完成都改變片選信號。

680行,累加所有transfer成功發送的數據。

682行,清發送和接收寄存器。

691行,取消DMA映射。

693行,記錄狀態信息。

695、696行,喚醒之前等待的完成量。

      到這里,已經說了整個write過程,不容易啊!。其他的read/ioctl過程是大同小異的。

 

總結

      spidev.c是一個通用的SPI驅動,因此它不處理任何有關具體驅動的邏輯,這就需要在用戶空間來完成具體的邏輯。其實這符合了Android驅動的思想,這也是Android HAL層存在的目的:內核驅動只完成硬件操作,具體邏輯放在HAL層,這樣就有利於保護廠家、開發者的知識產權。

     在用戶空間使用ioctl就可以完成write、read操作。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM