diff options
author | Mark Brown <broonie@kernel.org> | 2014-08-31 13:46:19 +0100 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2014-08-31 13:46:19 +0100 |
commit | 29571ce4a3577ae0bff3909da7c1befef1d739db (patch) | |
tree | 7e6c7435a499336754a243bf89c3daf906bb1a5e | |
parent | 52addcf9d6669fa439387610bc65c92fa0980cef (diff) | |
parent | 360b2eaeb563896ab95db45eb7d1b83c9a04c292 (diff) |
Merge tag 'spi-v3.17-rc3' into spi-linus
spi: Bug fixes for v3.17
A smattering of bug fixes for the SPI subsystem, all in driver code
which has seen active work recently and none of them with any great
global impact.
There's also a new ACPI ID for the pxa2xx driver which required no code
changes and the addition of kerneldoc for some structure fields that
were missing it and generating warnings during documentation builds as a
result.
# gpg: Signature made Sun 31 Aug 2014 13:19:12 BST using RSA key ID 7EA229BD
# gpg: Good signature from "Mark Brown <broonie@sirena.org.uk>"
# gpg: aka "Mark Brown <broonie@debian.org>"
# gpg: aka "Mark Brown <broonie@kernel.org>"
# gpg: aka "Mark Brown <broonie@tardis.ed.ac.uk>"
# gpg: aka "Mark Brown <broonie@linaro.org>"
# gpg: aka "Mark Brown <Mark.Brown@linaro.org>"
-rw-r--r-- | drivers/spi/spi-au1550.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-davinci.c | 16 | ||||
-rw-r--r-- | drivers/spi/spi-dw-pci.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-dw.c | 2 | ||||
-rw-r--r-- | drivers/spi/spi-omap2-mcspi.c | 3 | ||||
-rw-r--r-- | drivers/spi/spi-pxa2xx.c | 1 | ||||
-rw-r--r-- | drivers/spi/spi-rockchip.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi-rspi.c | 94 | ||||
-rw-r--r-- | drivers/spi/spi-sh-msiof.c | 71 | ||||
-rw-r--r-- | drivers/spi/spi.c | 1 | ||||
-rw-r--r-- | include/linux/spi/spi.h | 7 |
11 files changed, 121 insertions, 82 deletions
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c index 40c3d43c9292..f40b34cdf2fc 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c @@ -945,7 +945,7 @@ static int au1550_spi_remove(struct platform_device *pdev) spi_bitbang_stop(&hw->bitbang); free_irq(hw->irq, hw); iounmap((void __iomem *)hw->regs); - release_mem_region(r->start, sizeof(psc_spi_t)); + release_mem_region(hw->ioarea->start, sizeof(psc_spi_t)); if (hw->usedma) { au1550_spi_dma_rxtmp_free(hw); diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 276a3884fb3c..48f1d26e6ad9 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -417,16 +417,16 @@ static int davinci_spi_setup(struct spi_device *spi) flags, dev_name(&spi->dev)); internal_cs = false; } - } - if (retval) { - dev_err(&spi->dev, "GPIO %d setup failed (%d)\n", - spi->cs_gpio, retval); - return retval; - } + if (retval) { + dev_err(&spi->dev, "GPIO %d setup failed (%d)\n", + spi->cs_gpio, retval); + return retval; + } - if (internal_cs) - set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select); + if (internal_cs) + set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select); + } if (spi->mode & SPI_READY) set_io_bits(dspi->base + SPIPC0, SPIPC0_SPIENA_MASK); diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 3f3dc1226edf..e14960470d8d 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -62,6 +62,8 @@ static int spi_pci_probe(struct pci_dev *pdev, if (ret) return ret; + dws->regs = pcim_iomap_table(pdev)[pci_bar]; + dws->bus_num = 0; dws->num_cs = 4; dws->irq = pdev->irq; diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 29f33143b795..670f0627f3bf 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -271,7 +271,7 @@ static void giveback(struct dw_spi *dws) transfer_list); if (!last_transfer->cs_change) - spi_chip_sel(dws, dws->cur_msg->spi, 0); + spi_chip_sel(dws, msg->spi, 0); spi_finalize_current_message(dws->master); } diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 68441fa448de..352eed7463ac 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -329,7 +329,8 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi, disable_fifo: if (t->rx_buf != NULL) chconf &= ~OMAP2_MCSPI_CHCONF_FFER; - else + + if (t->tx_buf != NULL) chconf &= ~OMAP2_MCSPI_CHCONF_FFET; mcspi_write_chconf0(spi, chconf); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index fe792106bdc5..46f45ca2c694 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1074,6 +1074,7 @@ static struct acpi_device_id pxa2xx_spi_acpi_match[] = { { "INT3430", 0 }, { "INT3431", 0 }, { "80860F0E", 0 }, + { "8086228E", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index c0743604b906..cd0e08b0c9f6 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -499,7 +499,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs) } /* div doesn't support odd number */ - div = rs->max_freq / rs->speed; + div = max_t(u32, rs->max_freq / rs->speed, 1); div = (div + 1) & 0xfffe; spi_enable_chip(rs, 0); @@ -678,7 +678,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) rs->dma_tx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_TXDR); rs->dma_rx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_RXDR); rs->dma_tx.direction = DMA_MEM_TO_DEV; - rs->dma_tx.direction = DMA_DEV_TO_MEM; + rs->dma_rx.direction = DMA_DEV_TO_MEM; master->can_dma = rockchip_spi_can_dma; master->dma_tx = rs->dma_tx.ch; diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index c850dfdfa9e3..ad87a98f8f68 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -472,25 +472,52 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx, dma_cookie_t cookie; int ret; - 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) - goto no_dma; - - irq_mask |= SPCR_SPTIE; - } + /* First prepare and submit the DMA request(s), as this may fail */ 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) - goto no_dma; + if (!desc_rx) { + ret = -EAGAIN; + goto no_dma_rx; + } + + desc_rx->callback = rspi_dma_complete; + desc_rx->callback_param = rspi; + cookie = dmaengine_submit(desc_rx); + if (dma_submit_error(cookie)) { + ret = cookie; + goto no_dma_rx; + } irq_mask |= SPCR_SPRIE; } + 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) { + ret = -EAGAIN; + goto no_dma_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)) { + ret = cookie; + goto no_dma_tx; + } + + irq_mask |= SPCR_SPTIE; + } + /* * DMAC needs SPxIE, but if SPxIE is set, the IRQ routine will be * called. So, this driver disables the IRQ while DMA transfer. @@ -503,34 +530,24 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx, rspi_enable_irq(rspi, irq_mask); rspi->dma_callbacked = 0; - 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; + /* Now start DMA */ + if (rx) 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; + if (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) + else if (!ret) { + dev_err(&rspi->master->dev, "DMA timeout\n"); ret = -ETIMEDOUT; + if (tx) + dmaengine_terminate_all(rspi->master->dma_tx); + if (rx) + dmaengine_terminate_all(rspi->master->dma_rx); + } rspi_disable_irq(rspi, irq_mask); @@ -541,11 +558,16 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx, return ret; -no_dma: - pr_warn_once("%s %s: DMA not available, falling back to PIO\n", - dev_driver_string(&rspi->master->dev), - dev_name(&rspi->master->dev)); - return -EAGAIN; +no_dma_tx: + if (rx) + dmaengine_terminate_all(rspi->master->dma_rx); +no_dma_rx: + if (ret == -EAGAIN) { + pr_warn_once("%s %s: DMA not available, falling back to PIO\n", + dev_driver_string(&rspi->master->dev), + dev_name(&rspi->master->dev)); + } + return ret; } static void rspi_receive_init(const struct rspi_data *rspi) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 2a4354dcd661..887c2084130f 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -636,48 +636,38 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, dma_cookie_t cookie; int ret; - if (tx) { - ier_bits |= IER_TDREQE | IER_TDMAE; - dma_sync_single_for_device(p->master->dma_tx->device->dev, - p->tx_dma_addr, len, DMA_TO_DEVICE); - desc_tx = dmaengine_prep_slave_single(p->master->dma_tx, - p->tx_dma_addr, len, DMA_TO_DEVICE, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc_tx) - return -EAGAIN; - } - + /* First prepare and submit the DMA request(s), as this may fail */ if (rx) { ier_bits |= IER_RDREQE | IER_RDMAE; desc_rx = dmaengine_prep_slave_single(p->master->dma_rx, p->rx_dma_addr, len, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc_rx) - return -EAGAIN; - } - - /* 1 stage FIFO watermarks for DMA */ - sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1); - - /* setup msiof transfer mode registers (32-bit words) */ - sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4); - - sh_msiof_write(p, IER, ier_bits); - - reinit_completion(&p->done); + if (!desc_rx) { + ret = -EAGAIN; + goto no_dma_rx; + } - if (rx) { desc_rx->callback = sh_msiof_dma_complete; desc_rx->callback_param = p; cookie = dmaengine_submit(desc_rx); if (dma_submit_error(cookie)) { ret = cookie; - goto stop_ier; + goto no_dma_rx; } - dma_async_issue_pending(p->master->dma_rx); } if (tx) { + ier_bits |= IER_TDREQE | IER_TDMAE; + dma_sync_single_for_device(p->master->dma_tx->device->dev, + p->tx_dma_addr, len, DMA_TO_DEVICE); + desc_tx = dmaengine_prep_slave_single(p->master->dma_tx, + p->tx_dma_addr, len, DMA_TO_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc_tx) { + ret = -EAGAIN; + goto no_dma_tx; + } + if (rx) { /* No callback */ desc_tx->callback = NULL; @@ -688,15 +678,30 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, cookie = dmaengine_submit(desc_tx); if (dma_submit_error(cookie)) { ret = cookie; - goto stop_rx; + goto no_dma_tx; } - dma_async_issue_pending(p->master->dma_tx); } + /* 1 stage FIFO watermarks for DMA */ + sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1); + + /* setup msiof transfer mode registers (32-bit words) */ + sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4); + + sh_msiof_write(p, IER, ier_bits); + + reinit_completion(&p->done); + + /* Now start DMA */ + if (tx) + dma_async_issue_pending(p->master->dma_rx); + if (rx) + dma_async_issue_pending(p->master->dma_tx); + ret = sh_msiof_spi_start(p, rx); if (ret) { dev_err(&p->pdev->dev, "failed to start hardware\n"); - goto stop_tx; + goto stop_dma; } /* wait for tx fifo to be emptied / rx fifo to be filled */ @@ -726,14 +731,14 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, stop_reset: sh_msiof_reset_str(p); sh_msiof_spi_stop(p, rx); -stop_tx: +stop_dma: if (tx) dmaengine_terminate_all(p->master->dma_tx); -stop_rx: +no_dma_tx: if (rx) dmaengine_terminate_all(p->master->dma_rx); -stop_ier: sh_msiof_write(p, IER, 0); +no_dma_rx: return ret; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index e0531baf2782..ca935df80c88 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -848,6 +848,7 @@ out: /** * spi_finalize_current_transfer - report completion of a transfer + * @master: the master reporting completion * * Called by SPI drivers using the core transfer_one_message() * implementation to notify it that the current interrupt driven diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index e713543336f1..46d188a9947c 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -253,6 +253,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * the device whose settings are being modified. * @transfer: adds a message to the controller's transfer queue. * @cleanup: frees controller-specific state + * @can_dma: determine whether this master supports DMA * @queued: whether this master is providing an internal message queue * @kworker: thread struct for message pump * @kworker_task: pointer to task for message pump kworker thread @@ -262,6 +263,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @cur_msg: the currently in-flight message * @cur_msg_prepared: spi_prepare_message was called for the currently * in-flight message + * @cur_msg_mapped: message has been mapped for DMA * @xfer_completion: used by core transfer_one_message() * @busy: message pump is busy * @running: message pump is running @@ -299,6 +301,10 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @cs_gpios: Array of GPIOs to use as chip select lines; one per CS * number. Any individual value may be -ENOENT for CS lines that * are not GPIOs (driven by the SPI controller itself). + * @dma_tx: DMA transmit channel + * @dma_rx: DMA receive channel + * @dummy_rx: dummy receive buffer for full-duplex devices + * @dummy_tx: dummy transmit buffer for full-duplex devices * * Each SPI master controller can communicate with one or more @spi_device * children. These make a small bus, sharing MOSI, MISO and SCK signals @@ -632,6 +638,7 @@ struct spi_transfer { * addresses for each transfer buffer * @complete: called to report transaction completions * @context: the argument to complete() when it's called + * @frame_length: the total number of bytes in the message * @actual_length: the total number of bytes that were transferred in all * successful segments * @status: zero for success, else negative errno |