zoukankan      html  css  js  c++  java
  • 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!
    ");
    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
    ",
    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操作。

  • 相关阅读:
    css表格单元格间距设置
    JavaScript(js)设置输入焦点(focus)
    让div居中的方法
    Window.open()的使用
    getElementsByTagName的用法
    offsetTop获取top值
    js中indexof的使用
    jquery解析json数据
    iframe的使用
    WCF学习笔记Ⅲ
  • 原文地址:https://www.cnblogs.com/lknlfy/p/3265066.html
Copyright © 2011-2022 走看看