From 4a0f8a94e03ae8277b93efe4de6da573236de3e4 Mon Sep 17 00:00:00 2001 From: cmc Date: Mon, 29 Nov 2010 15:11:41 +0800 Subject: [PATCH] support dma transfer for spi --- arch/arm/mach-rk29/board-rk29sdk.c | 6 +- drivers/spi/Kconfig | 18 +- drivers/spi/Makefile | 2 +- drivers/spi/rk29xx_spim.c | 432 +++++++++++++++++++++++------ drivers/spi/rk29xx_spim.h | 8 + 5 files changed, 368 insertions(+), 98 deletions(-) diff --git a/arch/arm/mach-rk29/board-rk29sdk.c b/arch/arm/mach-rk29/board-rk29sdk.c index cb6a04796045..821046796ba8 100755 --- a/arch/arm/mach-rk29/board-rk29sdk.c +++ b/arch/arm/mach-rk29/board-rk29sdk.c @@ -557,8 +557,10 @@ static struct platform_device *devices[] __initdata = { #ifdef CONFIG_UART1_RK29 &rk29_device_uart1, #endif -#ifdef CONFIG_SPIM_RK29XX +#ifdef CONFIG_SPIM0_RK29 &rk29xx_device_spi0m, +#endif +#ifdef CONFIG_SPIM1_RK29 &rk29xx_device_spi1m, #endif #ifdef CONFIG_ADC_RK29 @@ -774,7 +776,7 @@ static struct spi_board_info board_spi_devices[] = { { .modalias = "xpt2046_ts", .chip_select = 0, - .max_speed_hz = 125 * 1000 * 26,/* (max sample rate @ 3V) * (cmd + data + overhead) */ + .max_speed_hz = 125 * 1000 * 8,/* (max sample rate @ 3V) * (cmd + data + overhead) */ .bus_num = 0, .irq = XPT2046_GPIO_INT, .platform_data = &xpt2046_info, diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 8fd8f941d966..a5375907655c 100755 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -254,11 +254,23 @@ config SPIM_RK2818 help general driver for SPI controller core from DesignWare -config SPIM_RK29XX - tristate "RK29xx SPI master controller core support" +config SPIM_RK29 + tristate "RK29 SPI master controller core support" depends on ARCH_RK29 && SPI_MASTER help - general driver for SPI controller core from DesignWare + general driver for SPI controller core from RockChips + +config SPIM0_RK29 + bool "RK29 SPI0 master controller" + depends on SPIM_RK29 + help + enable SPI0 master controller for RK29 + +config SPIM1_RK29 + bool "RK29 SPI1 master controller" + depends on SPIM_RK29 + help + enable SPI1 master controller for RK29 # # There are lots of SPI device types, with sensors and memory diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index f56531ae60b4..8e200b197ea7 100755 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -17,7 +17,7 @@ obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o obj-$(CONFIG_SPI_AU1550) += au1550_spi.o obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o obj-$(CONFIG_SPIM_RK2818) += rk2818_spim.o -obj-$(CONFIG_SPIM_RK29XX) += rk29xx_spim.o +obj-$(CONFIG_SPIM_RK29) += rk29xx_spim.o obj-$(CONFIG_SPI_GPIO) += spi_gpio.o obj-$(CONFIG_SPI_IMX) += spi_imx.o obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o diff --git a/drivers/spi/rk29xx_spim.c b/drivers/spi/rk29xx_spim.c index f526e94b7a91..09e3527b5823 100755 --- a/drivers/spi/rk29xx_spim.c +++ b/drivers/spi/rk29xx_spim.c @@ -40,8 +40,8 @@ QUICK_TRANSFER //#define QUICK_TRANSFER -#if 0 -#define DBG(x...) printk(x) +#if 1 +#define DBG printk #else #define DBG(x...) #endif @@ -198,6 +198,7 @@ static void wait_till_not_busy(struct rk29xx_spi *dws) "DW SPI: Status keeps busy for 1000us after a read/write!\n"); } +#if defined(QUICK_TRANSFER) static void wait_till_tf_empty(struct rk29xx_spi *dws) { unsigned long end = jiffies + 1 + usecs_to_jiffies(1000); @@ -209,6 +210,7 @@ static void wait_till_tf_empty(struct rk29xx_spi *dws) dev_err(&dws->master->dev, "DW SPI: Status keeps busy for 1000us after a read/write!\n"); } +#endif static void flush(struct rk29xx_spi *dws) { @@ -238,7 +240,7 @@ static int null_writer(struct rk29xx_spi *dws) return 0; rk29xx_writew(dws, SPIM_TXDR, 0); dws->tx += n_bytes; - wait_till_not_busy(dws); + //wait_till_not_busy(dws); return 1; } @@ -260,11 +262,9 @@ static int u8_writer(struct rk29xx_spi *dws) if ((rk29xx_readw(dws, SPIM_SR) & SR_TF_FULL) || (dws->tx == dws->tx_end)) return 0; - DBG(KERN_INFO "ctrl0: 0x%x\n", rk29xx_readl(dws, SPIM_CTRLR0)); rk29xx_writew(dws, SPIM_TXDR, *(u8 *)(dws->tx)); - DBG(KERN_INFO "dws->tx:%x\n", *(u8 *)(dws->tx)); ++dws->tx; - wait_till_not_busy(dws); + //wait_till_not_busy(dws); return 1; } @@ -273,9 +273,7 @@ static int u8_reader(struct rk29xx_spi *dws) { while (!(rk29xx_readw(dws, SPIM_SR) & SR_RF_EMPT) && (dws->rx < dws->rx_end)) { - printk(KERN_INFO "ctrl0: 0x%x\n", rk29xx_readl(dws, SPIM_CTRLR0)); *(u8 *)(dws->rx) = rk29xx_readw(dws, SPIM_RXDR) & 0xFFU; - printk(KERN_INFO "dws->rx:%x\n", *(u8 *)(dws->rx)); ++dws->rx; } @@ -291,7 +289,7 @@ static int u16_writer(struct rk29xx_spi *dws) rk29xx_writew(dws, SPIM_TXDR, *(u16 *)(dws->tx)); dws->tx += 2; - wait_till_not_busy(dws); + //wait_till_not_busy(dws); return 1; } @@ -303,7 +301,6 @@ static int u16_reader(struct rk29xx_spi *dws) while (!(rk29xx_readw(dws, SPIM_SR) & SR_RF_EMPT) && (dws->rx < dws->rx_end)) { temp = rk29xx_readw(dws, SPIM_RXDR); - printk(KERN_INFO "dws->rx:%02x\n", temp); *(u16 *)(dws->rx) = temp; dws->rx += 2; } @@ -328,7 +325,7 @@ static void *next_transfer(struct rk29xx_spi *dws) return DONE_STATE; } -static void rk29_spi_dma_rxcb(struct rk29_dma_chan *chan, void *buf_id, +static void rk29_spi_dma_rxcb(void *buf_id, int size, enum rk29_dma_buffresult res) { struct rk29xx_spi *dws = buf_id; @@ -339,7 +336,7 @@ static void rk29_spi_dma_rxcb(struct rk29_dma_chan *chan, void *buf_id, if (res == RK29_RES_OK) dws->state &= ~RXBUSY; else - dev_err(&dws->master->dev, "DmaAbrtRx-%d\n", size); + dev_err(&dws->master->dev, "DmaAbrtRx-%d, size: %d\n", res, size); /* If the other done */ if (!(dws->state & TXBUSY)) @@ -348,7 +345,7 @@ static void rk29_spi_dma_rxcb(struct rk29_dma_chan *chan, void *buf_id, spin_unlock_irqrestore(&dws->lock, flags); } -static void rk29_spi_dma_txcb(struct rk29_dma_chan *chan, void *buf_id, +static void rk29_spi_dma_txcb(void *buf_id, int size, enum rk29_dma_buffresult res) { struct rk29xx_spi *dws = buf_id; @@ -362,7 +359,7 @@ static void rk29_spi_dma_txcb(struct rk29_dma_chan *chan, void *buf_id, dev_err(&dws->master->dev, "DmaAbrtTx-%d \n", size); /* If the other done */ - if (!(dws->state & RXBUSY)) + if (!(dws->state & RXBUSY)) complete(&dws->xfer_completion); spin_unlock_irqrestore(&dws->lock, flags); @@ -375,38 +372,33 @@ static struct rk29_dma_client rk29_spi_dma_client = { static int acquire_dma(struct rk29xx_spi *dws) { - #if 1 - dws->dma_inited = 0; - return 1; - #endif - if (dws->dma_inited) { - return 1; + return 0; } if(rk29_dma_request(dws->rx_dmach, &rk29_spi_dma_client, NULL) < 0) { dev_err(&dws->master->dev, "dws->rx_dmach : %d, cannot get RxDMA\n", dws->rx_dmach); - return 0; + return -1; } - DBG(KERN_INFO "request dma success\n"); - - rk29_dma_set_buffdone_fn(dws->rx_dmach, rk29_spi_dma_rxcb); - rk29_dma_devconfig(dws->rx_dmach, RK29_DMASRC_HW, - dws->sfr_start + SPIM_RXDR); if (rk29_dma_request(dws->tx_dmach, &rk29_spi_dma_client, NULL) < 0) { dev_err(&dws->master->dev, "dws->tx_dmach : %d, cannot get TxDMA\n", dws->tx_dmach); rk29_dma_free(dws->rx_dmach, &rk29_spi_dma_client); - return 0; + return -1; } - rk29_dma_set_buffdone_fn(dws->tx_dmach, rk29_spi_dma_txcb); - rk29_dma_devconfig(dws->tx_dmach, RK29_DMASRC_MEM, - dws->sfr_start + SPIM_TXDR); - + dws->dma_inited = 1; - return 1; + return 0; +} + +static void release_dma(struct rk29xx_spi *dws) +{ + if(!dws && dws->dma_inited) { + rk29_dma_free(dws->rx_dmach, &rk29_spi_dma_client); + rk29_dma_free(dws->tx_dmach, &rk29_spi_dma_client); + } } /* @@ -418,15 +410,35 @@ static int map_dma_buffers(struct rk29xx_spi *dws) { if (!dws->cur_msg->is_dma_mapped || !dws->dma_inited || !dws->cur_chip->enable_dma) - return 0; + return -1; - if (dws->cur_transfer->tx_dma) + if (dws->cur_transfer->tx_dma) { dws->tx_dma = dws->cur_transfer->tx_dma; + if (rk29_dma_set_buffdone_fn(dws->tx_dmach, rk29_spi_dma_txcb)) { + dev_err(&dws->master->dev, "rk29_dma_set_buffdone_fn fail\n"); + return -1; + } + if (rk29_dma_devconfig(dws->tx_dmach, RK29_DMASRC_MEM, + (unsigned long)dws->sfr_start + SPIM_TXDR)) { + dev_err(&dws->master->dev, "rk29_dma_devconfig fail\n"); + return -1; + } + } - if (dws->cur_transfer->rx_dma) + if (dws->cur_transfer->rx_dma) { dws->rx_dma = dws->cur_transfer->rx_dma; + if (rk29_dma_set_buffdone_fn(dws->rx_dmach, rk29_spi_dma_rxcb)) { + dev_err(&dws->master->dev, "rk29_dma_set_buffdone_fn fail\n"); + return -1; + } + if (rk29_dma_devconfig(dws->rx_dmach, RK29_DMASRC_HW, + (unsigned long)dws->sfr_start + SPIM_RXDR)) { + dev_err(&dws->master->dev, "rk29_dma_devconfig fail\n"); + return -1; + } + } - return 1; + return 0; } /* Caller already set message->status; dma and pio irqs are blocked */ @@ -451,7 +463,7 @@ static void giveback(struct rk29xx_spi *dws) transfer_list); if (!last_transfer->cs_change) - dws->cs_control(dws,msg->spi->chip_select,MRST_SPI_DEASSERT); + dws->cs_control(dws,msg->spi->chip_select, MRST_SPI_DEASSERT); msg->state = NULL; if (msg->complete) @@ -537,45 +549,12 @@ static irqreturn_t rk29xx_spi_irq(int irq, void *dev_id) /* Must be called inside pump_transfers() */ static void poll_transfer(struct rk29xx_spi *dws) { - DBG(KERN_INFO "poll_transfer\n"); while (dws->write(dws)) { wait_till_not_busy(dws); dws->read(dws); } transfer_complete(dws); } - -static void dma_transfer(struct rk29xx_spi *dws, struct spi_transfer *xfer) //int cs_change) -{ - unsigned long val; - int ms; - - DBG(KERN_INFO "dma_transfer\n"); - - if (xfer->tx_buf != NULL) { - dws->state |= TXBUSY; - rk29_dma_config(dws->tx_dmach, 4); - rk29_dma_enqueue(dws->tx_dmach, (void *)dws, - xfer->tx_dma, xfer->len); - rk29_dma_ctrl(dws->tx_dmach, RK29_DMAOP_START); - } - - if (xfer->rx_buf != NULL) { - dws->state |= RXBUSY; - rk29_dma_config(dws->rx_dmach, 4); - rk29_dma_enqueue(dws->rx_dmach, (void *)dws, - xfer->rx_dma, xfer->len); - rk29_dma_ctrl(dws->rx_dmach, RK29_DMAOP_START); - } - - /* millisecs to xfer 'len' bytes @ 'cur_speed' */ - ms = xfer->len * 8 * 1000 / dws->cur_speed; - ms += 10; /* some tolerance */ - - val = msecs_to_jiffies(ms) + 10; - val = wait_for_completion_timeout(&dws->xfer_completion, val); -} - static void spi_chip_sel(struct rk29xx_spi *dws, u16 cs) { if(cs >= dws->master->num_chipselect) @@ -612,7 +591,8 @@ static void pump_transfers(unsigned long data) chip = dws->cur_chip; spi = message->spi; if (unlikely(!chip->clk_div)) - chip->clk_div = clk_get_rate(dws->clock_spim) / chip->speed_hz; + //chip->clk_div = clk_get_rate(dws->clock_spim) / chip->speed_hz; + chip->clk_div = 40000000 / chip->speed_hz; if (message->state == ERROR_STATE) { message->status = -EIO; goto early_exit; @@ -673,6 +653,7 @@ static void pump_transfers(unsigned long data) chip->clk_div = clk_div; } } + if (transfer->bits_per_word) { bits = transfer->bits_per_word; @@ -703,6 +684,8 @@ static void pump_transfers(unsigned long data) } cr0 = (spi_dfs << SPI_DFS_OFFSET) + | (SPI_HALF_WORLD_OFF << SPI_HALF_WORLD_TX_OFFSET) + | (SPI_SSN_DELAY_ONE << SPI_SSN_DELAY_OFFSET) | (chip->type << SPI_FRF_OFFSET) | (spi->mode << SPI_MODE_OFFSET) | (chip->tmode << SPI_TMOD_OFFSET); @@ -723,9 +706,7 @@ static void pump_transfers(unsigned long data) cr0 &= ~(0x3 << SPI_MODE_OFFSET); cr0 |= (chip->tmode << SPI_TMOD_OFFSET); - } - /* Check if current transfer is a DMA transaction */ - dws->dma_mapped = map_dma_buffers(dws); + } /* * Interrupt mode @@ -760,13 +741,11 @@ static void pump_transfers(unsigned long data) 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; - } - - if (dws->dma_mapped && transfer->len > DMA_MIN_BYTES) - dma_transfer(dws, transfer); ///cs_change); + } if (chip->poll_mode) poll_transfer(dws); @@ -778,6 +757,269 @@ early_exit: return; } +static void dma_transfer(struct rk29xx_spi *dws) //int cs_change) +{ + struct spi_message *message = NULL; + struct spi_transfer *transfer = NULL; + struct spi_transfer *previous = NULL; + struct spi_device *spi = NULL; + struct chip_data *chip = NULL; + unsigned long val; + int ms; + int iRet; + u8 bits = 0; + u8 spi_dfs = 0; + u8 cs_change = 0; + u16 clk_div = 0; + u32 speed = 0; + u32 cr0 = 0; + u32 dmacr = 0; + + DBG(KERN_INFO "dma_transfer\n"); + + if (acquire_dma(dws)) { + dev_err(&dws->master->dev, "acquire dma failed\n"); + goto err_out; + } + + if (map_dma_buffers(dws)) { + dev_err(&dws->master->dev, "acquire dma failed\n"); + goto err_out; + } + + /* 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 = 40000000 / chip->speed_hz; + if (message->state == ERROR_STATE) { + message->status = -EIO; + goto err_out; + } + + /* Handle end of message */ + if (message->state == DONE_STATE) { + message->status = 0; + goto err_out; + } + + /* Delay if requested at end of transfer*/ + if (message->state == RUNNING_STATE) { + previous = list_entry(transfer->transfer_list.prev, + struct spi_transfer, + transfer_list); + if (previous->delay_usecs) + udelay(previous->delay_usecs); + } + + dws->n_bytes = chip->n_bytes; + dws->dma_width = chip->dma_width; + dws->cs_control = chip->cs_control; + + dws->rx_dma = transfer->rx_dma; + dws->tx_dma = transfer->tx_dma; + dws->tx = (void *)transfer->tx_buf; + dws->tx_end = dws->tx + transfer->len; + dws->rx = transfer->rx_buf; + dws->rx_end = dws->rx + transfer->len; + dws->write = dws->tx ? chip->write : null_writer; + dws->read = dws->rx ? chip->read : null_reader; + dws->cs_change = transfer->cs_change; + dws->len = dws->cur_transfer->len; + if (chip != dws->prev_chip) + cs_change = 1; + + cr0 = chip->cr0; + + /* Handle per transfer options for bpw and speed */ + if (transfer->speed_hz) { + speed = chip->speed_hz; + + if (transfer->speed_hz != speed) { + speed = transfer->speed_hz; + if (speed > clk_get_rate(dws->clock_spim)) { + dev_err(&dws->master->dev, "MRST SPI0: unsupported" + "freq: %dHz\n", speed); + message->status = -EIO; + goto err_out; + } + + /* clk_div doesn't support odd number */ + clk_div = clk_get_rate(dws->clock_spim) / speed; + clk_div = (clk_div + 1) & 0xfffe; + + chip->speed_hz = speed; + chip->clk_div = clk_div; + } + } + + if (transfer->bits_per_word) { + bits = transfer->bits_per_word; + + switch (bits) { + case 8: + dws->n_bytes = 1; + dws->dma_width = 1; + spi_dfs = SPI_DFS_8BIT; + break; + case 16: + dws->n_bytes = 2; + dws->dma_width = 2; + spi_dfs = SPI_DFS_16BIT; + break; + default: + dev_err(&dws->master->dev, "MRST SPI0: unsupported bits:" + "%db\n", bits); + message->status = -EIO; + goto err_out; + } + + cr0 = (spi_dfs << SPI_DFS_OFFSET) + | (SPI_HALF_WORLD_OFF << SPI_HALF_WORLD_TX_OFFSET) + | (SPI_SSN_DELAY_ONE << SPI_SSN_DELAY_OFFSET) + | (chip->type << SPI_FRF_OFFSET) + | (spi->mode << SPI_MODE_OFFSET) + | (chip->tmode << SPI_TMOD_OFFSET); + } + message->state = RUNNING_STATE; + + /* + * Adjust transfer mode if necessary. Requires platform dependent + * chipselect mechanism. + */ + if (dws->cs_control) { + if (dws->rx && dws->tx) + chip->tmode = SPI_TMOD_TR; + else if (dws->rx) + chip->tmode = SPI_TMOD_RO; + else + chip->tmode = SPI_TMOD_TO; + + cr0 &= ~(0x3 << SPI_MODE_OFFSET); + cr0 |= (chip->tmode << SPI_TMOD_OFFSET); + } + + /* + * Reprogram registers only if + * 1. chip select changes + * 2. clk_div is changed + * 3. control value changes + */ + if (rk29xx_readw(dws, SPIM_CTRLR0) != cr0 || cs_change || clk_div) { + spi_enable_chip(dws, 0); + if (rk29xx_readw(dws, SPIM_CTRLR0) != cr0) { + rk29xx_writew(dws, SPIM_CTRLR0, cr0); + } + + spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); + spi_chip_sel(dws, spi->chip_select); + /* Set the interrupt mask, for poll mode just diable all int */ + spi_mask_intr(dws, 0xff); + + if (transfer->tx_buf != NULL) { + dmacr |= SPI_DMACR_TX_ENABLE; + rk29xx_writew(dws, SPIM_DMATDLR, 0); + } + if (transfer->rx_buf != NULL) { + dmacr |= SPI_DMACR_RX_ENABLE; + rk29xx_writew(dws, SPIM_DMARDLR, 0); + rk29xx_writew(dws, SPIM_CTRLR1, transfer->len-1); + } + rk29xx_writew(dws, SPIM_DMACR, dmacr); + spi_enable_chip(dws, 1); + if (cs_change) + dws->prev_chip = chip; + } + + INIT_COMPLETION(dws->xfer_completion); + + if (transfer->tx_buf != NULL) { + dws->state |= TXBUSY; + if (rk29_dma_config(dws->tx_dmach, 1)) { + dev_err(&dws->master->dev, "function: %s, line: %d\n", __FUNCTION__, __LINE__); + goto err_out; + } + + iRet = rk29_dma_enqueue(dws->tx_dmach, (void *)dws, + transfer->tx_dma, transfer->len); + if (iRet) { + dev_err(&dws->master->dev, "function: %s, line: %d, iRet: %d(dws->tx_dmach: %d, transfer->tx_dma: 0x%x)\n", __FUNCTION__, __LINE__, iRet, + dws->tx_dmach, (unsigned int)transfer->tx_dma); + goto err_out; + } + + if (rk29_dma_ctrl(dws->tx_dmach, RK29_DMAOP_START)) { + dev_err(&dws->master->dev, "function: %s, line: %d\n", __FUNCTION__, __LINE__); + goto err_out; + } + } + + if (transfer->rx_buf != NULL) { + dws->state |= RXBUSY; + if (rk29_dma_config(dws->rx_dmach, 1)) { + dev_err(&dws->master->dev, "function: %s, line: %d\n", __FUNCTION__, __LINE__); + goto err_out; + } + + iRet = rk29_dma_enqueue(dws->rx_dmach, (void *)dws, + transfer->rx_dma, transfer->len); + if (iRet) { + dev_err(&dws->master->dev, "function: %s, line: %d\n", __FUNCTION__, __LINE__); + goto err_out; + } + + if (rk29_dma_ctrl(dws->rx_dmach, RK29_DMAOP_START)) { + dev_err(&dws->master->dev, "function: %s, line: %d\n", __FUNCTION__, __LINE__); + goto err_out; + } + } + + /* millisecs to xfer 'len' bytes @ 'cur_speed' */ + ms = transfer->len * 8 * 1000 / dws->cur_chip->speed_hz; + ms += 10; + + val = msecs_to_jiffies(ms) + 500; + if (!wait_for_completion_timeout(&dws->xfer_completion, val)) { + if (transfer->rx_buf != NULL && (dws->state & RXBUSY)) { + rk29_dma_ctrl(dws->rx_dmach, RK29_DMAOP_FLUSH); + dws->state &= ~RXBUSY; + dev_err(&dws->master->dev, "function: %s, line: %d\n", __FUNCTION__, __LINE__); + goto NEXT_TRANSFER; + } + if (transfer->tx_buf != NULL && (dws->state & TXBUSY)) { + rk29_dma_ctrl(dws->tx_dmach, RK29_DMAOP_FLUSH); + dws->state &= ~TXBUSY; + dev_err(&dws->master->dev, "function: %s, line: %d\n", __FUNCTION__, __LINE__); + goto NEXT_TRANSFER; + } + } + + wait_till_not_busy(dws); + +NEXT_TRANSFER: + /* Update total byte transfered return count actual bytes read */ + dws->cur_msg->actual_length += dws->len; + + /* Move to next transfer */ + dws->cur_msg->state = next_transfer(dws); + + /* Handle end of message */ + if (dws->cur_msg->state == DONE_STATE) { + dws->cur_msg->status = 0; + giveback(dws); + } else + dma_transfer(dws); + + return; + +err_out: + giveback(dws); + return; + +} + static void pump_messages(struct work_struct *work) { struct rk29xx_spi *dws = @@ -786,9 +1028,6 @@ static void pump_messages(struct work_struct *work) DBG(KERN_INFO "pump_messages\n"); - while (!acquire_dma(dws)) - msleep(10); - /* Lock queue and check for queue work */ spin_lock_irqsave(&dws->lock, flags); if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) { @@ -816,7 +1055,15 @@ static void pump_messages(struct work_struct *work) dws->prev_chip = NULL; //ÿ¸öpump messageʱǿÖƸüÐÂcs dxj /* Mark as busy and launch transfers */ - tasklet_schedule(&dws->pump_transfers); + 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); + return; + } + else { + tasklet_schedule(&dws->pump_transfers); + } dws->busy = 1; spin_unlock_irqrestore(&dws->lock, flags); @@ -1116,15 +1363,10 @@ static int rk29xx_pump_transfers(struct rk29xx_spi *dws, int mode) if (cs_change) dws->prev_chip = chip; - if (dws->dma_mapped && transfer->len > DMA_MIN_BYTES) { - dma_transfer(dws, transfer); - } - else { - if (mode) - return do_full_transfer(dws); - else - return do_half_transfer(dws); - } + if (mode) + return do_full_transfer(dws); + else + return do_half_transfer(dws); early_exit: @@ -1319,6 +1561,8 @@ static int rk29xx_spi_setup(struct spi_device *spi) chip->tmode = 0; /* Tx & Rx */ /* Default SPI mode is SCPOL = 0, SCPH = 0 */ chip->cr0 = (spi_dfs << SPI_DFS_OFFSET) + | (SPI_HALF_WORLD_OFF << SPI_HALF_WORLD_TX_OFFSET) + | (SPI_SSN_DELAY_ONE << SPI_SSN_DELAY_OFFSET) | (chip->type << SPI_FRF_OFFSET) | (spi->mode << SPI_MODE_OFFSET) | (chip->tmode << SPI_TMOD_OFFSET); @@ -1341,6 +1585,8 @@ static int __devinit init_queue(struct rk29xx_spi *dws) dws->run = QUEUE_STOPPED; dws->busy = 0; + init_completion(&dws->xfer_completion); + tasklet_init(&dws->pump_transfers, pump_transfers, (unsigned long)dws); @@ -1582,7 +1828,7 @@ static int __init rk29xx_spim_probe(struct platform_device *pdev) ret =rk29xx_spim_cpufreq_register(dws); if (ret < 0) { - printk(KERN_ERR"rk29xx spim failed to init cpufreq support\n"); + dev_err(&master->dev, "rk29xx spim failed to init cpufreq support\n"); goto err_queue_alloc; } DBG(KERN_INFO "rk29xx_spim: driver initialized\n"); @@ -1612,6 +1858,8 @@ static void __exit rk29xx_spim_remove(struct platform_device *pdev) rk29xx_spim_cpufreq_deregister(dws); mrst_spi_debugfs_remove(dws); + release_dma(dws); + /* Remove the queue */ status = destroy_queue(dws); if (status != 0) diff --git a/drivers/spi/rk29xx_spim.h b/drivers/spi/rk29xx_spim.h index e26545b24397..fb3ab62c602d 100755 --- a/drivers/spi/rk29xx_spim.h +++ b/drivers/spi/rk29xx_spim.h @@ -73,6 +73,14 @@ #define SPI_CSM_HALF 0x01 /* ss_n be high for half sclk_out cycles after every frame data is transferred */ #define SPI_CSM_ONE 0x02 /* ss_n be high for one sclk_out cycle after every frame data is transferred */ +#define SPI_SSN_DELAY_OFFSET 10 +#define SPI_SSN_DELAY_HALF 0x00 +#define SPI_SSN_DELAY_ONE 0x01 + +#define SPI_HALF_WORLD_TX_OFFSET 13 +#define SPI_HALF_WORLD_ON 0x00 +#define SPI_HALF_WORLD_OFF 0x01 + /* --------Bit fields in CTRLR0--------end */ -- 2.34.1