From bb51537aa825e98b970c784f802e7e09f29df3ba Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 14 Mar 2016 16:30:16 +0100 Subject: spi: rockchip: Spelling s/divsor/divisor/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 26e2688c104e..bfeb0d4c7ee0 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -527,7 +527,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs) if (WARN_ON(rs->speed > MAX_SCLK_OUT)) rs->speed = MAX_SCLK_OUT; - /* the minimum divsor is 2 */ + /* the minimum divisor is 2 */ if (rs->max_freq < 2 * rs->speed) { clk_set_rate(rs->spiclk, 2 * rs->speed); rs->max_freq = clk_get_rate(rs->spiclk); -- cgit v1.2.3-58-ga151 From 793c7f9212fdb7bea5e017427e750afa11217c29 Mon Sep 17 00:00:00 2001 From: Knut Wohlrab Date: Tue, 15 Mar 2016 14:24:36 +0100 Subject: spi: imx: only do necessary changes to ECSPIx_CONFIGREG If the SPI chip select (CS) for a dedicated channel is done manually by the used higher device driver, the CS may be active while writing to ECSPIx_CONFIGREG. To prevent unwanted clock edges when selecting the clock mode, only do the necessary changes to the i.MX SPI configuration register and leave not selected channels untouched. To prevent unwanted clock edges on first use, an empty dummy transmission shall be done by the initialization procedure of the device driver of this channel. This will set the clock mode to the correct state. Signed-off-by: Knut Wohlrab Signed-off-by: Dirk Behme Acked-by: Sascha Hauer Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index e7a19be87c38..b79d70d6dabf 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -333,8 +333,9 @@ static void __maybe_unused mx51_ecspi_trigger(struct spi_imx_data *spi_imx) static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx, struct spi_imx_config *config) { - u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0; + u32 ctrl = MX51_ECSPI_CTRL_ENABLE; u32 clk = config->speed_hz, delay, reg; + u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG); /* * The hardware seems to have a race condition when changing modes. The @@ -358,13 +359,20 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx, if (config->mode & SPI_CPHA) cfg |= MX51_ECSPI_CONFIG_SCLKPHA(config->cs); + else + cfg &= ~MX51_ECSPI_CONFIG_SCLKPHA(config->cs); if (config->mode & SPI_CPOL) { cfg |= MX51_ECSPI_CONFIG_SCLKPOL(config->cs); cfg |= MX51_ECSPI_CONFIG_SCLKCTL(config->cs); + } else { + cfg &= ~MX51_ECSPI_CONFIG_SCLKPOL(config->cs); + cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(config->cs); } if (config->mode & SPI_CS_HIGH) cfg |= MX51_ECSPI_CONFIG_SSBPOL(config->cs); + else + cfg &= ~MX51_ECSPI_CONFIG_SSBPOL(config->cs); if (spi_imx->usedma) ctrl |= MX51_ECSPI_CTRL_SMC; -- cgit v1.2.3-58-ga151 From cd8dd41a33264a4602539711f76670c2a1f4d007 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 17 Mar 2016 09:21:50 +0100 Subject: spi: imx: Fix possible NULL pointer deref transfer could be NULL in spi_imx_can_dma() when it's called from spi_imx_setupxfer() with a NULL transfer. Test for a NULL pointer before dereferencing it. Signed-off-by: Sascha Hauer Cc: Dan Carpenter Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index b79d70d6dabf..50769078e72e 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -211,11 +211,15 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *transfer) { struct spi_imx_data *spi_imx = spi_master_get_devdata(master); - unsigned int bpw = transfer->bits_per_word; + unsigned int bpw; if (!master->dma_rx) return false; + if (!transfer) + return false; + + bpw = transfer->bits_per_word; if (!bpw) bpw = spi->bits_per_word; -- cgit v1.2.3-58-ga151 From 24c8cd1b081286fd34340f0e1fc68a774a5a775f Mon Sep 17 00:00:00 2001 From: Heiko Stübner Date: Fri, 18 Mar 2016 11:15:11 +0100 Subject: spi: fix possible deadlock between internal bus locks and bus_lock_flag External users may use spi_bus_lock to get exclusive access. This will also grab the bus_lock_mutex and may therefore result in a deadlock if __spi_pump_messages also tries to get the mutex. Therefore adapt spi_pump_messages as well as spi_sync to preset the bus_locked parameter according to the master->bus_lock_flag. Fixes: 49023d2e4ead ("spi: core: Fix deadlock when sending messages") Signed-off-by: Heiko Stuebner Signed-off-by: Mark Brown --- drivers/spi/spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index de2f2f90d799..0239b45eed92 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1209,7 +1209,7 @@ static void spi_pump_messages(struct kthread_work *work) struct spi_master *master = container_of(work, struct spi_master, pump_messages); - __spi_pump_messages(master, true, false); + __spi_pump_messages(master, true, master->bus_lock_flag); } static int spi_init_queue(struct spi_master *master) @@ -2853,7 +2853,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, */ int spi_sync(struct spi_device *spi, struct spi_message *message) { - return __spi_sync(spi, message, 0); + return __spi_sync(spi, message, spi->master->bus_lock_flag); } EXPORT_SYMBOL_GPL(spi_sync); -- cgit v1.2.3-58-ga151 From 3525e0aac91c4de5d20b1f22a6c6e2b39db3cc96 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Tue, 22 Mar 2016 01:00:21 +0900 Subject: spi: omap2-mcspi: fix dma transfer for vmalloced buffer Currently omap2-mcspi cannot handle dma transfer for vmalloced buffer. I hit this problem when using mtdblock on spi-nor. This lets the SPI core handle the page mapping for dma transfer buffer. Signed-off-by: Akinobu Mita Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 62 ++++++++++++------------------------------- 1 file changed, 17 insertions(+), 45 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 0caa3c8bef46..43a02e377b3b 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -423,16 +423,12 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi, if (mcspi_dma->dma_tx) { struct dma_async_tx_descriptor *tx; - struct scatterlist sg; dmaengine_slave_config(mcspi_dma->dma_tx, &cfg); - sg_init_table(&sg, 1); - sg_dma_address(&sg) = xfer->tx_dma; - sg_dma_len(&sg) = xfer->len; - - tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1, - DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl, + xfer->tx_sg.nents, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (tx) { tx->callback = omap2_mcspi_tx_callback; tx->callback_param = spi; @@ -478,20 +474,15 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, if (mcspi_dma->dma_rx) { struct dma_async_tx_descriptor *tx; - struct scatterlist sg; dmaengine_slave_config(mcspi_dma->dma_rx, &cfg); if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0) dma_count -= es; - sg_init_table(&sg, 1); - sg_dma_address(&sg) = xfer->rx_dma; - sg_dma_len(&sg) = dma_count; - - tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1, - DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | - DMA_CTRL_ACK); + tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, xfer->rx_sg.sgl, + xfer->rx_sg.nents, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (tx) { tx->callback = omap2_mcspi_rx_callback; tx->callback_param = spi; @@ -505,8 +496,6 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, omap2_mcspi_set_dma_req(spi, 1, 1); wait_for_completion(&mcspi_dma->dma_rx_completion); - dma_unmap_single(mcspi->dev, xfer->rx_dma, count, - DMA_FROM_DEVICE); if (mcspi->fifo_depth > 0) return count; @@ -619,8 +608,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) if (tx != NULL) { wait_for_completion(&mcspi_dma->dma_tx_completion); - dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len, - DMA_TO_DEVICE); if (mcspi->fifo_depth > 0) { irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS; @@ -1087,6 +1074,16 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) gpio_free(spi->cs_gpio); } +static bool omap2_mcspi_can_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + if (xfer->len < DMA_MIN_BYTES) + return false; + + return true; +} + static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi, struct spi_device *spi, struct spi_transfer *t) { @@ -1268,32 +1265,6 @@ static int omap2_mcspi_transfer_one(struct spi_master *master, return -EINVAL; } - if (len < DMA_MIN_BYTES) - goto skip_dma_map; - - if (mcspi_dma->dma_tx && tx_buf != NULL) { - t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf, - len, DMA_TO_DEVICE); - if (dma_mapping_error(mcspi->dev, t->tx_dma)) { - dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", - 'T', len); - return -EINVAL; - } - } - if (mcspi_dma->dma_rx && rx_buf != NULL) { - t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len, - DMA_FROM_DEVICE); - if (dma_mapping_error(mcspi->dev, t->rx_dma)) { - dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", - 'R', len); - if (tx_buf != NULL) - dma_unmap_single(mcspi->dev, t->tx_dma, - len, DMA_TO_DEVICE); - return -EINVAL; - } - } - -skip_dma_map: return omap2_mcspi_work_one(mcspi, spi, t); } @@ -1377,6 +1348,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev) master->transfer_one = omap2_mcspi_transfer_one; master->set_cs = omap2_mcspi_set_cs; master->cleanup = omap2_mcspi_cleanup; + master->can_dma = omap2_mcspi_can_dma; master->dev.of_node = node; master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ; master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15; -- cgit v1.2.3-58-ga151 From e4c0e06f949b9493cafe952c3029576b47c2a7c4 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 31 Mar 2016 11:11:41 +0800 Subject: spi: rockchip: fix probe deferral handling Use dma_request_chan instead of dma_request_slave_channel, in this case we can check EPROBE_DEFER without static warning. Reported-by: Dan Carpenter Signed-off-by: Shawn Lin Reviewed-by: Douglas Anderson Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index bfeb0d4c7ee0..9713b811a2cd 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -723,23 +723,27 @@ static int rockchip_spi_probe(struct platform_device *pdev) master->transfer_one = rockchip_spi_transfer_one; master->handle_err = rockchip_spi_handle_err; - rs->dma_tx.ch = dma_request_slave_channel(rs->dev, "tx"); - if (IS_ERR_OR_NULL(rs->dma_tx.ch)) { + rs->dma_tx.ch = dma_request_chan(rs->dev, "tx"); + if (IS_ERR(rs->dma_tx.ch)) { /* Check tx to see if we need defer probing driver */ if (PTR_ERR(rs->dma_tx.ch) == -EPROBE_DEFER) { ret = -EPROBE_DEFER; goto err_get_fifo_len; } dev_warn(rs->dev, "Failed to request TX DMA channel\n"); + rs->dma_tx.ch = NULL; } - rs->dma_rx.ch = dma_request_slave_channel(rs->dev, "rx"); - if (!rs->dma_rx.ch) { - if (rs->dma_tx.ch) { + rs->dma_rx.ch = dma_request_chan(rs->dev, "rx"); + if (IS_ERR(rs->dma_rx.ch)) { + if (PTR_ERR(rs->dma_rx.ch) == -EPROBE_DEFER) { dma_release_channel(rs->dma_tx.ch); rs->dma_tx.ch = NULL; + ret = -EPROBE_DEFER; + goto err_get_fifo_len; } dev_warn(rs->dev, "Failed to request RX DMA channel\n"); + rs->dma_rx.ch = NULL; } if (rs->dma_tx.ch && rs->dma_rx.ch) { -- cgit v1.2.3-58-ga151