diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-bfin-sport.c | 15 | ||||
-rw-r--r-- | drivers/spi/spi-bfin5xx.c | 15 | ||||
-rw-r--r-- | drivers/spi/spi-pxa2xx.c | 9 | ||||
-rw-r--r-- | drivers/spi/spi-rockchip.c | 21 | ||||
-rw-r--r-- | drivers/spi/spi-sun4i.c | 23 | ||||
-rw-r--r-- | drivers/spi/spi-sun6i.c | 10 | ||||
-rw-r--r-- | drivers/spi/spi-ti-qspi.c | 7 |
7 files changed, 71 insertions, 29 deletions
diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c index 6c967555a56a..01d0ba9c5942 100644 --- a/drivers/spi/spi-bfin-sport.c +++ b/drivers/spi/spi-bfin-sport.c @@ -64,8 +64,6 @@ struct bfin_sport_spi_master_data { /* Pin request list */ u16 *pin_req; - /* Driver message queue */ - struct workqueue_struct *workqueue; struct work_struct pump_messages; spinlock_t lock; struct list_head queue; @@ -300,7 +298,7 @@ bfin_sport_spi_giveback(struct bfin_sport_spi_master_data *drv_data) drv_data->cur_msg = NULL; drv_data->cur_transfer = NULL; drv_data->cur_chip = NULL; - queue_work(drv_data->workqueue, &drv_data->pump_messages); + schedule_work(&drv_data->pump_messages); spin_unlock_irqrestore(&drv_data->lock, flags); if (!drv_data->cs_change) @@ -556,7 +554,7 @@ bfin_sport_spi_transfer(struct spi_device *spi, struct spi_message *msg) list_add_tail(&msg->queue, &drv_data->queue); if (drv_data->run && !drv_data->busy) - queue_work(drv_data->workqueue, &drv_data->pump_messages); + schedule_work(&drv_data->pump_messages); spin_unlock_irqrestore(&drv_data->lock, flags); @@ -666,12 +664,7 @@ bfin_sport_spi_init_queue(struct bfin_sport_spi_master_data *drv_data) tasklet_init(&drv_data->pump_transfers, bfin_sport_spi_pump_transfers, (unsigned long)drv_data); - /* init messages workqueue */ INIT_WORK(&drv_data->pump_messages, bfin_sport_spi_pump_messages); - drv_data->workqueue = - create_singlethread_workqueue(dev_name(drv_data->master->dev.parent)); - if (drv_data->workqueue == NULL) - return -EBUSY; return 0; } @@ -694,7 +687,7 @@ bfin_sport_spi_start_queue(struct bfin_sport_spi_master_data *drv_data) drv_data->cur_chip = NULL; spin_unlock_irqrestore(&drv_data->lock, flags); - queue_work(drv_data->workqueue, &drv_data->pump_messages); + schedule_work(&drv_data->pump_messages); return 0; } @@ -738,7 +731,7 @@ bfin_sport_spi_destroy_queue(struct bfin_sport_spi_master_data *drv_data) if (status) return status; - destroy_workqueue(drv_data->workqueue); + flush_work(&drv_data->pump_messages); return 0; } diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c index 1e91325bf39c..249c7a3677c9 100644 --- a/drivers/spi/spi-bfin5xx.c +++ b/drivers/spi/spi-bfin5xx.c @@ -67,8 +67,6 @@ struct bfin_spi_master_data { /* BFIN hookup */ struct bfin5xx_spi_master *master_info; - /* Driver message queue */ - struct workqueue_struct *workqueue; struct work_struct pump_messages; spinlock_t lock; struct list_head queue; @@ -359,7 +357,7 @@ static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data) drv_data->cur_msg = NULL; drv_data->cur_transfer = NULL; drv_data->cur_chip = NULL; - queue_work(drv_data->workqueue, &drv_data->pump_messages); + schedule_work(&drv_data->pump_messages); spin_unlock_irqrestore(&drv_data->lock, flags); msg->state = NULL; @@ -946,7 +944,7 @@ static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg) list_add_tail(&msg->queue, &drv_data->queue); if (drv_data->running && !drv_data->busy) - queue_work(drv_data->workqueue, &drv_data->pump_messages); + schedule_work(&drv_data->pump_messages); spin_unlock_irqrestore(&drv_data->lock, flags); @@ -1177,12 +1175,7 @@ static int bfin_spi_init_queue(struct bfin_spi_master_data *drv_data) tasklet_init(&drv_data->pump_transfers, bfin_spi_pump_transfers, (unsigned long)drv_data); - /* init messages workqueue */ INIT_WORK(&drv_data->pump_messages, bfin_spi_pump_messages); - drv_data->workqueue = create_singlethread_workqueue( - dev_name(drv_data->master->dev.parent)); - if (drv_data->workqueue == NULL) - return -EBUSY; return 0; } @@ -1204,7 +1197,7 @@ static int bfin_spi_start_queue(struct bfin_spi_master_data *drv_data) drv_data->cur_chip = NULL; spin_unlock_irqrestore(&drv_data->lock, flags); - queue_work(drv_data->workqueue, &drv_data->pump_messages); + schedule_work(&drv_data->pump_messages); return 0; } @@ -1246,7 +1239,7 @@ static int bfin_spi_destroy_queue(struct bfin_spi_master_data *drv_data) if (status != 0) return status; - destroy_workqueue(drv_data->workqueue); + flush_work(&drv_data->pump_messages); return 0; } diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index fe07c0592b44..daf28443b7ad 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -585,7 +585,14 @@ static void reset_sccr1(struct driver_data *drv_data) u32 sccr1_reg; sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1; - sccr1_reg &= ~SSCR1_RFT; + switch (drv_data->ssp_type) { + case QUARK_X1000_SSP: + sccr1_reg &= ~QUARK_X1000_SSCR1_RFT; + break; + default: + sccr1_reg &= ~SSCR1_RFT; + break; + } sccr1_reg |= chip->threshold; pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg); } diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index cd89682065b9..7a58db4e3285 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -142,6 +142,12 @@ /* sclk_out: spi master internal logic in rk3x can support 50Mhz */ #define MAX_SCLK_OUT 50000000 +/* + * SPI_CTRLR1 is 16-bits, so we should support lengths of 0xffff + 1. However, + * the controller seems to hang when given 0x10000, so stick with this for now. + */ +#define ROCKCHIP_SPI_MAX_TRANLEN 0xffff + enum rockchip_ssi_type { SSI_MOTO_SPI = 0, SSI_TI_SSP, @@ -573,12 +579,17 @@ static void rockchip_spi_config(struct rockchip_spi *rs) dev_dbg(rs->dev, "cr0 0x%x, div %d\n", cr0, div); } +static size_t rockchip_spi_max_transfer_size(struct spi_device *spi) +{ + return ROCKCHIP_SPI_MAX_TRANLEN; +} + static int rockchip_spi_transfer_one( struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { - int ret = 1; + int ret = 0; struct rockchip_spi *rs = spi_master_get_devdata(master); WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) && @@ -589,6 +600,11 @@ static int rockchip_spi_transfer_one( return -EINVAL; } + if (xfer->len > ROCKCHIP_SPI_MAX_TRANLEN) { + dev_err(rs->dev, "Transfer is too long (%d)\n", xfer->len); + return -EINVAL; + } + rs->speed = xfer->speed_hz; rs->bpw = xfer->bits_per_word; rs->n_bytes = rs->bpw >> 3; @@ -627,6 +643,8 @@ static int rockchip_spi_transfer_one( spi_enable_chip(rs, 1); ret = rockchip_spi_prepare_dma(rs); } + /* successful DMA prepare means the transfer is in progress */ + ret = ret ? ret : 1; } else { spi_enable_chip(rs, 1); ret = rockchip_spi_pio_transfer(rs); @@ -728,6 +746,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) master->prepare_message = rockchip_spi_prepare_message; master->unprepare_message = rockchip_spi_unprepare_message; master->transfer_one = rockchip_spi_transfer_one; + master->max_transfer_size = rockchip_spi_max_transfer_size; master->handle_err = rockchip_spi_handle_err; rs->dma_tx.ch = dma_request_chan(rs->dev, "tx"); diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c index 1ddd9e2309b6..cf007f3b83ec 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c @@ -173,13 +173,17 @@ static int sun4i_spi_transfer_one(struct spi_master *master, { struct sun4i_spi *sspi = spi_master_get_devdata(master); unsigned int mclk_rate, div, timeout; + unsigned int start, end, tx_time; unsigned int tx_len = 0; int ret = 0; u32 reg; /* We don't support transfer larger than the FIFO */ if (tfr->len > SUN4I_FIFO_DEPTH) - return -EINVAL; + return -EMSGSIZE; + + if (tfr->tx_buf && tfr->len >= SUN4I_FIFO_DEPTH) + return -EMSGSIZE; reinit_completion(&sspi->done); sspi->tx_buf = tfr->tx_buf; @@ -269,8 +273,12 @@ static int sun4i_spi_transfer_one(struct spi_master *master, sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len)); sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len)); - /* Fill the TX FIFO */ - sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH); + /* + * Fill the TX FIFO + * Filling the FIFO fully causes timeout for some reason + * at least on spi2 on A10s + */ + sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1); /* Enable the interrupts */ sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC); @@ -279,9 +287,16 @@ static int sun4i_spi_transfer_one(struct spi_master *master, reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH); + tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U); + start = jiffies; timeout = wait_for_completion_timeout(&sspi->done, - msecs_to_jiffies(1000)); + msecs_to_jiffies(tx_time)); + end = jiffies; if (!timeout) { + dev_warn(&master->dev, + "%s: timeout transferring %u bytes@%iHz for %i(%i)ms", + dev_name(&spi->dev), tfr->len, tfr->speed_hz, + jiffies_to_msecs(end - start), tx_time); ret = -ETIMEDOUT; goto out; } diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index 42e2c4bd690a..7fce79a60608 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -160,6 +160,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master, { struct sun6i_spi *sspi = spi_master_get_devdata(master); unsigned int mclk_rate, div, timeout; + unsigned int start, end, tx_time; unsigned int tx_len = 0; int ret = 0; u32 reg; @@ -269,9 +270,16 @@ static int sun6i_spi_transfer_one(struct spi_master *master, reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH); + tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U); + start = jiffies; timeout = wait_for_completion_timeout(&sspi->done, - msecs_to_jiffies(1000)); + msecs_to_jiffies(tx_time)); + end = jiffies; if (!timeout) { + dev_warn(&master->dev, + "%s: timeout transferring %u bytes@%iHz for %i(%i)ms", + dev_name(&spi->dev), tfr->len, tfr->speed_hz, + jiffies_to_msecs(end - start), tx_time); ret = -ETIMEDOUT; goto out; } diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 443f664534e1..29ea8d2f9824 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -646,6 +646,13 @@ free_master: static int ti_qspi_remove(struct platform_device *pdev) { + struct ti_qspi *qspi = platform_get_drvdata(pdev); + int rc; + + rc = spi_master_suspend(qspi->master); + if (rc) + return rc; + pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); |