From: cmc Date: Fri, 17 Dec 2010 02:48:56 +0000 (+0800) Subject: fix interrupt recv bug for spi X-Git-Tag: firefly_0821_release~10925^2~9 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=353b01005b4fe27699233261dd8159be374972ab;p=firefly-linux-kernel-4.4.55.git fix interrupt recv bug for spi --- diff --git a/drivers/spi/rk29_spim.c b/drivers/spi/rk29_spim.c index b2ffd2ca1605..1227e6e836ff 100755 --- a/drivers/spi/rk29_spim.c +++ b/drivers/spi/rk29_spim.c @@ -40,7 +40,7 @@ QUICK_TRANSFER //#define QUICK_TRANSFER -#if 1 +#if 0 #define DBG printk #else #define DBG(x...) @@ -274,6 +274,7 @@ static int null_writer(struct rk29xx_spi *dws) static int null_reader(struct rk29xx_spi *dws) { u8 n_bytes = dws->n_bytes; + DBG("func: %s, line: %d\n", __FUNCTION__, __LINE__); while ((!(rk29xx_readw(dws, SPIM_SR) & SR_RF_EMPT)) && (dws->rx < dws->rx_end)) { rk29xx_readw(dws, SPIM_RXDR); @@ -299,9 +300,11 @@ static int u8_writer(struct rk29xx_spi *dws) static int u8_reader(struct rk29xx_spi *dws) { + spi_dump_regs(dws); while (!(rk29xx_readw(dws, SPIM_SR) & SR_RF_EMPT) && (dws->rx < dws->rx_end)) { *(u8 *)(dws->rx) = rk29xx_readw(dws, SPIM_RXDR) & 0xFFU; + DBG("rx: 0x%02x\n", *(u8 *)(dws->rx)); ++dws->rx; } @@ -330,6 +333,7 @@ static int u16_reader(struct rk29xx_spi *dws) && (dws->rx < dws->rx_end)) { temp = rk29xx_readw(dws, SPIM_RXDR); *(u16 *)(dws->rx) = temp; + //DBG("rx: 0x%04x\n", *(u16 *)(dws->rx)); dws->rx += 2; } @@ -551,7 +555,9 @@ static irqreturn_t interrupt_transfer(struct rk29xx_spi *dws) dws->write(dws); wait_till_not_busy(dws); } - dws->read(dws); + if (dws->rx) { + dws->read(dws); + } /* Re-enable the IRQ if there is still data left to tx */ if (dws->tx_end > dws->tx) @@ -560,6 +566,24 @@ static irqreturn_t interrupt_transfer(struct rk29xx_spi *dws) transfer_complete(dws); } + if (irq_status & SPI_INT_RXFI) { + spi_mask_intr(dws, SPI_INT_RXFI); + + dws->read(dws); + + /* Re-enable the IRQ if there is still data left to rx */ + if (dws->rx_end > dws->rx) { + left = ((dws->rx_end - dws->rx) / dws->n_bytes) - 1; + left = (left > int_level) ? int_level : left; + + rk29xx_writew(dws, SPIM_RXFTLR, left); + spi_umask_intr(dws, SPI_INT_RXFI); + } + else { + transfer_complete(dws); + } + } + return IRQ_HANDLED; } @@ -609,11 +633,12 @@ static void pump_transfers(unsigned long data) u8 imask = 0; u8 cs_change = 0; u16 txint_level = 0; + u16 rxint_level = 0; u16 clk_div = 0; u32 speed = 0; u32 cr0 = 0; - DBG(KERN_INFO "pump_transfers"); + DBG(KERN_INFO "pump_transfers\n"); /* Get current state information */ message = dws->cur_msg; @@ -742,11 +767,20 @@ static void pump_transfers(unsigned long data) * we only need set the TXEI IRQ, as TX/RX always happen syncronizely */ if (!dws->dma_mapped && !chip->poll_mode) { - int templen = dws->len / dws->n_bytes; - txint_level = dws->fifo_len / 2; - txint_level = (templen > txint_level) ? txint_level : templen; - - imask |= SPI_INT_TXEI; + int templen ; + + if (chip->tmode == SPI_TMOD_RO) { + templen = dws->len / dws->n_bytes - 1; + rxint_level = dws->fifo_len / 2; + rxint_level = (templen > rxint_level) ? rxint_level : templen; + imask |= SPI_INT_RXFI; + } + else { + templen = dws->len / dws->n_bytes; + txint_level = dws->fifo_len / 2; + txint_level = (templen > txint_level) ? txint_level : templen; + imask |= SPI_INT_TXEI; + } dws->transfer_handler = interrupt_transfer; } @@ -763,15 +797,19 @@ static void pump_transfers(unsigned long data) spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); spi_chip_sel(dws, spi->chip_select); + + rk29xx_writew(dws, SPIM_CTRLR1, dws->len-1); + spi_enable_chip(dws, 1); + + if (txint_level) + rk29xx_writew(dws, SPIM_TXFTLR, txint_level); + if (rxint_level) + rk29xx_writew(dws, SPIM_RXFTLR, rxint_level); /* Set the interrupt mask, for poll mode just diable all int */ spi_mask_intr(dws, 0xff); if (imask) spi_umask_intr(dws, imask); - if (txint_level) - rk29xx_writew(dws, SPIM_TXFTLR, txint_level); - - rk29xx_writew(dws, SPIM_CTRLR1, dws->len-1); - spi_enable_chip(dws, 1); + if (cs_change) dws->prev_chip = chip; } @@ -1093,7 +1131,7 @@ static void pump_messages(struct work_struct *work) dws->prev_chip = NULL; //ÿ¸öpump messageʱǿÖƸüÐÂcs dxj /* Mark as busy and launch transfers */ - if(dws->cur_msg->is_dma_mapped && dws->cur_transfer->len > DMA_MIN_BYTES) { + if(dws->cur_msg->is_dma_mapped /*&& dws->cur_transfer->len > DMA_MIN_BYTES*/) { dws->busy = 1; spin_unlock_irqrestore(&dws->lock, flags); dma_transfer(dws); @@ -1606,7 +1644,6 @@ static int rk29xx_spi_setup(struct spi_device *spi) | (chip->tmode << SPI_TMOD_OFFSET); spi_set_ctldata(spi, chip); - DBG("RK29XX_SPI_SETUP: CRO: 0x%x ???????????????????\n", chip->cr0); return 0; }