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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 1fb0ad21332..5639f9529e0 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 5639f9529e0..d04a4acce23 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index d04a4acce23..57beda20959 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 57beda20959..3bd06fd9af4 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 a25bd6f65e7..e546b2ceb62 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 3bd06fd9af4..ece8f603794 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index ece8f603794..fdbd46d0c57 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index fdbd46d0c57..94a99ec7d98 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 94a99ec7d98..0a7a2d618f0 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 0a7a2d618f0..1ec51cb0020 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 1ec51cb0020..7b993f75a3c 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 7b993f75a3c..753ac7bdfd5 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 753ac7bdfd5..3dea8adfdcf 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 3dea8adfdcf..bfa5e7e5df5 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index bfa5e7e5df5..c77cfe654b0 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index c77cfe654b0..b7f8be81423 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-70-g09d2 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(+) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index b7f8be81423..bec81470dd9 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-70-g09d2 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(+) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index bec81470dd9..4bc4138e002 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-70-g09d2 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(-) (limited to 'drivers/spi/spi-rspi.c') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 4bc4138e002..10112745bb1 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-70-g09d2