diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-04-27 02:32:11 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-04-27 02:32:11 +0300 |
commit | 4a0225c3d208cfa6e4550f2210ffd9114a952a81 (patch) | |
tree | 235f99c743c1e03780a9e75509cba7c50cc3bf7a /drivers/spi/spi-stm32-qspi.c | |
parent | ca62e9090d229926f43f20291bb44d67897baab7 (diff) | |
parent | 86527bcbc88922ea40df05d28189ee15489d2cf1 (diff) | |
download | linux-4a0225c3d208cfa6e4550f2210ffd9114a952a81.tar.xz |
Merge tag 'spi-v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown:
"The only core work for SPI this time around is the completion of the
conversion to the new style method for specifying transfer delays,
meaning we can cope with what most controllers support more directly
using conversions in the core rather than open coding in drivers.
Otherwise it's a good stack of cleanups and fixes plus a few new
drivers.
Summary:
- Completion of the conversion to new style transfer delay
configuration
- Introduction and use of module_parport_driver() helper, merged here
as there's no parport tree
- Support for Altera SoCs on DFL buses, NXP i.MX8DL, HiSilicon
Kunpeng, MediaTek MT8195"
* tag 'spi-v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (113 commits)
spi: Rename enable1 to activate in spi_set_cs()
spi: Convert Freescale QSPI binding to json schema
spi: stm32-qspi: fix debug format string
spi: tools: make a symbolic link to the header file spi.h
spi: fsi: add a missing of_node_put
spi: Make error handling of gpiod_count() call cleaner
spidev: Add Micron SPI NOR Authenta device compatible
spi: brcm,spi-bcm-qspi: convert to the json-schema
spi: altera: Add DFL bus driver for Altera API Controller
spi: altera: separate core code from platform code
spi: stm32-qspi: Fix compilation warning in ARM64
spi: Handle SPI device setup callback failure.
spi: sync up initial chipselect state
spi: stm32-qspi: Add dirmap support
spi: stm32-qspi: Trigger DMA only if more than 4 bytes to transfer
spi: stm32-qspi: fix pm_runtime usage_count counter
spi: spi-zynqmp-gqspi: return -ENOMEM if dma_map_single fails
spi: spi-zynqmp-gqspi: fix use-after-free in zynqmp_qspi_exec_op
spi: spi-zynqmp-gqspi: Resolved slab-out-of-bounds bug
spi: spi-zynqmp-gqspi: fix hang issue when suspend/resume
...
Diffstat (limited to 'drivers/spi/spi-stm32-qspi.c')
-rw-r--r-- | drivers/spi/spi-stm32-qspi.c | 106 |
1 files changed, 84 insertions, 22 deletions
diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 947e6b9dc9f4..7e640ccc7e77 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -269,8 +269,9 @@ static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) if (qspi->fmode == CCR_FMODE_MM) return stm32_qspi_tx_mm(qspi, op); - else if ((op->data.dir == SPI_MEM_DATA_IN && qspi->dma_chrx) || - (op->data.dir == SPI_MEM_DATA_OUT && qspi->dma_chtx)) + else if (((op->data.dir == SPI_MEM_DATA_IN && qspi->dma_chrx) || + (op->data.dir == SPI_MEM_DATA_OUT && qspi->dma_chtx)) && + op->data.nbytes > 4) if (!stm32_qspi_tx_dma(qspi, op)) return 0; @@ -330,7 +331,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) { struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); struct stm32_qspi_flash *flash = &qspi->flash[mem->spi->chip_select]; - u32 ccr, cr, addr_max; + u32 ccr, cr; int timeout, err = 0; dev_dbg(qspi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n", @@ -342,18 +343,6 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) if (err) goto abort; - addr_max = op->addr.val + op->data.nbytes + 1; - - if (op->data.dir == SPI_MEM_DATA_IN) { - if (addr_max < qspi->mm_size && - op->addr.buswidth) - qspi->fmode = CCR_FMODE_MM; - else - qspi->fmode = CCR_FMODE_INDR; - } else { - qspi->fmode = CCR_FMODE_INDW; - } - cr = readl_relaxed(qspi->io_base + QSPI_CR); cr &= ~CR_PRESC_MASK & ~CR_FSEL; cr |= FIELD_PREP(CR_PRESC_MASK, flash->presc); @@ -363,8 +352,6 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) if (op->data.nbytes) writel_relaxed(op->data.nbytes - 1, qspi->io_base + QSPI_DLR); - else - qspi->fmode = CCR_FMODE_INDW; ccr = qspi->fmode; ccr |= FIELD_PREP(CCR_INST_MASK, op->cmd.opcode); @@ -440,6 +427,11 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) } mutex_lock(&qspi->lock); + if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes) + qspi->fmode = CCR_FMODE_INDR; + else + qspi->fmode = CCR_FMODE_INDW; + ret = stm32_qspi_send(mem, op); mutex_unlock(&qspi->lock); @@ -449,6 +441,64 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) return ret; } +static int stm32_qspi_dirmap_create(struct spi_mem_dirmap_desc *desc) +{ + struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->master); + + if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) + return -EOPNOTSUPP; + + /* should never happen, as mm_base == null is an error probe exit condition */ + if (!qspi->mm_base && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) + return -EOPNOTSUPP; + + if (!qspi->mm_size) + return -EOPNOTSUPP; + + return 0; +} + +static ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, void *buf) +{ + struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->master); + struct spi_mem_op op; + u32 addr_max; + int ret; + + ret = pm_runtime_get_sync(qspi->dev); + if (ret < 0) { + pm_runtime_put_noidle(qspi->dev); + return ret; + } + + mutex_lock(&qspi->lock); + /* make a local copy of desc op_tmpl and complete dirmap rdesc + * spi_mem_op template with offs, len and *buf in order to get + * all needed transfer information into struct spi_mem_op + */ + memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op)); + dev_dbg(qspi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); + + op.data.nbytes = len; + op.addr.val = desc->info.offset + offs; + op.data.buf.in = buf; + + addr_max = op.addr.val + op.data.nbytes + 1; + if (addr_max < qspi->mm_size && op.addr.buswidth) + qspi->fmode = CCR_FMODE_MM; + else + qspi->fmode = CCR_FMODE_INDR; + + ret = stm32_qspi_send(desc->mem, &op); + mutex_unlock(&qspi->lock); + + pm_runtime_mark_last_busy(qspi->dev); + pm_runtime_put_autosuspend(qspi->dev); + + return ret ?: len; +} + static int stm32_qspi_setup(struct spi_device *spi) { struct spi_controller *ctrl = spi->master; @@ -554,7 +604,9 @@ static void stm32_qspi_dma_free(struct stm32_qspi *qspi) * to check supported mode. */ static const struct spi_controller_mem_ops stm32_qspi_mem_ops = { - .exec_op = stm32_qspi_exec_op, + .exec_op = stm32_qspi_exec_op, + .dirmap_create = stm32_qspi_dirmap_create, + .dirmap_read = stm32_qspi_dirmap_read, }; static int stm32_qspi_probe(struct platform_device *pdev) @@ -727,21 +779,31 @@ static int __maybe_unused stm32_qspi_suspend(struct device *dev) { pinctrl_pm_select_sleep_state(dev); - return 0; + return pm_runtime_force_suspend(dev); } static int __maybe_unused stm32_qspi_resume(struct device *dev) { struct stm32_qspi *qspi = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret < 0) + return ret; pinctrl_pm_select_default_state(dev); - clk_prepare_enable(qspi->clk); + + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + return ret; + } writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR); - pm_runtime_mark_last_busy(qspi->dev); - pm_runtime_put_autosuspend(qspi->dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; } |