From c586feba880d78cab1882e1faee0395bba2b884f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 31 Mar 2014 11:37:29 +0800 Subject: spi: s3c24xx: Convert to use devm_kzalloc Simplify the cleanup code. Signed-off-by: Axel Lin Reviewed-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/spi/spi-s3c24xx.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index bed23384dfab..6db14e53af17 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -183,7 +183,9 @@ static int s3c24xx_spi_setup(struct spi_device *spi) /* allocate settings on the first call */ if (!cs) { - cs = kzalloc(sizeof(struct s3c24xx_spi_devstate), GFP_KERNEL); + cs = devm_kzalloc(&spi->dev, + sizeof(struct s3c24xx_spi_devstate), + GFP_KERNEL); if (!cs) { dev_err(&spi->dev, "no memory for controller state\n"); return -ENOMEM; @@ -209,11 +211,6 @@ static int s3c24xx_spi_setup(struct spi_device *spi) return 0; } -static void s3c24xx_spi_cleanup(struct spi_device *spi) -{ - kfree(spi->controller_state); -} - static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count) { return hw->tx ? hw->tx[count] : 0; @@ -543,7 +540,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) hw->bitbang.txrx_bufs = s3c24xx_spi_txrx; hw->master->setup = s3c24xx_spi_setup; - hw->master->cleanup = s3c24xx_spi_cleanup; dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang); -- cgit v1.2.3 From d77ec5df47696300b9498e6973dcc34b40de8d27 Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Mon, 14 Apr 2014 14:30:00 +0800 Subject: spi: sirf: fix line over 80 characters style issue fix a lot of "line over 80 characters" checkpatch issues, on which the users of the driver, key customers care about this very much. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 51 +++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 67d8909dcf39..3c12f396d96a 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -382,14 +382,16 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) if (IS_DMA_VALID(t)) { struct dma_async_tx_descriptor *rx_desc, *tx_desc; - sspi->dst_start = dma_map_single(&spi->dev, sspi->rx, t->len, DMA_FROM_DEVICE); + sspi->dst_start = dma_map_single(&spi->dev, + sspi->rx, t->len, DMA_FROM_DEVICE); rx_desc = dmaengine_prep_slave_single(sspi->rx_chan, sspi->dst_start, t->len, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); rx_desc->callback = spi_sirfsoc_dma_fini_callback; rx_desc->callback_param = &sspi->rx_done; - sspi->src_start = dma_map_single(&spi->dev, (void *)sspi->tx, t->len, DMA_TO_DEVICE); + sspi->src_start = dma_map_single(&spi->dev, + (void *)sspi->tx, t->len, DMA_TO_DEVICE); tx_desc = dmaengine_prep_slave_single(sspi->tx_chan, sspi->src_start, t->len, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -404,13 +406,18 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) /* Send the first word to trigger the whole tx/rx process */ sspi->tx_word(sspi); - writel(SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN | - SIRFSOC_SPI_RXFIFO_THD_INT_EN | SIRFSOC_SPI_TXFIFO_THD_INT_EN | - SIRFSOC_SPI_FRM_END_INT_EN | SIRFSOC_SPI_RXFIFO_FULL_INT_EN | - SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN, sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_RX_OFLOW_INT_EN | + SIRFSOC_SPI_TX_UFLOW_INT_EN | + SIRFSOC_SPI_RXFIFO_THD_INT_EN | + SIRFSOC_SPI_TXFIFO_THD_INT_EN | + SIRFSOC_SPI_FRM_END_INT_EN | + SIRFSOC_SPI_RXFIFO_FULL_INT_EN | + SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN, + sspi->base + SIRFSOC_SPI_INT_EN); } - writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, sspi->base + SIRFSOC_SPI_TX_RX_EN); + writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, + sspi->base + SIRFSOC_SPI_TX_RX_EN); if (!IS_DMA_VALID(t)) { /* for PIO */ if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) @@ -434,8 +441,10 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) } if (IS_DMA_VALID(t)) { - dma_unmap_single(&spi->dev, sspi->src_start, t->len, DMA_TO_DEVICE); - dma_unmap_single(&spi->dev, sspi->dst_start, t->len, DMA_FROM_DEVICE); + dma_unmap_single(&spi->dev, + sspi->src_start, t->len, DMA_TO_DEVICE); + dma_unmap_single(&spi->dev, + sspi->dst_start, t->len, DMA_FROM_DEVICE); } /* TX, RX FIFO stop */ @@ -512,7 +521,8 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) break; case 12: case 16: - regval |= (bits_per_word == 12) ? SIRFSOC_SPI_TRAN_DAT_FORMAT_12 : + regval |= (bits_per_word == 12) ? + SIRFSOC_SPI_TRAN_DAT_FORMAT_12 : SIRFSOC_SPI_TRAN_DAT_FORMAT_16; sspi->rx_word = spi_sirfsoc_rx_word_u16; sspi->tx_word = spi_sirfsoc_tx_word_u16; @@ -540,8 +550,8 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) regval |= SIRFSOC_SPI_CLK_IDLE_STAT; /* - * Data should be driven at least 1/2 cycle before the fetch edge to make - * sure that data gets stable at the fetch edge. + * Data should be driven at least 1/2 cycle before the fetch edge + * to make sure that data gets stable at the fetch edge. */ if (((spi->mode & SPI_CPOL) && (spi->mode & SPI_CPHA)) || (!(spi->mode & SPI_CPOL) && !(spi->mode & SPI_CPHA))) @@ -578,11 +588,14 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) if (IS_DMA_VALID(t)) { /* Enable DMA mode for RX, TX */ writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL); - writel(SIRFSOC_SPI_RX_DMA_FLUSH, sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL); + writel(SIRFSOC_SPI_RX_DMA_FLUSH, + sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL); } else { /* Enable IO mode for RX, TX */ - writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL); - writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL); + writel(SIRFSOC_SPI_IO_MODE_SEL, + sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL); + writel(SIRFSOC_SPI_IO_MODE_SEL, + sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL); } return 0; @@ -612,7 +625,8 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) goto err_cs; } - master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs); + master = spi_alloc_master(&pdev->dev, + sizeof(*sspi) + sizeof(int) * num_cs); if (!master) { dev_err(&pdev->dev, "Unable to allocate SPI master\n"); return -ENOMEM; @@ -808,8 +822,7 @@ static struct platform_driver spi_sirfsoc_driver = { .remove = spi_sirfsoc_remove, }; module_platform_driver(spi_sirfsoc_driver); - MODULE_DESCRIPTION("SiRF SoC SPI master driver"); -MODULE_AUTHOR("Zhiwu Song , " - "Barry Song "); +MODULE_AUTHOR("Zhiwu Song "); +MODULE_AUTHOR("Barry Song "); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From bf83fd6402a856eeb9a22c364c50ccf9bbdf9b17 Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Mon, 14 Apr 2014 14:30:01 +0800 Subject: spi: sirf: fix spi full-duplex DMA transferring issue sometimes t->tx can be equal with t->rx. for example, spidev will make tx and rx point to spidev->buffer at the same time. currently, for this case, we map the buffer BIDIRECTION to fix the cache consistency. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 3c12f396d96a..0c039d4542a5 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -383,7 +383,8 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) struct dma_async_tx_descriptor *rx_desc, *tx_desc; sspi->dst_start = dma_map_single(&spi->dev, - sspi->rx, t->len, DMA_FROM_DEVICE); + sspi->rx, t->len, (t->tx_buf != t->rx_buf) ? + DMA_FROM_DEVICE : DMA_BIDIRECTIONAL); rx_desc = dmaengine_prep_slave_single(sspi->rx_chan, sspi->dst_start, t->len, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -391,7 +392,9 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) rx_desc->callback_param = &sspi->rx_done; sspi->src_start = dma_map_single(&spi->dev, - (void *)sspi->tx, t->len, DMA_TO_DEVICE); + (void *)sspi->tx, t->len, + (t->tx_buf != t->rx_buf) ? + DMA_TO_DEVICE : DMA_BIDIRECTIONAL); tx_desc = dmaengine_prep_slave_single(sspi->tx_chan, sspi->src_start, t->len, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); -- cgit v1.2.3 From c908ef345d2c314ec25cfac113a8f9bb2b6b3a25 Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Tue, 15 Apr 2014 15:24:59 +0800 Subject: spi: sirf: refactor spi transfer functions split sirfsoc_spi_transfer function into 3 sub-functions: spi_sirfsoc_cmd_transfer, spi_sirfsoc_pio_transfer and spi_sirfsoc_dma_transfer. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 232 ++++++++++++++++++++++++++----------------------- 1 file changed, 123 insertions(+), 109 deletions(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 0c039d4542a5..2d238990115c 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -309,59 +310,51 @@ static void spi_sirfsoc_dma_fini_callback(void *data) complete(dma_complete); } -static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) +static int spi_sirfsoc_cmd_transfer(struct spi_device *spi, + struct spi_transfer *t) { struct sirfsoc_spi *sspi; int timeout = t->len * 10; - sspi = spi_master_get_devdata(spi->master); + u32 cmd; - sspi->tx = t->tx_buf ? t->tx_buf : sspi->dummypage; - sspi->rx = t->rx_buf ? t->rx_buf : sspi->dummypage; - sspi->left_tx_word = sspi->left_rx_word = t->len / sspi->word_width; - reinit_completion(&sspi->rx_done); - reinit_completion(&sspi->tx_done); - - writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); - - /* - * fill tx_buf into command register and wait for its completion - */ - if (sspi->tx_by_cmd) { - u32 cmd; - memcpy(&cmd, sspi->tx, t->len); - - if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST)) - cmd = cpu_to_be32(cmd) >> - ((SIRFSOC_MAX_CMD_BYTES - t->len) * 8); - if (sspi->word_width == 2 && t->len == 4 && - (!(spi->mode & SPI_LSB_FIRST))) - cmd = ((cmd & 0xffff) << 16) | (cmd >> 16); - - writel(cmd, sspi->base + SIRFSOC_SPI_CMD); - writel(SIRFSOC_SPI_FRM_END_INT_EN, - sspi->base + SIRFSOC_SPI_INT_EN); - writel(SIRFSOC_SPI_CMD_TX_EN, - sspi->base + SIRFSOC_SPI_TX_RX_EN); + sspi = spi_master_get_devdata(spi->master); + memcpy(&cmd, sspi->tx, t->len); + if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST)) + cmd = cpu_to_be32(cmd) >> + ((SIRFSOC_MAX_CMD_BYTES - t->len) * 8); + if (sspi->word_width == 2 && t->len == 4 && + (!(spi->mode & SPI_LSB_FIRST))) + cmd = ((cmd & 0xffff) << 16) | (cmd >> 16); + writel(cmd, sspi->base + SIRFSOC_SPI_CMD); + writel(SIRFSOC_SPI_FRM_END_INT_EN, + sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_CMD_TX_EN, + sspi->base + SIRFSOC_SPI_TX_RX_EN); + if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { + dev_err(&spi->dev, "cmd transfer timeout\n"); + return 0; + } - if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { - dev_err(&spi->dev, "transfer timeout\n"); - return 0; - } + return t->len; +} - return t->len; - } +static void spi_sirfsoc_dma_transfer(struct spi_device *spi, + struct spi_transfer *t) +{ + struct sirfsoc_spi *sspi; + struct dma_async_tx_descriptor *rx_desc, *tx_desc; + int timeout = t->len * 10; - if (sspi->left_tx_word == 1) { - writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | - SIRFSOC_SPI_ENA_AUTO_CLR, - sspi->base + SIRFSOC_SPI_CTRL); - writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); - writel(0, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); - } else if ((sspi->left_tx_word > 1) && (sspi->left_tx_word < - SIRFSOC_SPI_DAT_FRM_LEN_MAX)) { + sspi = spi_master_get_devdata(spi->master); + writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + writel(0, sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); + if (sspi->left_tx_word < SIRFSOC_SPI_DAT_FRM_LEN_MAX) { writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | - SIRFSOC_SPI_MUL_DAT_MODE | - SIRFSOC_SPI_ENA_AUTO_CLR, + SIRFSOC_SPI_ENA_AUTO_CLR | SIRFSOC_SPI_MUL_DAT_MODE, sspi->base + SIRFSOC_SPI_CTRL); writel(sspi->left_tx_word - 1, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); @@ -373,88 +366,109 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); writel(0, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); } - - writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP); - writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP); - writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); - writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); - - if (IS_DMA_VALID(t)) { - struct dma_async_tx_descriptor *rx_desc, *tx_desc; - - sspi->dst_start = dma_map_single(&spi->dev, - sspi->rx, t->len, (t->tx_buf != t->rx_buf) ? - DMA_FROM_DEVICE : DMA_BIDIRECTIONAL); - rx_desc = dmaengine_prep_slave_single(sspi->rx_chan, - sspi->dst_start, t->len, DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - rx_desc->callback = spi_sirfsoc_dma_fini_callback; - rx_desc->callback_param = &sspi->rx_done; - - sspi->src_start = dma_map_single(&spi->dev, - (void *)sspi->tx, t->len, - (t->tx_buf != t->rx_buf) ? - DMA_TO_DEVICE : DMA_BIDIRECTIONAL); - tx_desc = dmaengine_prep_slave_single(sspi->tx_chan, - sspi->src_start, t->len, DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - tx_desc->callback = spi_sirfsoc_dma_fini_callback; - tx_desc->callback_param = &sspi->tx_done; - - dmaengine_submit(tx_desc); - dmaengine_submit(rx_desc); - dma_async_issue_pending(sspi->tx_chan); - dma_async_issue_pending(sspi->rx_chan); - } else { - /* Send the first word to trigger the whole tx/rx process */ - sspi->tx_word(sspi); - - writel(SIRFSOC_SPI_RX_OFLOW_INT_EN | - SIRFSOC_SPI_TX_UFLOW_INT_EN | - SIRFSOC_SPI_RXFIFO_THD_INT_EN | - SIRFSOC_SPI_TXFIFO_THD_INT_EN | - SIRFSOC_SPI_FRM_END_INT_EN | - SIRFSOC_SPI_RXFIFO_FULL_INT_EN | - SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN, - sspi->base + SIRFSOC_SPI_INT_EN); - } - + sspi->dst_start = dma_map_single(&spi->dev, sspi->rx, t->len, + (t->tx_buf != t->rx_buf) ? + DMA_FROM_DEVICE : DMA_BIDIRECTIONAL); + rx_desc = dmaengine_prep_slave_single(sspi->rx_chan, + sspi->dst_start, t->len, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + rx_desc->callback = spi_sirfsoc_dma_fini_callback; + rx_desc->callback_param = &sspi->rx_done; + + sspi->src_start = dma_map_single(&spi->dev, (void *)sspi->tx, t->len, + (t->tx_buf != t->rx_buf) ? + DMA_TO_DEVICE : DMA_BIDIRECTIONAL); + tx_desc = dmaengine_prep_slave_single(sspi->tx_chan, + sspi->src_start, t->len, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + tx_desc->callback = spi_sirfsoc_dma_fini_callback; + tx_desc->callback_param = &sspi->tx_done; + + dmaengine_submit(tx_desc); + dmaengine_submit(rx_desc); + dma_async_issue_pending(sspi->tx_chan); + dma_async_issue_pending(sspi->rx_chan); writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, sspi->base + SIRFSOC_SPI_TX_RX_EN); - - if (!IS_DMA_VALID(t)) { /* for PIO */ - if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) - dev_err(&spi->dev, "transfer timeout\n"); - } else if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) { + if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) { dev_err(&spi->dev, "transfer timeout\n"); dmaengine_terminate_all(sspi->rx_chan); } else sspi->left_rx_word = 0; - /* * we only wait tx-done event if transferring by DMA. for PIO, * we get rx data by writing tx data, so if rx is done, tx has * done earlier */ - if (IS_DMA_VALID(t)) { - if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { - dev_err(&spi->dev, "transfer timeout\n"); - dmaengine_terminate_all(sspi->tx_chan); - } + if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { + dev_err(&spi->dev, "transfer timeout\n"); + dmaengine_terminate_all(sspi->tx_chan); } + dma_unmap_single(&spi->dev, sspi->src_start, t->len, DMA_TO_DEVICE); + dma_unmap_single(&spi->dev, sspi->dst_start, t->len, DMA_FROM_DEVICE); + /* TX, RX FIFO stop */ + writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + if (sspi->left_tx_word >= SIRFSOC_SPI_DAT_FRM_LEN_MAX) + writel(0, sspi->base + SIRFSOC_SPI_TX_RX_EN); +} - if (IS_DMA_VALID(t)) { - dma_unmap_single(&spi->dev, - sspi->src_start, t->len, DMA_TO_DEVICE); - dma_unmap_single(&spi->dev, - sspi->dst_start, t->len, DMA_FROM_DEVICE); - } +static void spi_sirfsoc_pio_transfer(struct spi_device *spi, + struct spi_transfer *t) +{ + struct sirfsoc_spi *sspi; + int timeout = t->len * 10; - /* TX, RX FIFO stop */ + sspi = spi_master_get_devdata(spi->master); + writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + writel(0, sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); + writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | SIRFSOC_SPI_MUL_DAT_MODE | + SIRFSOC_SPI_ENA_AUTO_CLR, sspi->base + SIRFSOC_SPI_CTRL); + writel(sspi->left_tx_word - 1, + sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); + writel(sspi->left_rx_word - 1, + sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); + sspi->tx_word(sspi); + writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN | + SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_RXFIFO_THD_INT_EN | + SIRFSOC_SPI_TXFIFO_THD_INT_EN | SIRFSOC_SPI_FRM_END_INT_EN| + SIRFSOC_SPI_RXFIFO_FULL_INT_EN, + sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, + sspi->base + SIRFSOC_SPI_TX_RX_EN); + if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) + dev_err(&spi->dev, "transfer timeout\n"); writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP); writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP); writel(0, sspi->base + SIRFSOC_SPI_TX_RX_EN); writel(0, sspi->base + SIRFSOC_SPI_INT_EN); +} + +static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) +{ + struct sirfsoc_spi *sspi; + sspi = spi_master_get_devdata(spi->master); + + sspi->tx = t->tx_buf ? t->tx_buf : sspi->dummypage; + sspi->rx = t->rx_buf ? t->rx_buf : sspi->dummypage; + sspi->left_tx_word = sspi->left_rx_word = t->len / sspi->word_width; + reinit_completion(&sspi->rx_done); + reinit_completion(&sspi->tx_done); + /* + * in the transfer, if transfer data using command register with rx_buf + * null, just fill command data into command register and wait for its + * completion. + */ + if (sspi->tx_by_cmd) + spi_sirfsoc_cmd_transfer(spi, t); + else if (IS_DMA_VALID(t)) + spi_sirfsoc_dma_transfer(spi, t); + else + spi_sirfsoc_pio_transfer(spi, t); return t->len - sspi->left_rx_word * sspi->word_width; } -- cgit v1.2.3 From d6ba32d5c60f569d252ec9dcd96cd46b19785b60 Mon Sep 17 00:00:00 2001 From: "Chew, Chiau Ee" Date: Fri, 18 Apr 2014 00:26:06 +0800 Subject: spi/pxa2xx-pci: Add PCI mode support for BayTrail LPSS SPI Similar to CE4100, BayTrail LPSS SPI can be PCI enumerated as well. Thus, the functions are renamed from ce4100_xxx to pxa2xx_spi_pci_xxx to clarify that this is a generic PCI glue layer. Also, added required infrastructure to support SPI hosts with different configurations. This patch is based on Mika Westerberg's previous work. Signed-off-by: Chew, Chiau Ee Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 76 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 3f006d3ed2a8..c1865c92ccb9 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -8,7 +8,43 @@ #include #include -static int ce4100_spi_probe(struct pci_dev *dev, +enum { + PORT_CE4100, + PORT_BYT, +}; + +struct pxa_spi_info { + enum pxa_ssp_type type; + int port_id; + int num_chipselect; + int tx_slave_id; + int tx_chan_id; + int rx_slave_id; + int rx_chan_id; +}; + +static struct pxa_spi_info spi_info_configs[] = { + [PORT_CE4100] = { + .type = PXA25x_SSP, + .port_id = -1, + .num_chipselect = -1, + .tx_slave_id = -1, + .tx_chan_id = -1, + .rx_slave_id = -1, + .rx_chan_id = -1, + }, + [PORT_BYT] = { + .type = LPSS_SSP, + .port_id = 0, + .num_chipselect = 1, + .tx_slave_id = 0, + .tx_chan_id = 0, + .rx_slave_id = 1, + .rx_chan_id = 1, + }, +}; + +static int pxa2xx_spi_pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { struct platform_device_info pi; @@ -16,6 +52,7 @@ static int ce4100_spi_probe(struct pci_dev *dev, struct platform_device *pdev; struct pxa2xx_spi_master spi_pdata; struct ssp_device *ssp; + struct pxa_spi_info *c; ret = pcim_enable_device(dev); if (ret) @@ -25,8 +62,16 @@ static int ce4100_spi_probe(struct pci_dev *dev, if (ret) return ret; + c = &spi_info_configs[ent->driver_data]; + memset(&spi_pdata, 0, sizeof(spi_pdata)); - spi_pdata.num_chipselect = dev->devfn; + spi_pdata.num_chipselect = (c->num_chipselect > 0) ? + c->num_chipselect : dev->devfn; + spi_pdata.tx_slave_id = c->tx_slave_id; + spi_pdata.tx_chan_id = c->tx_chan_id; + spi_pdata.rx_slave_id = c->rx_slave_id; + spi_pdata.rx_chan_id = c->rx_chan_id; + spi_pdata.enable_dma = c->rx_slave_id >= 0 && c->tx_slave_id >= 0; ssp = &spi_pdata.ssp; ssp->phys_base = pci_resource_start(dev, 0); @@ -36,8 +81,8 @@ static int ce4100_spi_probe(struct pci_dev *dev, return -EIO; } ssp->irq = dev->irq; - ssp->port_id = dev->devfn; - ssp->type = PXA25x_SSP; + ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn; + ssp->type = c->type; memset(&pi, 0, sizeof(pi)); pi.parent = &dev->dev; @@ -55,28 +100,29 @@ static int ce4100_spi_probe(struct pci_dev *dev, return 0; } -static void ce4100_spi_remove(struct pci_dev *dev) +static void pxa2xx_spi_pci_remove(struct pci_dev *dev) { struct platform_device *pdev = pci_get_drvdata(dev); platform_device_unregister(pdev); } -static const struct pci_device_id ce4100_spi_devices[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) }, +static const struct pci_device_id pxa2xx_spi_pci_devices[] = { + { PCI_VDEVICE(INTEL, 0x2e6a), PORT_CE4100 }, + { PCI_VDEVICE(INTEL, 0x0f0e), PORT_BYT }, { }, }; -MODULE_DEVICE_TABLE(pci, ce4100_spi_devices); +MODULE_DEVICE_TABLE(pci, pxa2xx_spi_pci_devices); -static struct pci_driver ce4100_spi_driver = { - .name = "ce4100_spi", - .id_table = ce4100_spi_devices, - .probe = ce4100_spi_probe, - .remove = ce4100_spi_remove, +static struct pci_driver pxa2xx_spi_pci_driver = { + .name = "pxa2xx_spi_pci", + .id_table = pxa2xx_spi_pci_devices, + .probe = pxa2xx_spi_pci_probe, + .remove = pxa2xx_spi_pci_remove, }; -module_pci_driver(ce4100_spi_driver); +module_pci_driver(pxa2xx_spi_pci_driver); -MODULE_DESCRIPTION("CE4100 PCI-SPI glue code for PXA's driver"); +MODULE_DESCRIPTION("CE4100/LPSS PCI-SPI glue code for PXA's driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Sebastian Andrzej Siewior "); -- cgit v1.2.3 From 77538f4a98dc542ad25a1c0fa3b79c5f90c47619 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:19:01 +0900 Subject: spi: pl022: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/spi/spi-pl022.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 51d99779682f..66d2ae21e78e 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -1111,10 +1111,8 @@ static int pl022_dma_probe(struct pl022 *pl022) } pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!pl022->dummypage) { - dev_dbg(&pl022->adev->dev, "no DMA dummypage!\n"); + if (!pl022->dummypage) goto err_no_dummypage; - } dev_info(&pl022->adev->dev, "setup for DMA on RX %s, TX %s\n", dma_chan_name(pl022->dma_rx_channel), @@ -1809,11 +1807,8 @@ static int pl022_setup(struct spi_device *spi) if (chip == NULL) { chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); - if (!chip) { - dev_err(&spi->dev, - "cannot allocate controller state\n"); + if (!chip) return -ENOMEM; - } dev_dbg(&spi->dev, "allocated memory for controller's runtime state\n"); } @@ -2050,10 +2045,8 @@ pl022_platform_data_dt_get(struct device *dev) } pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL); - if (!pd) { - dev_err(dev, "cannot allocate platform data memory\n"); + if (!pd) return NULL; - } pd->bus_id = -1; pd->enable_dma = 1; -- cgit v1.2.3 From 9deae4592b66c0b2a7832fefa192e7a506ce047e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:19:38 +0900 Subject: spi: pxa2xx: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 41185d0557fa..54e4e6593980 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -886,11 +886,8 @@ static int setup(struct spi_device *spi) chip = spi_get_ctldata(spi); if (!chip) { chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); - if (!chip) { - dev_err(&spi->dev, - "failed setup: can't allocate chip data\n"); + if (!chip) return -ENOMEM; - } if (drv_data->ssp_type == CE4100_SSP) { if (spi->chip_select > 4) { @@ -1037,11 +1034,8 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) return NULL; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(&pdev->dev, - "failed to allocate memory for platform data\n"); + if (!pdata) return NULL; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) -- cgit v1.2.3 From 0375cff5d8c9da86787167da2740b6e5c50963da Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:20:02 +0900 Subject: spi: s3c24xx: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/spi/spi-s3c24xx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index 6db14e53af17..381d4af149fc 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -186,10 +186,8 @@ static int s3c24xx_spi_setup(struct spi_device *spi) cs = devm_kzalloc(&spi->dev, sizeof(struct s3c24xx_spi_devstate), GFP_KERNEL); - if (!cs) { - dev_err(&spi->dev, "no memory for controller state\n"); + if (!cs) return -ENOMEM; - } cs->spcon = SPCON_DEFAULT; cs->hz = -1; -- cgit v1.2.3 From 1273eb0506c474a128d06025de98c5ca4a11cf14 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:20:20 +0900 Subject: spi: s3c64xx: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index f19cd97855e8..affcfd6fe76b 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -773,7 +773,6 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( cs = kzalloc(sizeof(*cs), GFP_KERNEL); if (!cs) { - dev_err(&spi->dev, "could not allocate memory for controller data\n"); of_node_put(data_np); return ERR_PTR(-ENOMEM); } @@ -987,10 +986,8 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev) u32 temp; sci = devm_kzalloc(dev, sizeof(*sci), GFP_KERNEL); - if (!sci) { - dev_err(dev, "memory allocation for spi_info failed\n"); + if (!sci) return ERR_PTR(-ENOMEM); - } if (of_property_read_u32(dev->of_node, "samsung,spi-src-clk", &temp)) { dev_warn(dev, "spi bus clock parent not specified, using clock at index 0 as parent\n"); -- cgit v1.2.3 From 1e8231b79ccbb3e6e7b3f6af9f998dca16b00efe Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:21:25 +0900 Subject: spi: sh-msiof: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index e850d03e7190..45b09142afe2 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -642,10 +642,8 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) u32 num_cs = 1; info = devm_kzalloc(dev, sizeof(struct sh_msiof_spi_info), GFP_KERNEL); - if (!info) { - dev_err(dev, "failed to allocate setup data\n"); + if (!info) return NULL; - } /* Parse the MSIOF properties */ of_property_read_u32(np, "num-cs", &num_cs); -- cgit v1.2.3 From 9f48e54bf70018547b0c146b4187489c615bd3a2 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:22:32 +0900 Subject: spi: tle62x0: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/spi/spi-tle62x0.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c index 2d4010d80824..daf5aa1c24c3 100644 --- a/drivers/spi/spi-tle62x0.c +++ b/drivers/spi/spi-tle62x0.c @@ -253,10 +253,8 @@ static int tle62x0_probe(struct spi_device *spi) } st = kzalloc(sizeof(struct tle62x0_state), GFP_KERNEL); - if (st == NULL) { - dev_err(&spi->dev, "no memory for device state\n"); + if (st == NULL) return -ENOMEM; - } st->us = spi; st->nr_gpio = pdata->gpio_count; -- cgit v1.2.3 From fe75cbc1bd94d9e7d837b31f4373d55d7dd91019 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 29 Apr 2014 17:23:10 +0900 Subject: spi: topcliff-pch: remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/spi/spi-topcliff-pch.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index f406b30af961..f05abf89c067 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1578,14 +1578,11 @@ static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct pch_pd_dev_save *pd_dev_save; pd_dev_save = kzalloc(sizeof(struct pch_pd_dev_save), GFP_KERNEL); - if (!pd_dev_save) { - dev_err(&pdev->dev, "%s Can't allocate pd_dev_sav\n", __func__); + if (!pd_dev_save) return -ENOMEM; - } board_dat = kzalloc(sizeof(struct pch_spi_board_data), GFP_KERNEL); if (!board_dat) { - dev_err(&pdev->dev, "%s Can't allocate board_dat\n", __func__); retval = -ENOMEM; goto err_no_mem; } -- cgit v1.2.3 From 41148c3a728222a885bc2f3ba3ce66831de0b244 Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Sun, 4 May 2014 14:32:36 +0800 Subject: spi: sirf: decrease the interrupt count and latency of PIO mode current PIO tranfer method be described as follows: 1. fill as much as bytes but no more than 256 bytes(fifo size) 2. enable oflow/uflow/txfifo_empty interrupt 3. isr process 3 interrupt signal, do complete works. 4. after isr done, if there are left bytes go into 1 else go into 5 5. transfer end by current PIO transfer method: 1. reduce interrupt counts in spi interrupt line. 2. reduce interrupt latency because no do data fill/fetch in isr. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 101 ++++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 47 deletions(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 2d238990115c..95ac276eaafe 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -86,6 +86,7 @@ #define SIRFSOC_SPI_TX_DONE BIT(1) #define SIRFSOC_SPI_RX_OFLOW BIT(2) #define SIRFSOC_SPI_TX_UFLOW BIT(3) +#define SIRFSOC_SPI_RX_IO_DMA BIT(4) #define SIRFSOC_SPI_RX_FIFO_FULL BIT(6) #define SIRFSOC_SPI_TXFIFO_EMPTY BIT(7) #define SIRFSOC_SPI_RXFIFO_THD_REACH BIT(8) @@ -265,41 +266,34 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id) { struct sirfsoc_spi *sspi = dev_id; u32 spi_stat = readl(sspi->base + SIRFSOC_SPI_INT_STATUS); - - writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS); - if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) { complete(&sspi->tx_done); writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_INT_MASK_ALL, + sspi->base + SIRFSOC_SPI_INT_STATUS); return IRQ_HANDLED; } /* Error Conditions */ if (spi_stat & SIRFSOC_SPI_RX_OFLOW || spi_stat & SIRFSOC_SPI_TX_UFLOW) { + complete(&sspi->tx_done); complete(&sspi->rx_done); writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_INT_MASK_ALL, + sspi->base + SIRFSOC_SPI_INT_STATUS); + return IRQ_HANDLED; } + if (spi_stat & SIRFSOC_SPI_TXFIFO_EMPTY) + complete(&sspi->tx_done); + while (!(readl(sspi->base + SIRFSOC_SPI_INT_STATUS) & + SIRFSOC_SPI_RX_IO_DMA)) + cpu_relax(); + complete(&sspi->rx_done); + writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_INT_MASK_ALL, + sspi->base + SIRFSOC_SPI_INT_STATUS); - if (spi_stat & (SIRFSOC_SPI_FRM_END - | SIRFSOC_SPI_RXFIFO_THD_REACH)) - while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS) - & SIRFSOC_SPI_FIFO_EMPTY)) && - sspi->left_rx_word) - sspi->rx_word(sspi); - - if (spi_stat & (SIRFSOC_SPI_TXFIFO_EMPTY | - SIRFSOC_SPI_TXFIFO_THD_REACH)) - while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS) - & SIRFSOC_SPI_FIFO_FULL)) && - sspi->left_tx_word) - sspi->tx_word(sspi); - - /* Received all words */ - if ((sspi->left_rx_word == 0) && (sspi->left_tx_word == 0)) { - complete(&sspi->rx_done); - writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); - } return IRQ_HANDLED; } @@ -420,32 +414,45 @@ static void spi_sirfsoc_pio_transfer(struct spi_device *spi, int timeout = t->len * 10; sspi = spi_master_get_devdata(spi->master); - writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP); - writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP); - writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); - writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); - writel(0, sspi->base + SIRFSOC_SPI_INT_EN); - writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); - writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | SIRFSOC_SPI_MUL_DAT_MODE | - SIRFSOC_SPI_ENA_AUTO_CLR, sspi->base + SIRFSOC_SPI_CTRL); - writel(sspi->left_tx_word - 1, - sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); - writel(sspi->left_rx_word - 1, - sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); - sspi->tx_word(sspi); - writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN | - SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_RXFIFO_THD_INT_EN | - SIRFSOC_SPI_TXFIFO_THD_INT_EN | SIRFSOC_SPI_FRM_END_INT_EN| - SIRFSOC_SPI_RXFIFO_FULL_INT_EN, - sspi->base + SIRFSOC_SPI_INT_EN); - writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, + do { + writel(SIRFSOC_SPI_FIFO_RESET, + sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_RESET, + sspi->base + SIRFSOC_SPI_TXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, + sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(SIRFSOC_SPI_FIFO_START, + sspi->base + SIRFSOC_SPI_TXFIFO_OP); + writel(0, sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_INT_MASK_ALL, + sspi->base + SIRFSOC_SPI_INT_STATUS); + writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | + SIRFSOC_SPI_MUL_DAT_MODE | SIRFSOC_SPI_ENA_AUTO_CLR, + sspi->base + SIRFSOC_SPI_CTRL); + writel(min(sspi->left_tx_word, (u32)(256 / sspi->word_width)) + - 1, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN); + writel(min(sspi->left_rx_word, (u32)(256 / sspi->word_width)) + - 1, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN); + while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS) + & SIRFSOC_SPI_FIFO_FULL)) && sspi->left_tx_word) + sspi->tx_word(sspi); + writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN | + SIRFSOC_SPI_TX_UFLOW_INT_EN | + SIRFSOC_SPI_RX_OFLOW_INT_EN, + sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, sspi->base + SIRFSOC_SPI_TX_RX_EN); - if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) - dev_err(&spi->dev, "transfer timeout\n"); - writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP); - writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP); - writel(0, sspi->base + SIRFSOC_SPI_TX_RX_EN); - writel(0, sspi->base + SIRFSOC_SPI_INT_EN); + if (!wait_for_completion_timeout(&sspi->tx_done, timeout) || + !wait_for_completion_timeout(&sspi->rx_done, timeout)) { + dev_err(&spi->dev, "transfer timeout\n"); + break; + } + while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS) + & SIRFSOC_SPI_FIFO_EMPTY)) && sspi->left_rx_word) + sspi->rx_word(sspi); + writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP); + writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP); + } while (sspi->left_tx_word != 0 || sspi->left_rx_word != 0); } static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) -- cgit v1.2.3 From 3beb61dbfcf188399cbc36ce1eeb8b2ba724de38 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 22 May 2014 20:07:35 +0200 Subject: spi: rspi: Round up division to avoid slave overclocking The calculation of the bit rate divider used a standard C division, which rounds down the quotient. This may lead to a higher bitrate than requested. Round up to avoid this. E.g. on Koelsch, the SPI flash (configured for 30 MHz) was driven at 48.75 MHz. After this patch it's driven at a safe 24.375 MHz. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 1fb0ad213324..5639f9529e0b 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -266,7 +266,8 @@ static int rspi_set_config_register(struct rspi_data *rspi, int access_size) rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR); /* Sets transfer bit rate */ - spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1; + spbr = DIV_ROUND_UP(clk_get_rate(rspi->clk), + 2 * rspi->max_speed_hz) - 1; rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR); /* Disable dummy transmission, set 16-bit word access, 1 frame */ @@ -302,7 +303,8 @@ static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size) rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR); /* Sets transfer bit rate */ - spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1; + spbr = DIV_ROUND_UP(clk_get_rate(rspi->clk), + 2 * rspi->max_speed_hz) - 1; rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR); /* Disable dummy transmission, set byte access */ @@ -335,7 +337,7 @@ static int qspi_set_config_register(struct rspi_data *rspi, int access_size) rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR); /* Sets transfer bit rate */ - spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz); + spbr = DIV_ROUND_UP(clk_get_rate(rspi->clk), 2 * rspi->max_speed_hz); rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR); /* Disable dummy transmission, set byte access */ -- cgit v1.2.3 From 836d1a22db9ee0a466301465e873bc94da86cb15 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Fri, 30 May 2014 18:18:09 +0200 Subject: spi/pxa2xx: fix runtime PM enabling order In commit 7dd62787334ac6e0e2a0ef3f20bb1936ac431b04 (spi/pxa2xx: Convert to core runtime PM) master->auto_runtime_pm was set to true. In this case pm_runtime_enable() must be called *before* spi_register_master(), otherwise the kernel hangs with this error message: spi_master spi0: Failed to power device: -13 A similar fix, but for spi/hspi, was applied in 268d76430d1b68c340687357ffd18b4b12d02269. Signed-off-by: Antonio Ospite Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 41185d0557fa..a07b75814442 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1202,6 +1202,11 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) tasklet_init(&drv_data->pump_transfers, pump_transfers, (unsigned long)drv_data); + pm_runtime_set_autosuspend_delay(&pdev->dev, 50); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + /* Register with the SPI framework */ platform_set_drvdata(pdev, drv_data); status = devm_spi_register_master(&pdev->dev, master); @@ -1210,11 +1215,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) goto out_error_clock_enabled; } - pm_runtime_set_autosuspend_delay(&pdev->dev, 50); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - return status; out_error_clock_enabled: -- cgit v1.2.3 From 5f684c34fc82be84ece158aa5c5c7c5072daa9a0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:03 +0200 Subject: spi: rspi: Extract rspi_wait_for_{tx_empty,rx_full}() Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 5639f9529e0b..d04a4acce231 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -405,11 +405,22 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask, return 0; } +static inline int rspi_wait_for_tx_empty(struct rspi_data *rspi) +{ + return rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); +} + +static inline int rspi_wait_for_rx_full(struct rspi_data *rspi) +{ + return rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE); +} + static int rspi_data_out(struct rspi_data *rspi, u8 data) { - if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) { + int error = rspi_wait_for_tx_empty(rspi); + if (error < 0) { dev_err(&rspi->master->dev, "transmit timeout\n"); - return -ETIMEDOUT; + return error; } rspi_write_data(rspi, data); return 0; @@ -417,11 +428,13 @@ static int rspi_data_out(struct rspi_data *rspi, u8 data) static int rspi_data_in(struct rspi_data *rspi) { + int error; u8 data; - if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) { + error = rspi_wait_for_rx_full(rspi); + if (error < 0) { dev_err(&rspi->master->dev, "receive timeout\n"); - return -ETIMEDOUT; + return error; } data = rspi_read_data(rspi); return data; @@ -737,7 +750,7 @@ static int rspi_transfer_out_in(struct rspi_data *rspi, } /* Wait for the last transmission */ - rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); + rspi_wait_for_tx_empty(rspi); return 0; } @@ -783,7 +796,7 @@ static int rspi_rz_transfer_out_in(struct rspi_data *rspi, } /* Wait for the last transmission */ - rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); + rspi_wait_for_tx_empty(rspi); return 0; } @@ -818,7 +831,7 @@ static int qspi_transfer_out_in(struct rspi_data *rspi, } /* Wait for the last transmission */ - rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); + rspi_wait_for_tx_empty(rspi); return 0; } @@ -836,7 +849,7 @@ static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer) } /* Wait for the last transmission */ - rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); + rspi_wait_for_tx_empty(rspi); return 0; } -- cgit v1.2.3 From 32c64261c6f50a4e71ec7546f7e2f48eba91c985 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:04 +0200 Subject: spi: rspi: Do not call rspi_receive_init() for TX-only Since commit 8449fd76deb9ac67a15a6fb8ead7bb4595d019d2 ("spi: rspi: Merge rspi_send_pio() and rspi_receive_pio()"), rspi_receive_init() is called for transmit-only transfers too, while this is not needed. Only call rspi_receive_init() when receiving, to preserve behavior on RSPI on SH. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index d04a4acce231..57beda209599 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -726,13 +726,13 @@ static int rspi_transfer_out_in(struct rspi_data *rspi, u8 *rx_buf = xfer->rx_buf; u8 spcr, data; - rspi_receive_init(rspi); - spcr = rspi_read8(rspi, RSPI_SPCR); - if (rx_buf) + if (rx_buf) { + rspi_receive_init(rspi); spcr &= ~SPCR_TXMD; - else + } else { spcr |= SPCR_TXMD; + } rspi_write8(rspi, spcr, RSPI_SPCR); while (remain > 0) { -- cgit v1.2.3 From 9c5de2c1754c2bb3c69c4d7bf0d0edc0a61d8232 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:05 +0200 Subject: spi: rspi: Remove unused 16-bit DMA support The 16-bit DMA support doesn't fit well within the SPI core DMA framework, as it needs to manage its own double-sized temporary buffers, for handling the interleaved data. Remove it, as there is no in-tree board code that sets rspi_plat_data.dma_width_16bit. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 84 ++++-------------------------------------------- include/linux/spi/rspi.h | 2 -- 2 files changed, 6 insertions(+), 80 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 57beda209599..3bd06fd9af47 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -201,7 +201,6 @@ struct rspi_data { struct dma_chan *chan_tx; struct dma_chan *chan_rx; - unsigned dma_width_16bit:1; unsigned dma_callbacked:1; unsigned byte_access:1; }; @@ -475,60 +474,17 @@ static void rspi_dma_unmap_sg(struct scatterlist *sg, struct dma_chan *chan, dma_unmap_sg(chan->device->dev, sg, 1, dir); } -static void rspi_memory_to_8bit(void *buf, const void *data, unsigned len) -{ - u16 *dst = buf; - const u8 *src = data; - - while (len) { - *dst++ = (u16)(*src++); - len--; - } -} - -static void rspi_memory_from_8bit(void *buf, const void *data, unsigned len) -{ - u8 *dst = buf; - const u16 *src = data; - - while (len) { - *dst++ = (u8)*src++; - len--; - } -} - static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) { struct scatterlist sg; - const void *buf = NULL; + const void *buf = t->tx_buf; struct dma_async_tx_descriptor *desc; - unsigned int len; + unsigned int len = t->len; int ret = 0; - if (rspi->dma_width_16bit) { - void *tmp; - /* - * If DMAC bus width is 16-bit, the driver allocates a dummy - * buffer. And, the driver converts original data into the - * DMAC data as the following format: - * original data: 1st byte, 2nd byte ... - * DMAC data: 1st byte, dummy, 2nd byte, dummy ... - */ - len = t->len * 2; - tmp = kmalloc(len, GFP_KERNEL); - if (!tmp) - return -ENOMEM; - rspi_memory_to_8bit(tmp, t->tx_buf, t->len); - buf = tmp; - } else { - len = t->len; - buf = t->tx_buf; - } + if (!rspi_dma_map_sg(&sg, buf, len, rspi->chan_tx, DMA_TO_DEVICE)) + return -EFAULT; - if (!rspi_dma_map_sg(&sg, buf, len, rspi->chan_tx, DMA_TO_DEVICE)) { - ret = -EFAULT; - goto end_nomap; - } desc = dmaengine_prep_slave_sg(rspi->chan_tx, &sg, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { @@ -563,10 +519,6 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) end: rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE); -end_nomap: - if (rspi->dma_width_16bit) - kfree(buf); - return ret; } @@ -603,28 +555,11 @@ static void qspi_receive_init(const struct rspi_data *rspi) static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) { struct scatterlist sg, sg_dummy; - void *dummy = NULL, *rx_buf = NULL; + void *dummy = NULL, *rx_buf = t->rx_buf; struct dma_async_tx_descriptor *desc, *desc_dummy; - unsigned int len; + unsigned int len = t->len; int ret = 0; - if (rspi->dma_width_16bit) { - /* - * If DMAC bus width is 16-bit, the driver allocates a dummy - * buffer. And, finally the driver converts the DMAC data into - * actual data as the following format: - * DMAC data: 1st byte, dummy, 2nd byte, dummy ... - * actual data: 1st byte, 2nd byte ... - */ - len = t->len * 2; - rx_buf = kmalloc(len, GFP_KERNEL); - if (!rx_buf) - return -ENOMEM; - } else { - len = t->len; - rx_buf = t->rx_buf; - } - /* prepare dummy transfer to generate SPI clocks */ dummy = kzalloc(len, GFP_KERNEL); if (!dummy) { @@ -697,11 +632,6 @@ end: end_dummy_mapped: rspi_dma_unmap_sg(&sg_dummy, rspi->chan_tx, DMA_TO_DEVICE); end_nomap: - if (rspi->dma_width_16bit) { - if (!ret) - rspi_memory_from_8bit(t->rx_buf, rx_buf, t->len); - kfree(rx_buf); - } kfree(dummy); return ret; @@ -1073,8 +1003,6 @@ static int rspi_request_dma(struct rspi_data *rspi, if (!res || !rspi_pd) return 0; /* The driver assumes no error. */ - rspi->dma_width_16bit = rspi_pd->dma_width_16bit; - /* If the module receives data by DMAC, it also needs TX DMAC */ if (rspi_pd->dma_rx_id && rspi_pd->dma_tx_id) { dma_cap_zero(mask); diff --git a/include/linux/spi/rspi.h b/include/linux/spi/rspi.h index a25bd6f65e7f..e546b2ceb623 100644 --- a/include/linux/spi/rspi.h +++ b/include/linux/spi/rspi.h @@ -25,8 +25,6 @@ struct rspi_plat_data { unsigned int dma_tx_id; unsigned int dma_rx_id; - unsigned dma_width_16bit:1; /* DMAC read/write width = 16-bit */ - u16 num_chipselect; }; -- cgit v1.2.3 From b42e03596db3d45980c976c8124fdc323f031dc4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:06 +0200 Subject: spi: rspi: Use core SPI_MASTER_MUST_[RT]X handling RSPI needs dummy transfers to generate the SPI clock on receive. RSPI-RZ and QSPI always do both transmit and receive. Use the SPI core SPI_MASTER_MUST_RX/SPI_MASTER_MUST_TX infrastructure instead of checking for the presence of buffers and providing dummy data ourselves (for PIO), or providing a dummy buffer (for DMA). rspi_receive_dma() now provides full duplex DMA transfers on RSPI, and is renamed to rspi_send_receive_dma(). As the SPI core will always provide a TX buffer, the logic to choose between DMA send and DMA send/receive in rspi_transfer_one() now has to check for the presence of an RX buffer. Likewise for the DMA availability tests in rspi_is_dma(). The buffer tests in qspi_transfer_one() are now always true, so they're removed. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 132 ++++++++++++++++++++++--------------------------- 1 file changed, 58 insertions(+), 74 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 3bd06fd9af47..ece8f6037943 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -183,8 +183,6 @@ #define SPBFCR_TXTRG_MASK 0x30 /* Transmit Buffer Data Triggering Number */ #define SPBFCR_RXTRG_MASK 0x07 /* Receive Buffer Data Triggering Number */ -#define DUMMY_DATA 0x00 - struct rspi_data { void __iomem *addr; u32 max_speed_hz; @@ -252,6 +250,7 @@ struct spi_ops { int (*transfer_one)(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer); u16 mode_bits; + u16 flags; }; /* @@ -552,42 +551,38 @@ static void qspi_receive_init(const struct rspi_data *rspi) rspi_write8(rspi, 0, QSPI_SPBFCR); } -static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) +static int rspi_send_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) { - struct scatterlist sg, sg_dummy; - void *dummy = NULL, *rx_buf = t->rx_buf; - struct dma_async_tx_descriptor *desc, *desc_dummy; + struct scatterlist sg_rx, sg_tx; + const void *tx_buf = t->tx_buf; + void *rx_buf = t->rx_buf; + struct dma_async_tx_descriptor *desc_tx, *desc_rx; unsigned int len = t->len; int ret = 0; - /* prepare dummy transfer to generate SPI clocks */ - dummy = kzalloc(len, GFP_KERNEL); - if (!dummy) { - ret = -ENOMEM; - goto end_nomap; - } - if (!rspi_dma_map_sg(&sg_dummy, dummy, len, rspi->chan_tx, - DMA_TO_DEVICE)) { - ret = -EFAULT; - goto end_nomap; - } - desc_dummy = dmaengine_prep_slave_sg(rspi->chan_tx, &sg_dummy, 1, + /* prepare transmit transfer */ + if (!rspi_dma_map_sg(&sg_tx, tx_buf, len, rspi->chan_tx, + DMA_TO_DEVICE)) + return -EFAULT; + + desc_tx = dmaengine_prep_slave_sg(rspi->chan_tx, &sg_tx, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc_dummy) { + if (!desc_tx) { ret = -EIO; - goto end_dummy_mapped; + goto end_tx_mapped; } /* prepare receive transfer */ - if (!rspi_dma_map_sg(&sg, rx_buf, len, rspi->chan_rx, + if (!rspi_dma_map_sg(&sg_rx, rx_buf, len, rspi->chan_rx, DMA_FROM_DEVICE)) { ret = -EFAULT; - goto end_dummy_mapped; + goto end_tx_mapped; } - desc = dmaengine_prep_slave_sg(rspi->chan_rx, &sg, 1, DMA_FROM_DEVICE, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { + desc_rx = dmaengine_prep_slave_sg(rspi->chan_rx, &sg_rx, 1, + DMA_FROM_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc_rx) { ret = -EIO; goto end; } @@ -606,13 +601,13 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); rspi->dma_callbacked = 0; - desc->callback = rspi_dma_complete; - desc->callback_param = rspi; - dmaengine_submit(desc); + desc_rx->callback = rspi_dma_complete; + desc_rx->callback_param = rspi; + dmaengine_submit(desc_rx); dma_async_issue_pending(rspi->chan_rx); - desc_dummy->callback = NULL; /* No callback */ - dmaengine_submit(desc_dummy); + desc_tx->callback = NULL; /* No callback */ + dmaengine_submit(desc_tx); dma_async_issue_pending(rspi->chan_tx); ret = wait_event_interruptible_timeout(rspi->wait, @@ -628,21 +623,19 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) enable_irq(rspi->rx_irq); end: - rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE); -end_dummy_mapped: - rspi_dma_unmap_sg(&sg_dummy, rspi->chan_tx, DMA_TO_DEVICE); -end_nomap: - kfree(dummy); - + rspi_dma_unmap_sg(&sg_rx, rspi->chan_rx, DMA_FROM_DEVICE); +end_tx_mapped: + rspi_dma_unmap_sg(&sg_tx, rspi->chan_tx, DMA_TO_DEVICE); return ret; } static int rspi_is_dma(const struct rspi_data *rspi, struct spi_transfer *t) { - if (t->tx_buf && rspi->chan_tx) - return 1; /* If the module receives data by DMAC, it also needs TX DMAC */ - if (t->rx_buf && rspi->chan_tx && rspi->chan_rx) + if (t->rx_buf) + return rspi->chan_tx && rspi->chan_rx; + + if (rspi->chan_tx) return 1; return 0; @@ -654,7 +647,7 @@ static int rspi_transfer_out_in(struct rspi_data *rspi, int remain = xfer->len, ret; const u8 *tx_buf = xfer->tx_buf; u8 *rx_buf = xfer->rx_buf; - u8 spcr, data; + u8 spcr; spcr = rspi_read8(rspi, RSPI_SPCR); if (rx_buf) { @@ -666,8 +659,7 @@ static int rspi_transfer_out_in(struct rspi_data *rspi, rspi_write8(rspi, spcr, RSPI_SPCR); while (remain > 0) { - data = tx_buf ? *tx_buf++ : DUMMY_DATA; - ret = rspi_data_out(rspi, data); + ret = rspi_data_out(rspi, *tx_buf++); if (ret < 0) return ret; if (rx_buf) { @@ -689,20 +681,14 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { struct rspi_data *rspi = spi_master_get_devdata(master); - int ret; if (!rspi_is_dma(rspi, xfer)) return rspi_transfer_out_in(rspi, xfer); - if (xfer->tx_buf) { - ret = rspi_send_dma(rspi, xfer); - if (ret < 0) - return ret; - } if (xfer->rx_buf) - return rspi_receive_dma(rspi, xfer); - - return 0; + return rspi_send_receive_dma(rspi, xfer); + else + return rspi_send_dma(rspi, xfer); } static int rspi_rz_transfer_out_in(struct rspi_data *rspi, @@ -711,17 +697,14 @@ static int rspi_rz_transfer_out_in(struct rspi_data *rspi, int remain = xfer->len, ret; const u8 *tx_buf = xfer->tx_buf; u8 *rx_buf = xfer->rx_buf; - u8 data; rspi_rz_receive_init(rspi); while (remain > 0) { - data = tx_buf ? *tx_buf++ : DUMMY_DATA; - ret = rspi_data_out_in(rspi, data); + ret = rspi_data_out_in(rspi, *tx_buf++); if (ret < 0) return ret; - if (rx_buf) - *rx_buf++ = ret; + *rx_buf++ = ret; remain--; } @@ -746,17 +729,14 @@ static int qspi_transfer_out_in(struct rspi_data *rspi, int remain = xfer->len, ret; const u8 *tx_buf = xfer->tx_buf; u8 *rx_buf = xfer->rx_buf; - u8 data; qspi_receive_init(rspi); while (remain > 0) { - data = tx_buf ? *tx_buf++ : DUMMY_DATA; - ret = rspi_data_out_in(rspi, data); + ret = rspi_data_out_in(rspi, *tx_buf++); if (ret < 0) return ret; - if (rx_buf) - *rx_buf++ = ret; + *rx_buf++ = ret; remain--; } @@ -807,10 +787,10 @@ static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi, if (spi->mode & SPI_LOOP) { return qspi_transfer_out_in(rspi, xfer); - } else if (xfer->tx_buf && xfer->tx_nbits > SPI_NBITS_SINGLE) { + } else if (xfer->tx_nbits > SPI_NBITS_SINGLE) { /* Quad or Dual SPI Write */ return qspi_transfer_out(rspi, xfer); - } else if (xfer->rx_buf && xfer->rx_nbits > SPI_NBITS_SINGLE) { + } else if (xfer->rx_nbits > SPI_NBITS_SINGLE) { /* Quad or Dual SPI Read */ return qspi_transfer_in(rspi, xfer); } else { @@ -1061,23 +1041,26 @@ static int rspi_remove(struct platform_device *pdev) } static const struct spi_ops rspi_ops = { - .set_config_register = rspi_set_config_register, - .transfer_one = rspi_transfer_one, - .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, + .set_config_register = rspi_set_config_register, + .transfer_one = rspi_transfer_one, + .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, + .flags = SPI_MASTER_MUST_TX, }; static const struct spi_ops rspi_rz_ops = { - .set_config_register = rspi_rz_set_config_register, - .transfer_one = rspi_rz_transfer_one, - .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, + .set_config_register = rspi_rz_set_config_register, + .transfer_one = rspi_rz_transfer_one, + .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, + .flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX, }; static const struct spi_ops qspi_ops = { - .set_config_register = qspi_set_config_register, - .transfer_one = qspi_transfer_one, - .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP | - SPI_TX_DUAL | SPI_TX_QUAD | - SPI_RX_DUAL | SPI_RX_QUAD, + .set_config_register = qspi_set_config_register, + .transfer_one = qspi_transfer_one, + .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP | + SPI_TX_DUAL | SPI_TX_QUAD | + SPI_RX_DUAL | SPI_RX_QUAD, + .flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX, }; #ifdef CONFIG_OF @@ -1197,6 +1180,7 @@ static int rspi_probe(struct platform_device *pdev) master->prepare_message = rspi_prepare_message; master->unprepare_message = rspi_unprepare_message; master->mode_bits = ops->mode_bits; + master->flags = ops->flags; master->dev.of_node = pdev->dev.of_node; ret = platform_get_irq_byname(pdev, "rx"); -- cgit v1.2.3 From 6837b8e91d2a080293c30d5fe42d9692390091fa Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:07 +0200 Subject: spi: rspi: Extract rspi_pio_transfer() The various PIO loops are very similar. Consolidate into a single function rspi_pio_transfer(). Both buffer pointers can be NULL, as RSPI supports TX-only mode, and Dual/Quad SPI Transfers are unidirectional. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 95 ++++++++++++++++++-------------------------------- 1 file changed, 33 insertions(+), 62 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index ece8f6037943..fdbd46d0c570 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -438,15 +438,24 @@ static int rspi_data_in(struct rspi_data *rspi) return data; } -static int rspi_data_out_in(struct rspi_data *rspi, u8 data) +static int rspi_pio_transfer(struct rspi_data *rspi, const u8 *tx, u8 *rx, + unsigned int n) { - int ret; - - ret = rspi_data_out(rspi, data); - if (ret < 0) - return ret; + while (n-- > 0) { + if (tx) { + int ret = rspi_data_out(rspi, *tx++); + if (ret < 0) + return ret; + } + if (rx) { + int ret = rspi_data_in(rspi); + if (ret < 0) + return ret; + *rx++ = ret; + } + } - return rspi_data_in(rspi); + return 0; } static void rspi_dma_complete(void *arg) @@ -644,13 +653,11 @@ static int rspi_is_dma(const struct rspi_data *rspi, struct spi_transfer *t) static int rspi_transfer_out_in(struct rspi_data *rspi, struct spi_transfer *xfer) { - int remain = xfer->len, ret; - const u8 *tx_buf = xfer->tx_buf; - u8 *rx_buf = xfer->rx_buf; u8 spcr; + int ret; spcr = rspi_read8(rspi, RSPI_SPCR); - if (rx_buf) { + if (xfer->rx_buf) { rspi_receive_init(rspi); spcr &= ~SPCR_TXMD; } else { @@ -658,18 +665,9 @@ static int rspi_transfer_out_in(struct rspi_data *rspi, } rspi_write8(rspi, spcr, RSPI_SPCR); - while (remain > 0) { - ret = rspi_data_out(rspi, *tx_buf++); - if (ret < 0) - return ret; - if (rx_buf) { - ret = rspi_data_in(rspi); - if (ret < 0) - return ret; - *rx_buf++ = ret; - } - remain--; - } + ret = rspi_pio_transfer(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len); + if (ret < 0) + return ret; /* Wait for the last transmission */ rspi_wait_for_tx_empty(rspi); @@ -694,19 +692,13 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, static int rspi_rz_transfer_out_in(struct rspi_data *rspi, struct spi_transfer *xfer) { - int remain = xfer->len, ret; - const u8 *tx_buf = xfer->tx_buf; - u8 *rx_buf = xfer->rx_buf; + int ret; rspi_rz_receive_init(rspi); - while (remain > 0) { - ret = rspi_data_out_in(rspi, *tx_buf++); - if (ret < 0) - return ret; - *rx_buf++ = ret; - remain--; - } + ret = rspi_pio_transfer(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len); + if (ret < 0) + return ret; /* Wait for the last transmission */ rspi_wait_for_tx_empty(rspi); @@ -726,19 +718,13 @@ static int rspi_rz_transfer_one(struct spi_master *master, static int qspi_transfer_out_in(struct rspi_data *rspi, struct spi_transfer *xfer) { - int remain = xfer->len, ret; - const u8 *tx_buf = xfer->tx_buf; - u8 *rx_buf = xfer->rx_buf; + int ret; qspi_receive_init(rspi); - while (remain > 0) { - ret = rspi_data_out_in(rspi, *tx_buf++); - if (ret < 0) - return ret; - *rx_buf++ = ret; - remain--; - } + ret = rspi_pio_transfer(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len); + if (ret < 0) + return ret; /* Wait for the last transmission */ rspi_wait_for_tx_empty(rspi); @@ -748,15 +734,11 @@ static int qspi_transfer_out_in(struct rspi_data *rspi, static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer) { - const u8 *buf = xfer->tx_buf; - unsigned int i; int ret; - for (i = 0; i < xfer->len; i++) { - ret = rspi_data_out(rspi, *buf++); - if (ret < 0) - return ret; - } + ret = rspi_pio_transfer(rspi, xfer->tx_buf, NULL, xfer->len); + if (ret < 0) + return ret; /* Wait for the last transmission */ rspi_wait_for_tx_empty(rspi); @@ -766,18 +748,7 @@ static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer) static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer) { - u8 *buf = xfer->rx_buf; - unsigned int i; - int ret; - - for (i = 0; i < xfer->len; i++) { - ret = rspi_data_in(rspi); - if (ret < 0) - return ret; - *buf++ = ret; - } - - return 0; + return rspi_pio_transfer(rspi, NULL, xfer->rx_buf, xfer->len); } static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi, -- cgit v1.2.3 From 27e105a6006b8ce1b55709c5e24f63959981475d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:08 +0200 Subject: spi: rspi: Don't consider DMA configuration failures fatal Fall back to PIO if DMA configuration failed. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index fdbd46d0c570..94a99ec7d989 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1190,10 +1190,8 @@ static int rspi_probe(struct platform_device *pdev) } ret = rspi_request_dma(rspi, pdev); - if (ret < 0) { - dev_err(&pdev->dev, "rspi_request_dma failed.\n"); - goto error3; - } + if (ret < 0) + dev_warn(&pdev->dev, "DMA not available, using PIO\n"); ret = devm_spi_register_master(&pdev->dev, master); if (ret < 0) { -- cgit v1.2.3 From 65bf220571f131a7c3a564a88793bd0f16fd7c96 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:09 +0200 Subject: spi: rspi: Extract rspi_request_dma_chan() Setup of the receive and transmit DMA channels is very similar, so let's consolidate. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 89 +++++++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 34 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 94a99ec7d989..0a7a2d618f0f 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -942,52 +942,73 @@ static irqreturn_t rspi_irq_tx(int irq, void *_sr) return 0; } -static int rspi_request_dma(struct rspi_data *rspi, - struct platform_device *pdev) +static struct dma_chan *rspi_request_dma_chan(struct device *dev, + enum dma_transfer_direction dir, + unsigned int id, + dma_addr_t port_addr) { - const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dma_cap_mask_t mask; + struct dma_chan *chan; struct dma_slave_config cfg; int ret; + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + chan = dma_request_channel(mask, shdma_chan_filter, + (void *)(unsigned long)id); + if (!chan) { + dev_warn(dev, "dma_request_channel failed\n"); + return NULL; + } + + memset(&cfg, 0, sizeof(cfg)); + cfg.slave_id = id; + cfg.direction = dir; + if (dir == DMA_MEM_TO_DEV) + cfg.dst_addr = port_addr; + else + cfg.src_addr = port_addr; + + ret = dmaengine_slave_config(chan, &cfg); + if (ret) { + dev_warn(dev, "dmaengine_slave_config failed %d\n", ret); + dma_release_channel(chan); + return NULL; + } + + return chan; +} + +static int rspi_request_dma(struct rspi_data *rspi, + struct platform_device *pdev) +{ + const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev); + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res || !rspi_pd) return 0; /* The driver assumes no error. */ /* If the module receives data by DMAC, it also needs TX DMAC */ if (rspi_pd->dma_rx_id && rspi_pd->dma_tx_id) { - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - rspi->chan_rx = dma_request_channel(mask, shdma_chan_filter, - (void *)rspi_pd->dma_rx_id); - if (rspi->chan_rx) { - cfg.slave_id = rspi_pd->dma_rx_id; - cfg.direction = DMA_DEV_TO_MEM; - cfg.dst_addr = 0; - cfg.src_addr = res->start + RSPI_SPDR; - ret = dmaengine_slave_config(rspi->chan_rx, &cfg); - if (!ret) - dev_info(&pdev->dev, "Use DMA when rx.\n"); - else - return ret; - } + rspi->chan_rx = rspi_request_dma_chan(&pdev->dev, + DMA_DEV_TO_MEM, + rspi_pd->dma_rx_id, + res->start + RSPI_SPDR); + if (!rspi->chan_rx) + return -ENODEV; + + dev_info(&pdev->dev, "Use DMA when rx.\n"); } if (rspi_pd->dma_tx_id) { - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - rspi->chan_tx = dma_request_channel(mask, shdma_chan_filter, - (void *)rspi_pd->dma_tx_id); - if (rspi->chan_tx) { - cfg.slave_id = rspi_pd->dma_tx_id; - cfg.direction = DMA_MEM_TO_DEV; - cfg.dst_addr = res->start + RSPI_SPDR; - cfg.src_addr = 0; - ret = dmaengine_slave_config(rspi->chan_tx, &cfg); - if (!ret) - dev_info(&pdev->dev, "Use DMA when tx\n"); - else - return ret; - } + rspi->chan_tx = rspi_request_dma_chan(&pdev->dev, + DMA_MEM_TO_DEV, + rspi_pd->dma_tx_id, + res->start + RSPI_SPDR); + if (!rspi->chan_tx) + return -ENODEV; + + dev_info(&pdev->dev, "Use DMA when tx\n"); } return 0; -- cgit v1.2.3 From fcdc49ae53dc8cfc1a7758607bca68935f568ca2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:10 +0200 Subject: spi: rspi: Remove unneeded resource test in DMA setup The resource is know to exist, as rspi_probe() already mapped it. Remove the test, and just pass the resource. Pass the device pointer instead of the platform device pointer, as the latter is no longer needed. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 0a7a2d618f0f..1ec51cb00203 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -980,35 +980,32 @@ static struct dma_chan *rspi_request_dma_chan(struct device *dev, return chan; } -static int rspi_request_dma(struct rspi_data *rspi, - struct platform_device *pdev) +static int rspi_request_dma(struct device *dev, struct rspi_data *rspi, + const struct resource *res) { - const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + const struct rspi_plat_data *rspi_pd = dev_get_platdata(dev); - if (!res || !rspi_pd) + if (!rspi_pd) return 0; /* The driver assumes no error. */ /* If the module receives data by DMAC, it also needs TX DMAC */ if (rspi_pd->dma_rx_id && rspi_pd->dma_tx_id) { - rspi->chan_rx = rspi_request_dma_chan(&pdev->dev, - DMA_DEV_TO_MEM, + rspi->chan_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM, rspi_pd->dma_rx_id, res->start + RSPI_SPDR); if (!rspi->chan_rx) return -ENODEV; - dev_info(&pdev->dev, "Use DMA when rx.\n"); + dev_info(dev, "Use DMA when rx.\n"); } if (rspi_pd->dma_tx_id) { - rspi->chan_tx = rspi_request_dma_chan(&pdev->dev, - DMA_MEM_TO_DEV, + rspi->chan_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV, rspi_pd->dma_tx_id, res->start + RSPI_SPDR); if (!rspi->chan_tx) return -ENODEV; - dev_info(&pdev->dev, "Use DMA when tx\n"); + dev_info(dev, "Use DMA when tx\n"); } return 0; @@ -1210,7 +1207,7 @@ static int rspi_probe(struct platform_device *pdev) goto error2; } - ret = rspi_request_dma(rspi, pdev); + ret = rspi_request_dma(&pdev->dev, rspi, res); if (ret < 0) dev_warn(&pdev->dev, "DMA not available, using PIO\n"); -- cgit v1.2.3 From 5f338d0ce0b4c9e6c554b92cfb288789a41bfbc1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:11 +0200 Subject: spi: rspi: SPI DMA core needs both RX and TX DMA to function The SPI DMA core framework needs both RX and TX DMA to function. As a preparation for converting the driver to use this framework, fall back to PIO if no DMA channel or only one DMA channel is available. This affects only RSPI, which could do DMA transfers for TX-only before. RSPI-RZ and QSPI (at least for Single SPI Transfers) will need both RX and TX DMA anyway. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 1ec51cb00203..7b993f75a3cf 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -640,10 +640,6 @@ end_tx_mapped: static int rspi_is_dma(const struct rspi_data *rspi, struct spi_transfer *t) { - /* If the module receives data by DMAC, it also needs TX DMAC */ - if (t->rx_buf) - return rspi->chan_tx && rspi->chan_rx; - if (rspi->chan_tx) return 1; @@ -985,29 +981,25 @@ static int rspi_request_dma(struct device *dev, struct rspi_data *rspi, { const struct rspi_plat_data *rspi_pd = dev_get_platdata(dev); - if (!rspi_pd) + if (!rspi_pd || !rspi_pd->dma_rx_id || !rspi_pd->dma_tx_id) return 0; /* The driver assumes no error. */ - /* If the module receives data by DMAC, it also needs TX DMAC */ - if (rspi_pd->dma_rx_id && rspi_pd->dma_tx_id) { - rspi->chan_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM, - rspi_pd->dma_rx_id, - res->start + RSPI_SPDR); - if (!rspi->chan_rx) - return -ENODEV; + rspi->chan_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM, + rspi_pd->dma_rx_id, + res->start + RSPI_SPDR); + if (!rspi->chan_rx) + return -ENODEV; - dev_info(dev, "Use DMA when rx.\n"); - } - if (rspi_pd->dma_tx_id) { - rspi->chan_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV, - rspi_pd->dma_tx_id, - res->start + RSPI_SPDR); - if (!rspi->chan_tx) - return -ENODEV; - - dev_info(dev, "Use DMA when tx\n"); + rspi->chan_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV, + rspi_pd->dma_tx_id, + res->start + RSPI_SPDR); + if (!rspi->chan_tx) { + dma_release_channel(rspi->chan_rx); + rspi->chan_rx = NULL; + return -ENODEV; } + dev_info(dev, "DMA available"); return 0; } -- cgit v1.2.3 From 2f777ec91aa0623e058c43dd4aaf0b3325d3c3e8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:12 +0200 Subject: spi: rspi: Use SPI core DMA mapping framework Use the SPI core DMA mapping framework instead of our own. If available, DMA is used for transfers larger than the FIFO size (8 or 32 bytes). Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 140 ++++++++++++++++++------------------------------- 1 file changed, 50 insertions(+), 90 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 7b993f75a3cf..753ac7bdfd55 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -195,10 +195,6 @@ struct rspi_data { int rx_irq, tx_irq; const struct spi_ops *ops; - /* for dmaengine */ - struct dma_chan *chan_tx; - struct dma_chan *chan_rx; - unsigned dma_callbacked:1; unsigned byte_access:1; }; @@ -251,6 +247,7 @@ struct spi_ops { struct spi_transfer *xfer); u16 mode_bits; u16 flags; + u16 fifo_size; }; /* @@ -466,39 +463,16 @@ static void rspi_dma_complete(void *arg) wake_up_interruptible(&rspi->wait); } -static int rspi_dma_map_sg(struct scatterlist *sg, const void *buf, - unsigned len, struct dma_chan *chan, - enum dma_transfer_direction dir) -{ - sg_init_table(sg, 1); - sg_set_buf(sg, buf, len); - sg_dma_len(sg) = len; - return dma_map_sg(chan->device->dev, sg, 1, dir); -} - -static void rspi_dma_unmap_sg(struct scatterlist *sg, struct dma_chan *chan, - enum dma_transfer_direction dir) -{ - dma_unmap_sg(chan->device->dev, sg, 1, dir); -} - static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) { - struct scatterlist sg; - const void *buf = t->tx_buf; struct dma_async_tx_descriptor *desc; - unsigned int len = t->len; - int ret = 0; - - if (!rspi_dma_map_sg(&sg, buf, len, rspi->chan_tx, DMA_TO_DEVICE)) - return -EFAULT; + int ret; - desc = dmaengine_prep_slave_sg(rspi->chan_tx, &sg, 1, DMA_TO_DEVICE, + desc = dmaengine_prep_slave_sg(rspi->master->dma_tx, t->tx_sg.sgl, + t->tx_sg.nents, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - ret = -EIO; - goto end; - } + if (!desc) + return -EIO; /* * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be @@ -513,7 +487,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) desc->callback = rspi_dma_complete; desc->callback_param = rspi; dmaengine_submit(desc); - dma_async_issue_pending(rspi->chan_tx); + dma_async_issue_pending(rspi->master->dma_tx); ret = wait_event_interruptible_timeout(rspi->wait, rspi->dma_callbacked, HZ); @@ -524,9 +498,6 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) rspi_disable_irq(rspi, SPCR_SPTIE); enable_irq(rspi->tx_irq); - -end: - rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE); return ret; } @@ -562,39 +533,22 @@ static void qspi_receive_init(const struct rspi_data *rspi) static int rspi_send_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) { - struct scatterlist sg_rx, sg_tx; - const void *tx_buf = t->tx_buf; - void *rx_buf = t->rx_buf; struct dma_async_tx_descriptor *desc_tx, *desc_rx; - unsigned int len = t->len; - int ret = 0; + int ret; /* prepare transmit transfer */ - if (!rspi_dma_map_sg(&sg_tx, tx_buf, len, rspi->chan_tx, - DMA_TO_DEVICE)) - return -EFAULT; - - desc_tx = dmaengine_prep_slave_sg(rspi->chan_tx, &sg_tx, 1, - DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc_tx) { - ret = -EIO; - goto end_tx_mapped; - } + desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx, t->tx_sg.sgl, + t->tx_sg.nents, DMA_TO_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc_tx) + return -EIO; /* prepare receive transfer */ - if (!rspi_dma_map_sg(&sg_rx, rx_buf, len, rspi->chan_rx, - DMA_FROM_DEVICE)) { - ret = -EFAULT; - goto end_tx_mapped; - - } - desc_rx = dmaengine_prep_slave_sg(rspi->chan_rx, &sg_rx, 1, - DMA_FROM_DEVICE, + desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx, t->rx_sg.sgl, + t->rx_sg.nents, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc_rx) { - ret = -EIO; - goto end; - } + if (!desc_rx) + return -EIO; rspi_receive_init(rspi); @@ -613,11 +567,11 @@ static int rspi_send_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) desc_rx->callback = rspi_dma_complete; desc_rx->callback_param = rspi; dmaengine_submit(desc_rx); - dma_async_issue_pending(rspi->chan_rx); + dma_async_issue_pending(rspi->master->dma_rx); desc_tx->callback = NULL; /* No callback */ dmaengine_submit(desc_tx); - dma_async_issue_pending(rspi->chan_tx); + dma_async_issue_pending(rspi->master->dma_tx); ret = wait_event_interruptible_timeout(rspi->wait, rspi->dma_callbacked, HZ); @@ -631,19 +585,21 @@ static int rspi_send_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) if (rspi->rx_irq != rspi->tx_irq) enable_irq(rspi->rx_irq); -end: - rspi_dma_unmap_sg(&sg_rx, rspi->chan_rx, DMA_FROM_DEVICE); -end_tx_mapped: - rspi_dma_unmap_sg(&sg_tx, rspi->chan_tx, DMA_TO_DEVICE); return ret; } -static int rspi_is_dma(const struct rspi_data *rspi, struct spi_transfer *t) +static bool __rspi_can_dma(const struct rspi_data *rspi, + const struct spi_transfer *xfer) { - if (rspi->chan_tx) - return 1; + return xfer->len > rspi->ops->fifo_size; +} - return 0; +static bool rspi_can_dma(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct rspi_data *rspi = spi_master_get_devdata(master); + + return __rspi_can_dma(rspi, xfer); } static int rspi_transfer_out_in(struct rspi_data *rspi, @@ -676,7 +632,7 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, { struct rspi_data *rspi = spi_master_get_devdata(master); - if (!rspi_is_dma(rspi, xfer)) + if (!master->can_dma || !__rspi_can_dma(rspi, xfer)) return rspi_transfer_out_in(rspi, xfer); if (xfer->rx_buf) @@ -976,7 +932,7 @@ static struct dma_chan *rspi_request_dma_chan(struct device *dev, return chan; } -static int rspi_request_dma(struct device *dev, struct rspi_data *rspi, +static int rspi_request_dma(struct device *dev, struct spi_master *master, const struct resource *res) { const struct rspi_plat_data *rspi_pd = dev_get_platdata(dev); @@ -984,31 +940,32 @@ static int rspi_request_dma(struct device *dev, struct rspi_data *rspi, if (!rspi_pd || !rspi_pd->dma_rx_id || !rspi_pd->dma_tx_id) return 0; /* The driver assumes no error. */ - rspi->chan_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM, - rspi_pd->dma_rx_id, - res->start + RSPI_SPDR); - if (!rspi->chan_rx) + master->dma_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM, + rspi_pd->dma_rx_id, + res->start + RSPI_SPDR); + if (!master->dma_rx) return -ENODEV; - rspi->chan_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV, - rspi_pd->dma_tx_id, - res->start + RSPI_SPDR); - if (!rspi->chan_tx) { - dma_release_channel(rspi->chan_rx); - rspi->chan_rx = NULL; + master->dma_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV, + rspi_pd->dma_tx_id, + res->start + RSPI_SPDR); + if (!master->dma_tx) { + dma_release_channel(master->dma_rx); + master->dma_rx = NULL; return -ENODEV; } + master->can_dma = rspi_can_dma; dev_info(dev, "DMA available"); return 0; } static void rspi_release_dma(struct rspi_data *rspi) { - if (rspi->chan_tx) - dma_release_channel(rspi->chan_tx); - if (rspi->chan_rx) - dma_release_channel(rspi->chan_rx); + if (rspi->master->dma_tx) + dma_release_channel(rspi->master->dma_tx); + if (rspi->master->dma_rx) + dma_release_channel(rspi->master->dma_rx); } static int rspi_remove(struct platform_device *pdev) @@ -1026,6 +983,7 @@ static const struct spi_ops rspi_ops = { .transfer_one = rspi_transfer_one, .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, .flags = SPI_MASTER_MUST_TX, + .fifo_size = 8, }; static const struct spi_ops rspi_rz_ops = { @@ -1033,6 +991,7 @@ static const struct spi_ops rspi_rz_ops = { .transfer_one = rspi_rz_transfer_one, .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, .flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX, + .fifo_size = 8, /* 8 for TX, 32 for RX */ }; static const struct spi_ops qspi_ops = { @@ -1042,6 +1001,7 @@ static const struct spi_ops qspi_ops = { SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD, .flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX, + .fifo_size = 32, }; #ifdef CONFIG_OF @@ -1199,7 +1159,7 @@ static int rspi_probe(struct platform_device *pdev) goto error2; } - ret = rspi_request_dma(&pdev->dev, rspi, res); + ret = rspi_request_dma(&pdev->dev, master, res); if (ret < 0) dev_warn(&pdev->dev, "DMA not available, using PIO\n"); -- cgit v1.2.3 From 8393fa787bf63c05cb6f9cf0a58ba1ea213c3f01 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:13 +0200 Subject: spi: rspi: Move RSPI-specific setup out of DMA routines Refactor RSPI (on SH) DMA handling to make it reusable for other RSPI implementations: - Call the DMA routines after configuring the TX Mode bit and after calling rspi_receive_init(), so these RSPI-specific operations can be removed from the DMA routines, - Absorb rspi_transfer_out_in() into rspi_transfer_one(). Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 753ac7bdfd55..3dea8adfdcf3 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -480,7 +480,6 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) */ disable_irq(rspi->tx_irq); - rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR); rspi_enable_irq(rspi, SPCR_SPTIE); rspi->dma_callbacked = 0; @@ -550,8 +549,6 @@ static int rspi_send_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) if (!desc_rx) return -EIO; - rspi_receive_init(rspi); - /* * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be * called. So, this driver disables the IRQ while DMA transfer. @@ -560,7 +557,6 @@ static int rspi_send_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) if (rspi->rx_irq != rspi->tx_irq) disable_irq(rspi->rx_irq); - rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR); rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); rspi->dma_callbacked = 0; @@ -602,9 +598,10 @@ static bool rspi_can_dma(struct spi_master *master, struct spi_device *spi, return __rspi_can_dma(rspi, xfer); } -static int rspi_transfer_out_in(struct rspi_data *rspi, - struct spi_transfer *xfer) +static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *xfer) { + struct rspi_data *rspi = spi_master_get_devdata(master); u8 spcr; int ret; @@ -617,6 +614,13 @@ static int rspi_transfer_out_in(struct rspi_data *rspi, } rspi_write8(rspi, spcr, RSPI_SPCR); + if (master->can_dma && __rspi_can_dma(rspi, xfer)) { + if (xfer->rx_buf) + return rspi_send_receive_dma(rspi, xfer); + else + return rspi_send_dma(rspi, xfer); + } + ret = rspi_pio_transfer(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len); if (ret < 0) return ret; @@ -627,20 +631,6 @@ static int rspi_transfer_out_in(struct rspi_data *rspi, return 0; } -static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, - struct spi_transfer *xfer) -{ - struct rspi_data *rspi = spi_master_get_devdata(master); - - if (!master->can_dma || !__rspi_can_dma(rspi, xfer)) - return rspi_transfer_out_in(rspi, xfer); - - if (xfer->rx_buf) - return rspi_send_receive_dma(rspi, xfer); - else - return rspi_send_dma(rspi, xfer); -} - static int rspi_rz_transfer_out_in(struct rspi_data *rspi, struct spi_transfer *xfer) { -- cgit v1.2.3 From e4b52dc4625ee739195189d40c6ddc7d55ddf312 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:14 +0200 Subject: spi: rspi: Pass sg_tables instead of spi_tranfer to rspi_*_dma() The DMA routines only need access to the scatter-gather tables inside the spi_transfer structures, hence just pass those. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 3dea8adfdcf3..bfa5e7e5df5a 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -463,13 +463,13 @@ static void rspi_dma_complete(void *arg) wake_up_interruptible(&rspi->wait); } -static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) +static int rspi_send_dma(struct rspi_data *rspi, struct sg_table *tx) { struct dma_async_tx_descriptor *desc; int ret; - desc = dmaengine_prep_slave_sg(rspi->master->dma_tx, t->tx_sg.sgl, - t->tx_sg.nents, DMA_TO_DEVICE, + desc = dmaengine_prep_slave_sg(rspi->master->dma_tx, tx->sgl, + tx->nents, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) return -EIO; @@ -530,21 +530,22 @@ static void qspi_receive_init(const struct rspi_data *rspi) rspi_write8(rspi, 0, QSPI_SPBFCR); } -static int rspi_send_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) +static int rspi_send_receive_dma(struct rspi_data *rspi, struct sg_table *tx, + struct sg_table *rx) { struct dma_async_tx_descriptor *desc_tx, *desc_rx; int ret; /* prepare transmit transfer */ - desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx, t->tx_sg.sgl, - t->tx_sg.nents, DMA_TO_DEVICE, + desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx, tx->sgl, + tx->nents, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_tx) return -EIO; /* prepare receive transfer */ - desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx, t->rx_sg.sgl, - t->rx_sg.nents, DMA_FROM_DEVICE, + desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx, rx->sgl, + rx->nents, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_rx) return -EIO; @@ -616,9 +617,10 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, if (master->can_dma && __rspi_can_dma(rspi, xfer)) { if (xfer->rx_buf) - return rspi_send_receive_dma(rspi, xfer); + return rspi_send_receive_dma(rspi, &xfer->tx_sg, + &xfer->rx_sg); else - return rspi_send_dma(rspi, xfer); + return rspi_send_dma(rspi, &xfer->tx_sg); } ret = rspi_pio_transfer(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len); -- cgit v1.2.3 From c52fb6d63425248bd4152451a2cc74b7df8fa989 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:15 +0200 Subject: spi: rspi: Merge rspi_*_dma() into rspi_dma_transfer() rspi_send_dma() and rspi_send_receive_dma() are very similar. Consolidate into a single function rspi_dma_transfer(), and add missing checks for dmaengine_submit() failures. Both sg_table pointer parameters can be NULL, as RSPI supports TX-only mode, and unidirectional DMA transfers will also be needed later for Dual/Quad DMA support. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 139 ++++++++++++++++++++++--------------------------- 1 file changed, 61 insertions(+), 78 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index bfa5e7e5df5a..c77cfe654b0e 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -463,30 +463,67 @@ static void rspi_dma_complete(void *arg) wake_up_interruptible(&rspi->wait); } -static int rspi_send_dma(struct rspi_data *rspi, struct sg_table *tx) +static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx, + struct sg_table *rx) { - struct dma_async_tx_descriptor *desc; + struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL; + u8 irq_mask = 0; + unsigned int other_irq = 0; + dma_cookie_t cookie; int ret; - desc = dmaengine_prep_slave_sg(rspi->master->dma_tx, tx->sgl, - tx->nents, DMA_TO_DEVICE, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - return -EIO; + if (tx) { + desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx, + tx->sgl, tx->nents, DMA_TO_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc_tx) + return -EIO; + + irq_mask |= SPCR_SPTIE; + } + if (rx) { + desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx, + rx->sgl, rx->nents, DMA_FROM_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc_rx) + return -EIO; + + irq_mask |= SPCR_SPRIE; + } /* - * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be + * DMAC needs SPxIE, but if SPxIE is set, the IRQ routine will be * called. So, this driver disables the IRQ while DMA transfer. */ - disable_irq(rspi->tx_irq); + if (tx) + disable_irq(other_irq = rspi->tx_irq); + if (rx && rspi->rx_irq != other_irq) + disable_irq(rspi->rx_irq); - rspi_enable_irq(rspi, SPCR_SPTIE); + rspi_enable_irq(rspi, irq_mask); rspi->dma_callbacked = 0; - desc->callback = rspi_dma_complete; - desc->callback_param = rspi; - dmaengine_submit(desc); - dma_async_issue_pending(rspi->master->dma_tx); + if (rx) { + desc_rx->callback = rspi_dma_complete; + desc_rx->callback_param = rspi; + cookie = dmaengine_submit(desc_rx); + if (dma_submit_error(cookie)) + return cookie; + dma_async_issue_pending(rspi->master->dma_rx); + } + if (tx) { + if (rx) { + /* No callback */ + desc_tx->callback = NULL; + } else { + desc_tx->callback = rspi_dma_complete; + desc_tx->callback_param = rspi; + } + cookie = dmaengine_submit(desc_tx); + if (dma_submit_error(cookie)) + return cookie; + dma_async_issue_pending(rspi->master->dma_tx); + } ret = wait_event_interruptible_timeout(rspi->wait, rspi->dma_callbacked, HZ); @@ -494,9 +531,14 @@ static int rspi_send_dma(struct rspi_data *rspi, struct sg_table *tx) ret = 0; else if (!ret) ret = -ETIMEDOUT; - rspi_disable_irq(rspi, SPCR_SPTIE); - enable_irq(rspi->tx_irq); + rspi_disable_irq(rspi, irq_mask); + + if (tx) + enable_irq(rspi->tx_irq); + if (rx && rspi->rx_irq != other_irq) + enable_irq(rspi->rx_irq); + return ret; } @@ -530,61 +572,6 @@ static void qspi_receive_init(const struct rspi_data *rspi) rspi_write8(rspi, 0, QSPI_SPBFCR); } -static int rspi_send_receive_dma(struct rspi_data *rspi, struct sg_table *tx, - struct sg_table *rx) -{ - struct dma_async_tx_descriptor *desc_tx, *desc_rx; - int ret; - - /* prepare transmit transfer */ - desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx, tx->sgl, - tx->nents, DMA_TO_DEVICE, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc_tx) - return -EIO; - - /* prepare receive transfer */ - desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx, rx->sgl, - rx->nents, DMA_FROM_DEVICE, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc_rx) - return -EIO; - - /* - * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be - * called. So, this driver disables the IRQ while DMA transfer. - */ - disable_irq(rspi->tx_irq); - if (rspi->rx_irq != rspi->tx_irq) - disable_irq(rspi->rx_irq); - - rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); - rspi->dma_callbacked = 0; - - desc_rx->callback = rspi_dma_complete; - desc_rx->callback_param = rspi; - dmaengine_submit(desc_rx); - dma_async_issue_pending(rspi->master->dma_rx); - - desc_tx->callback = NULL; /* No callback */ - dmaengine_submit(desc_tx); - dma_async_issue_pending(rspi->master->dma_tx); - - ret = wait_event_interruptible_timeout(rspi->wait, - rspi->dma_callbacked, HZ); - if (ret > 0 && rspi->dma_callbacked) - ret = 0; - else if (!ret) - ret = -ETIMEDOUT; - rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); - - enable_irq(rspi->tx_irq); - if (rspi->rx_irq != rspi->tx_irq) - enable_irq(rspi->rx_irq); - - return ret; -} - static bool __rspi_can_dma(const struct rspi_data *rspi, const struct spi_transfer *xfer) { @@ -615,13 +602,9 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, } rspi_write8(rspi, spcr, RSPI_SPCR); - if (master->can_dma && __rspi_can_dma(rspi, xfer)) { - if (xfer->rx_buf) - return rspi_send_receive_dma(rspi, &xfer->tx_sg, - &xfer->rx_sg); - else - return rspi_send_dma(rspi, &xfer->tx_sg); - } + if (master->can_dma && __rspi_can_dma(rspi, xfer)) + return rspi_dma_transfer(rspi, &xfer->tx_sg, + xfer->rx_buf ? &xfer->rx_sg : NULL); ret = rspi_pio_transfer(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len); if (ret < 0) -- cgit v1.2.3 From 03e627c55752fa434d5b3eba5ee3e489c51672b6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:16 +0200 Subject: spi: rspi: Absorb rspi_rz_transfer_out_in() into rspi_rz_transfer_one() Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index c77cfe654b0e..b7f8be81423b 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -616,9 +616,11 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, return 0; } -static int rspi_rz_transfer_out_in(struct rspi_data *rspi, - struct spi_transfer *xfer) +static int rspi_rz_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) { + struct rspi_data *rspi = spi_master_get_devdata(master); int ret; rspi_rz_receive_init(rspi); @@ -633,15 +635,6 @@ static int rspi_rz_transfer_out_in(struct rspi_data *rspi, return 0; } -static int rspi_rz_transfer_one(struct spi_master *master, - struct spi_device *spi, - struct spi_transfer *xfer) -{ - struct rspi_data *rspi = spi_master_get_devdata(master); - - return rspi_rz_transfer_out_in(rspi, xfer); -} - static int qspi_transfer_out_in(struct rspi_data *rspi, struct spi_transfer *xfer) { -- cgit v1.2.3 From 4f12b5e529e4ff274eb478ec1c2ef41358ed9577 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:17 +0200 Subject: spi: rspi: Add DMA support for QSPI on R-Car Gen2 Enable DMA support for QSPI on R-Car Gen2, for Single, Dual, and Quad SPI Transfers. Performance figures for reading from a QSPI FLASH driven at 24.375 MHz on r8a7791/koelsch: - Single: 1.1 Mbps PIO, 23 Mbps DMA - Dual : 12.7 Mbps PIO, 48 Mbps DMA - Quad : 13 Mbps PIO, 70 Mbps DMA Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index b7f8be81423b..bec81470dd9c 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -642,6 +642,9 @@ static int qspi_transfer_out_in(struct rspi_data *rspi, qspi_receive_init(rspi); + if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer)) + return rspi_dma_transfer(rspi, &xfer->tx_sg, &xfer->rx_sg); + ret = rspi_pio_transfer(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len); if (ret < 0) return ret; @@ -656,6 +659,9 @@ static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer) { int ret; + if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer)) + return rspi_dma_transfer(rspi, &xfer->tx_sg, NULL); + ret = rspi_pio_transfer(rspi, xfer->tx_buf, NULL, xfer->len); if (ret < 0) return ret; @@ -668,6 +674,9 @@ static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer) static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer) { + if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer)) + return rspi_dma_transfer(rspi, NULL, &xfer->rx_sg); + return rspi_pio_transfer(rspi, NULL, xfer->rx_buf, xfer->len); } -- cgit v1.2.3 From e7fb921d9f62df05240ad1a74b5a0f623e503c9c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:18 +0200 Subject: spi: rspi: Add DMA support for RSPI on RZ/A1H Enable DMA support for RSPI on r7s72100 (RZ/A1H). Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index bec81470dd9c..4bc4138e002b 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -625,6 +625,9 @@ static int rspi_rz_transfer_one(struct spi_master *master, rspi_rz_receive_init(rspi); + if (master->can_dma && __rspi_can_dma(rspi, xfer)) + return rspi_dma_transfer(rspi, &xfer->tx_sg, &xfer->rx_sg); + ret = rspi_pio_transfer(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len); if (ret < 0) return ret; -- cgit v1.2.3 From 8b983e90ea1a3dd82070f96c062ad521a06b7cc0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 2 Jun 2014 15:38:19 +0200 Subject: spi: rspi: Extract rspi_common_transfer() Extract the common parts of rspi_transfer_one(), rspi_rz_transfer_one(), and qspi_transfer_out_in() into the new function rspi_common_transfer(). Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 61 ++++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 4bc4138e002b..10112745bb17 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -586,12 +586,32 @@ static bool rspi_can_dma(struct spi_master *master, struct spi_device *spi, return __rspi_can_dma(rspi, xfer); } +static int rspi_common_transfer(struct rspi_data *rspi, + struct spi_transfer *xfer) +{ + int ret; + + if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer)) { + /* rx_buf can be NULL on RSPI on SH in TX-only Mode */ + return rspi_dma_transfer(rspi, &xfer->tx_sg, + xfer->rx_buf ? &xfer->rx_sg : NULL); + } + + ret = rspi_pio_transfer(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len); + if (ret < 0) + return ret; + + /* Wait for the last transmission */ + rspi_wait_for_tx_empty(rspi); + + return 0; +} + static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { struct rspi_data *rspi = spi_master_get_devdata(master); u8 spcr; - int ret; spcr = rspi_read8(rspi, RSPI_SPCR); if (xfer->rx_buf) { @@ -602,18 +622,7 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, } rspi_write8(rspi, spcr, RSPI_SPCR); - if (master->can_dma && __rspi_can_dma(rspi, xfer)) - return rspi_dma_transfer(rspi, &xfer->tx_sg, - xfer->rx_buf ? &xfer->rx_sg : NULL); - - ret = rspi_pio_transfer(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len); - if (ret < 0) - return ret; - - /* Wait for the last transmission */ - rspi_wait_for_tx_empty(rspi); - - return 0; + return rspi_common_transfer(rspi, xfer); } static int rspi_rz_transfer_one(struct spi_master *master, @@ -625,37 +634,15 @@ static int rspi_rz_transfer_one(struct spi_master *master, rspi_rz_receive_init(rspi); - if (master->can_dma && __rspi_can_dma(rspi, xfer)) - return rspi_dma_transfer(rspi, &xfer->tx_sg, &xfer->rx_sg); - - ret = rspi_pio_transfer(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len); - if (ret < 0) - return ret; - - /* Wait for the last transmission */ - rspi_wait_for_tx_empty(rspi); - - return 0; + return rspi_common_transfer(rspi, xfer); } static int qspi_transfer_out_in(struct rspi_data *rspi, struct spi_transfer *xfer) { - int ret; - qspi_receive_init(rspi); - if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer)) - return rspi_dma_transfer(rspi, &xfer->tx_sg, &xfer->rx_sg); - - ret = rspi_pio_transfer(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len); - if (ret < 0) - return ret; - - /* Wait for the last transmission */ - rspi_wait_for_tx_empty(rspi); - - return 0; + return rspi_common_transfer(rspi, xfer); } static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer) -- cgit v1.2.3