diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/Kconfig | 3 | ||||
-rw-r--r-- | drivers/spi/spi-bcm2835.c | 5 | ||||
-rw-r--r-- | drivers/spi/spi-bitbang.c | 17 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-cpm.c | 40 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-espi.c | 45 | ||||
-rw-r--r-- | drivers/spi/spi-omap2-mcspi.c | 16 | ||||
-rw-r--r-- | drivers/spi/spi.c | 9 |
7 files changed, 89 insertions, 46 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 198f96b7fb45..72b059081559 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -78,6 +78,7 @@ config SPI_ATMEL config SPI_BCM2835 tristate "BCM2835 SPI controller" depends on ARCH_BCM2835 || COMPILE_TEST + depends on GPIOLIB help This selects a driver for the Broadcom BCM2835 SPI master. @@ -302,7 +303,7 @@ config SPI_FSL_SPI config SPI_FSL_DSPI tristate "Freescale DSPI controller" select REGMAP_MMIO - depends on SOC_VF610 || COMPILE_TEST + depends on SOC_VF610 || SOC_LS1021A || COMPILE_TEST help This enables support for the Freescale DSPI controller in master mode. VF610 platform uses the controller. diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index f63864a893c5..37875cf942f7 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -164,13 +164,12 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master, unsigned long xfer_time_us) { struct bcm2835_spi *bs = spi_master_get_devdata(master); - unsigned long timeout = jiffies + - max(4 * xfer_time_us * HZ / 1000000, 2uL); + /* set timeout to 1 second of maximum polling */ + unsigned long timeout = jiffies + HZ; /* enable HW block without interrupts */ bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA); - /* set timeout to 4x the expected time, or 2 jiffies */ /* loop until finished the transfer */ while (bs->rx_len) { /* read from fifo as much as possible */ diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 5ef6638d5e8a..840a4984d365 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -180,7 +180,6 @@ int spi_bitbang_setup(struct spi_device *spi) { struct spi_bitbang_cs *cs = spi->controller_state; struct spi_bitbang *bitbang; - int retval; unsigned long flags; bitbang = spi_master_get_devdata(spi->master); @@ -197,9 +196,11 @@ int spi_bitbang_setup(struct spi_device *spi) if (!cs->txrx_word) return -EINVAL; - retval = bitbang->setup_transfer(spi, NULL); - if (retval < 0) - return retval; + if (bitbang->setup_transfer) { + int retval = bitbang->setup_transfer(spi, NULL); + if (retval < 0) + return retval; + } dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs); @@ -295,9 +296,11 @@ static int spi_bitbang_transfer_one(struct spi_master *master, /* init (-1) or override (1) transfer params */ if (do_setup != 0) { - status = bitbang->setup_transfer(spi, t); - if (status < 0) - break; + if (bitbang->setup_transfer) { + status = bitbang->setup_transfer(spi, t); + if (status < 0) + break; + } if (do_setup == -1) do_setup = 0; } diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c index 9c46a3058743..896add8cfd3b 100644 --- a/drivers/spi/spi-fsl-cpm.c +++ b/drivers/spi/spi-fsl-cpm.c @@ -24,6 +24,7 @@ #include <linux/of_address.h> #include <linux/spi/spi.h> #include <linux/types.h> +#include <linux/platform_device.h> #include "spi-fsl-cpm.h" #include "spi-fsl-lib.h" @@ -269,17 +270,6 @@ static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi) if (mspi->flags & SPI_CPM2) { pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); out_be16(spi_base, pram_ofs); - } else { - struct spi_pram __iomem *pram = spi_base; - u16 rpbase = in_be16(&pram->rpbase); - - /* Microcode relocation patch applied? */ - if (rpbase) { - pram_ofs = rpbase; - } else { - pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); - out_be16(spi_base, pram_ofs); - } } iounmap(spi_base); @@ -292,7 +282,6 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) struct device_node *np = dev->of_node; const u32 *iprop; int size; - unsigned long pram_ofs; unsigned long bds_ofs; if (!(mspi->flags & SPI_CPM_MODE)) @@ -319,8 +308,26 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) } } - pram_ofs = fsl_spi_cpm_get_pram(mspi); - if (IS_ERR_VALUE(pram_ofs)) { + if (mspi->flags & SPI_CPM1) { + struct resource *res; + void *pram; + + res = platform_get_resource(to_platform_device(dev), + IORESOURCE_MEM, 1); + pram = devm_ioremap_resource(dev, res); + if (IS_ERR(pram)) + mspi->pram = NULL; + else + mspi->pram = pram; + } else { + unsigned long pram_ofs = fsl_spi_cpm_get_pram(mspi); + + if (IS_ERR_VALUE(pram_ofs)) + mspi->pram = NULL; + else + mspi->pram = cpm_muram_addr(pram_ofs); + } + if (mspi->pram == NULL) { dev_err(dev, "can't allocate spi parameter ram\n"); goto err_pram; } @@ -346,8 +353,6 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) goto err_dummy_rx; } - mspi->pram = cpm_muram_addr(pram_ofs); - mspi->tx_bd = cpm_muram_addr(bds_ofs); mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd)); @@ -375,7 +380,8 @@ err_dummy_rx: err_dummy_tx: cpm_muram_free(bds_ofs); err_bds: - cpm_muram_free(pram_ofs); + if (!(mspi->flags & SPI_CPM1)) + cpm_muram_free(cpm_muram_offset(mspi->pram)); err_pram: fsl_spi_free_dummy_rx(); return -ENOMEM; diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index d0a73a09a9bd..80d245ac846f 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -359,14 +359,16 @@ static void fsl_espi_rw_trans(struct spi_message *m, struct fsl_espi_transfer *trans, u8 *rx_buff) { struct fsl_espi_transfer *espi_trans = trans; - unsigned int n_tx = espi_trans->n_tx; - unsigned int n_rx = espi_trans->n_rx; + unsigned int total_len = espi_trans->len; struct spi_transfer *t; u8 *local_buf; u8 *rx_buf = rx_buff; unsigned int trans_len; unsigned int addr; - int i, pos, loop; + unsigned int tx_only; + unsigned int rx_pos = 0; + unsigned int pos; + int i, loop; local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL); if (!local_buf) { @@ -374,36 +376,48 @@ static void fsl_espi_rw_trans(struct spi_message *m, return; } - for (pos = 0, loop = 0; pos < n_rx; pos += trans_len, loop++) { - trans_len = n_rx - pos; - if (trans_len > SPCOM_TRANLEN_MAX - n_tx) - trans_len = SPCOM_TRANLEN_MAX - n_tx; + for (pos = 0, loop = 0; pos < total_len; pos += trans_len, loop++) { + trans_len = total_len - pos; i = 0; + tx_only = 0; list_for_each_entry(t, &m->transfers, transfer_list) { if (t->tx_buf) { memcpy(local_buf + i, t->tx_buf, t->len); i += t->len; + if (!t->rx_buf) + tx_only += t->len; } } + /* Add additional TX bytes to compensate SPCOM_TRANLEN_MAX */ + if (loop > 0) + trans_len += tx_only; + + if (trans_len > SPCOM_TRANLEN_MAX) + trans_len = SPCOM_TRANLEN_MAX; + + /* Update device offset */ if (pos > 0) { addr = fsl_espi_cmd2addr(local_buf); - addr += pos; + addr += rx_pos; fsl_espi_addr2cmd(addr, local_buf); } - espi_trans->n_tx = n_tx; - espi_trans->n_rx = trans_len; - espi_trans->len = trans_len + n_tx; + espi_trans->len = trans_len; espi_trans->tx_buf = local_buf; espi_trans->rx_buf = local_buf; fsl_espi_do_trans(m, espi_trans); - memcpy(rx_buf + pos, espi_trans->rx_buf + n_tx, trans_len); + /* If there is at least one RX byte then copy it to rx_buf */ + if (tx_only < SPCOM_TRANLEN_MAX) + memcpy(rx_buf + rx_pos, espi_trans->rx_buf + tx_only, + trans_len - tx_only); + + rx_pos += trans_len - tx_only; if (loop > 0) - espi_trans->actual_length += espi_trans->len - n_tx; + espi_trans->actual_length += espi_trans->len - tx_only; else espi_trans->actual_length += espi_trans->len; } @@ -418,6 +432,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master, u8 *rx_buf = NULL; unsigned int n_tx = 0; unsigned int n_rx = 0; + unsigned int xfer_len = 0; struct fsl_espi_transfer espi_trans; list_for_each_entry(t, &m->transfers, transfer_list) { @@ -427,11 +442,13 @@ static int fsl_espi_do_one_msg(struct spi_master *master, n_rx += t->len; rx_buf = t->rx_buf; } + if ((t->tx_buf) || (t->rx_buf)) + xfer_len += t->len; } espi_trans.n_tx = n_tx; espi_trans.n_rx = n_rx; - espi_trans.len = n_tx + n_rx; + espi_trans.len = xfer_len; espi_trans.actual_length = 0; espi_trans.status = 0; diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 4df8942058de..d1a5b9fc3eba 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1210,6 +1210,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, struct omap2_mcspi *mcspi; struct omap2_mcspi_dma *mcspi_dma; struct spi_transfer *t; + int status; spi = m->spi; mcspi = spi_master_get_devdata(master); @@ -1229,7 +1230,8 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, tx_buf ? "tx" : "", rx_buf ? "rx" : "", t->bits_per_word); - return -EINVAL; + status = -EINVAL; + goto out; } if (m->is_dma_mapped || len < DMA_MIN_BYTES) @@ -1241,7 +1243,8 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, if (dma_mapping_error(mcspi->dev, t->tx_dma)) { dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", 'T', len); - return -EINVAL; + status = -EINVAL; + goto out; } } if (mcspi_dma->dma_rx && rx_buf != NULL) { @@ -1253,14 +1256,19 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, if (tx_buf != NULL) dma_unmap_single(mcspi->dev, t->tx_dma, len, DMA_TO_DEVICE); - return -EINVAL; + status = -EINVAL; + goto out; } } } omap2_mcspi_work(mcspi, m); + /* spi_finalize_current_message() changes the status inside the + * spi_message, save the status here. */ + status = m->status; +out: spi_finalize_current_message(master); - return 0; + return status; } static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index d5d7d2235163..50910d85df5a 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -583,6 +583,15 @@ static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg) rx_dev = master->dma_rx->device->dev; list_for_each_entry(xfer, &msg->transfers, transfer_list) { + /* + * Restore the original value of tx_buf or rx_buf if they are + * NULL. + */ + if (xfer->tx_buf == master->dummy_tx) + xfer->tx_buf = NULL; + if (xfer->rx_buf == master->dummy_rx) + xfer->rx_buf = NULL; + if (!master->can_dma(master, msg->spi, xfer)) continue; |