From 1ae4d3c9d7932f7586eaa41069b98d07483bc6fc Mon Sep 17 00:00:00 2001 From: lyx Date: Sat, 4 Sep 2010 06:40:39 -0700 Subject: [PATCH] =?utf8?q?spi:=E4=BF=AE=E6=94=B9spi=E9=A9=B1=E5=8A=A8?= =?utf8?q?=E7=9A=84=E5=B7=A5=E4=BD=9C=E6=96=B9=E5=BC=8F=EF=BC=8C=E6=8F=90?= =?utf8?q?=E9=AB=98spi=E9=A9=B1=E5=8A=A8=E7=9A=84=E6=95=88=E7=8E=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- drivers/spi/rk2818_spim.c | 142 ++++++++++++++++++++++++++++++-------- 1 file changed, 113 insertions(+), 29 deletions(-) diff --git a/drivers/spi/rk2818_spim.c b/drivers/spi/rk2818_spim.c index 0d68a8d8f26a..0f1aea70b997 100755 --- a/drivers/spi/rk2818_spim.c +++ b/drivers/spi/rk2818_spim.c @@ -44,6 +44,12 @@ #define MRST_SPI_ASSERT 1 ///CS0 #define MRST_SPI_ASSERT1 2 ///CS1 +#if 0 +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + /* Slave spi_dev related */ struct chip_data { u16 cr0; @@ -317,16 +323,17 @@ static void giveback(struct rk2818_spi *dws) struct spi_transfer *last_transfer; unsigned long flags; struct spi_message *msg; - - spin_lock_irqsave(&dws->lock, flags); + DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__); + //spin_lock_irqsave(&dws->lock, flags); msg = dws->cur_msg; dws->cur_msg = NULL; dws->cur_transfer = NULL; dws->prev_chip = dws->cur_chip; dws->cur_chip = NULL; dws->dma_mapped = 0; - queue_work(dws->workqueue, &dws->pump_messages); - spin_unlock_irqrestore(&dws->lock, flags); + //queue_work(dws->workqueue, &dws->pump_messages); + //spin_unlock_irqrestore(&dws->lock, flags); + dws->busy = 0; last_transfer = list_entry(msg->transfers.prev, struct spi_transfer, @@ -351,8 +358,12 @@ static void int_error_stop(struct rk2818_spi *dws, const char *msg) tasklet_schedule(&dws->pump_transfers); } +static int pump_transfers(unsigned long data); + static void transfer_complete(struct rk2818_spi *dws) { + DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__); + /* Update total byte transfered return count actual bytes read */ dws->cur_msg->actual_length += dws->len; @@ -364,7 +375,8 @@ static void transfer_complete(struct rk2818_spi *dws) dws->cur_msg->status = 0; giveback(dws); } else - tasklet_schedule(&dws->pump_transfers); + //tasklet_schedule(&dws->pump_transfers); + pump_transfers((unsigned long)dws); } static irqreturn_t interrupt_transfer(struct rk2818_spi *dws) @@ -372,7 +384,8 @@ static irqreturn_t interrupt_transfer(struct rk2818_spi *dws) u16 irq_status, irq_mask = 0x3f; u32 int_level = dws->fifo_len / 2; u32 left; - + DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__); + irq_status = rk2818_readw(dws, SPIM_ISR) & irq_mask; /* Error handling */ if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) { @@ -383,22 +396,22 @@ static irqreturn_t interrupt_transfer(struct rk2818_spi *dws) return IRQ_HANDLED; } - if (irq_status & SPI_INT_TXEI) { - spi_mask_intr(dws, SPI_INT_TXEI); + spi_mask_intr(dws, 0xff); left = (dws->tx_end - dws->tx) / dws->n_bytes; left = (left > int_level) ? int_level : left; + //DBG("+++++++++++++++left = %d++++++++++++++++++\n", left); + while (left--) dws->write(dws); dws->read(dws); /* Re-enable the IRQ if there is still data left to tx */ if (dws->tx_end > dws->tx) - spi_umask_intr(dws, SPI_INT_TXEI); + spi_umask_intr(dws, 0xff); else transfer_complete(dws); - } return IRQ_HANDLED; } @@ -408,7 +421,7 @@ static irqreturn_t rk2818_spi_irq(int irq, void *dev_id) struct rk2818_spi *dws = dev_id; if (!dws->cur_msg) { - spi_mask_intr(dws, SPI_INT_TXEI); + spi_mask_intr(dws, 0xff); /* Never fail */ return IRQ_HANDLED; } @@ -417,12 +430,59 @@ static irqreturn_t rk2818_spi_irq(int irq, void *dev_id) } /* Must be called inside pump_transfers() */ -static void poll_transfer(struct rk2818_spi *dws) +static int poll_transfer(struct rk2818_spi *dws) { - while (dws->write(dws)) +#if 0 + int level = dws->fifo_len; + int left = (dws->tx_end - dws->tx)/dws->n_bytes; + int length = left > level ? level : left; + DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__); + + while (left>0) { + left -= length; + while (length--) + dws->write(dws); + while(!(rk2818_readw(dws, SPIM_SR)& SR_TF_EMPT)); + cpu_relax(); + //while(rk2818_readw(dws, SPIM_SR) & SR_BUSY); + //cpu_relax(); dws->read(dws); + length = left > level ? level : left; + } + transfer_complete(dws); +#else + if ((dws->read(dws))) { + goto comple; + } + + while (dws->txtx_end){ + dws->write(dws); + dws->read(dws); + } + + if (dws->rx < dws->rx_end) { + dws->read(dws); + } + +comple: + + dws->cur_msg->actual_length += dws->len; + + /* Move to next transfer */ + dws->cur_msg->state = next_transfer(dws); + + if (dws->cur_msg->state == DONE_STATE) { + dws->cur_msg->status = 0; + giveback(dws); + return 0; + } + else { + return -1; + } + +#endif } static void dma_transfer(struct rk2818_spi *dws, struct spi_transfer *xfer) //int cs_change) @@ -442,7 +502,7 @@ static void spi_chip_sel(struct rk2818_spi *dws, u16 cs) rk2818_writel(dws, SPIM_SER, 1 << 0); } -static void pump_transfers(unsigned long data) +static int pump_transfers(unsigned long data) { struct rk2818_spi *dws = (struct rk2818_spi *)data; struct spi_message *message = NULL; @@ -457,12 +517,15 @@ static void pump_transfers(unsigned long data) u16 clk_div = 0; u32 speed = 0; u32 cr0 = 0; + + DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__); /* Get current state information */ message = dws->cur_msg; transfer = dws->cur_transfer; chip = dws->cur_chip; spi = message->spi; + if (unlikely(!chip->clk_div)) chip->clk_div = clk_get_rate(dws->clock_spim) / chip->speed_hz; if (message->state == ERROR_STATE) { @@ -581,6 +644,7 @@ static void pump_transfers(unsigned long data) * Interrupt mode * we only need set the TXEI IRQ, as TX/RX always happen syncronizely */ + chip->poll_mode = 1; if (!dws->dma_mapped && !chip->poll_mode) { int templen = dws->len / dws->n_bytes; txint_level = dws->fifo_len / 2; @@ -605,8 +669,8 @@ static void pump_transfers(unsigned long data) spi_chip_sel(dws, spi->chip_select); /* Set the interrupt mask, for poll mode just diable all int */ spi_mask_intr(dws, 0xff); - if (imask) - spi_umask_intr(dws, imask); + //if (imask) + //spi_umask_intr(dws, 0xff); if (txint_level) rk2818_writew(dws, SPIM_TXFTLR, txint_level); @@ -618,14 +682,15 @@ static void pump_transfers(unsigned long data) if (dws->dma_mapped) dma_transfer(dws, transfer); ///cs_change); - if (chip->poll_mode) - poll_transfer(dws); - - return; + if (chip->poll_mode) { + return poll_transfer(dws); + } + + return 0; early_exit: giveback(dws); - return; + return 0; } static void pump_messages(struct work_struct *work) @@ -633,18 +698,19 @@ static void pump_messages(struct work_struct *work) struct rk2818_spi *dws = container_of(work, struct rk2818_spi, pump_messages); unsigned long flags; + DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__); /* Lock queue and check for queue work */ - spin_lock_irqsave(&dws->lock, flags); + //spin_lock_irqsave(&dws->lock, flags); if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) { dws->busy = 0; - spin_unlock_irqrestore(&dws->lock, flags); + //spin_unlock_irqrestore(&dws->lock, flags); return; } /* Make sure we are not already running a message */ if (dws->cur_msg) { - spin_unlock_irqrestore(&dws->lock, flags); + //spin_unlock_irqrestore(&dws->lock, flags); return; } @@ -661,10 +727,18 @@ static void pump_messages(struct work_struct *work) dws->prev_chip = NULL; //ÿ¸öpump messageʱǿÖƸüÐÂcs dxj /* Mark as busy and launch transfers */ + #if 0 tasklet_schedule(&dws->pump_transfers); dws->busy = 1; - spin_unlock_irqrestore(&dws->lock, flags); + //spin_unlock_irqrestore(&dws->lock, flags); + + #else + dws->busy = 1; + //spin_unlock_irqrestore(&dws->lock, flags); + + while (pump_transfers((unsigned long)dws)) ; + #endif } /* spi_device use this to queue in their spi_msg */ @@ -672,7 +746,7 @@ static int rk2818_spi_transfer(struct spi_device *spi, struct spi_message *msg) { struct rk2818_spi *dws = spi_master_get_devdata(spi->master); unsigned long flags; - + DBG("+++++++++++++++enter %s++++++++++++++++++\n", __func__); spin_lock_irqsave(&dws->lock, flags); if (dws->run == QUEUE_STOPPED) { @@ -688,6 +762,9 @@ static int rk2818_spi_transfer(struct spi_device *spi, struct spi_message *msg) if (dws->run == QUEUE_RUNNING && !dws->busy) { + //DBG("+++++++++++++++add message++++++++++++++++++\n"); + + #if 0 if (dws->cur_transfer || dws->cur_msg) queue_work(dws->workqueue, &dws->pump_messages); @@ -697,10 +774,17 @@ static int rk2818_spi_transfer(struct spi_device *spi, struct spi_message *msg) pump_messages(&dws->pump_messages); return 0; } + #else + //spin_unlock_irqrestore(&dws->lock, flags); + //mutex_lock(&dws->mutex_lock); + pump_messages(&dws->pump_messages); + //mutex_unlock(&dws->mutex_lock); + //return 0; + #endif } spin_unlock_irqrestore(&dws->lock, flags); - + DBG("+++++++++++++++quit %s++++++++++++++++++\n", __func__); return 0; } @@ -822,7 +906,7 @@ static int start_queue(struct rk2818_spi *dws) dws->prev_chip = NULL; spin_unlock_irqrestore(&dws->lock, flags); - queue_work(dws->workqueue, &dws->pump_messages); + //queue_work(dws->workqueue, &dws->pump_messages); return 0; } @@ -926,7 +1010,7 @@ static int __init rk2818_spim_probe(struct platform_device *pdev) struct rk2818_spi *dws; struct spi_master *master; int irq; - int ret,i,j; + int ret; struct rk2818_spi_platform_data *pdata = pdev->dev.platform_data; if (pdata && pdata->io_init) { -- 2.34.1