From 556351f14e74db4cd3ddde386457edce7bf0b27f Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Fri, 11 Dec 2015 09:39:56 +0530 Subject: spi: introduce accelerated read support for spi flash devices In addition to providing direct access to SPI bus, some spi controller hardwares (like ti-qspi) provide special port (like memory mapped port) that are optimized to improve SPI flash read performance. This means the controller can automatically send the SPI signals required to read data from the SPI flash device. For this, SPI controller needs to know flash specific information like read command to use, dummy bytes and address width. Introduce spi_flash_read() interface to support accelerated read over SPI flash devices. SPI master drivers can implement this callback to support interfaces such as memory mapped read etc. m25p80 flash driver and other flash drivers can call this make use of such interfaces. The interface should only be used with SPI flashes and cannot be used with other SPI devices. Signed-off-by: Vignesh R Signed-off-by: Mark Brown --- drivers/spi/spi.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 47eff8012a77..dcc6f6e92668 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1152,6 +1152,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) } } + mutex_lock(&master->bus_lock_mutex); trace_spi_message_start(master->cur_msg); if (master->prepare_message) { @@ -1161,6 +1162,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) "failed to prepare message: %d\n", ret); master->cur_msg->status = ret; spi_finalize_current_message(master); + mutex_unlock(&master->bus_lock_mutex); return; } master->cur_msg_prepared = true; @@ -1170,6 +1172,7 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) if (ret) { master->cur_msg->status = ret; spi_finalize_current_message(master); + mutex_unlock(&master->bus_lock_mutex); return; } @@ -1177,8 +1180,10 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) if (ret) { dev_err(&master->dev, "failed to transfer one message from queue\n"); + mutex_unlock(&master->bus_lock_mutex); return; } + mutex_unlock(&master->bus_lock_mutex); } /** @@ -2351,6 +2356,46 @@ int spi_async_locked(struct spi_device *spi, struct spi_message *message) EXPORT_SYMBOL_GPL(spi_async_locked); +int spi_flash_read(struct spi_device *spi, + struct spi_flash_read_message *msg) + +{ + struct spi_master *master = spi->master; + int ret; + + if ((msg->opcode_nbits == SPI_NBITS_DUAL || + msg->addr_nbits == SPI_NBITS_DUAL) && + !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD))) + return -EINVAL; + if ((msg->opcode_nbits == SPI_NBITS_QUAD || + msg->addr_nbits == SPI_NBITS_QUAD) && + !(spi->mode & SPI_TX_QUAD)) + return -EINVAL; + if (msg->data_nbits == SPI_NBITS_DUAL && + !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD))) + return -EINVAL; + if (msg->data_nbits == SPI_NBITS_QUAD && + !(spi->mode & SPI_RX_QUAD)) + return -EINVAL; + + if (master->auto_runtime_pm) { + ret = pm_runtime_get_sync(master->dev.parent); + if (ret < 0) { + dev_err(&master->dev, "Failed to power device: %d\n", + ret); + return ret; + } + } + mutex_lock(&master->bus_lock_mutex); + ret = master->spi_flash_read(spi, msg); + mutex_unlock(&master->bus_lock_mutex); + if (master->auto_runtime_pm) + pm_runtime_put(master->dev.parent); + + return ret; +} +EXPORT_SYMBOL_GPL(spi_flash_read); + /*-------------------------------------------------------------------------*/ /* Utility methods for SPI master protocol drivers, layered on -- cgit v1.2.3 From 628269704f19fcfc765499b7158effccfc79b6cf Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 15 Feb 2016 18:28:02 +0000 Subject: spi: Add cond_resched() in main message processing loop When a controller has only PIO support it is very likely that we will run into use cases where we spend a very large amount of time consuming CPU. Code that does this should call cond_resched() every once in a while to give other tasks more of a chance to run so do that in the main SPI loop, the overhead is negligable if it's not needed. Suggested-by: Arnd Bergmann Signed-off-by: Mark Brown --- drivers/spi/spi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index dcc6f6e92668..0b2bbf144460 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1184,6 +1184,9 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread) return; } mutex_unlock(&master->bus_lock_mutex); + + /* Prod the scheduler in case transfer_one() was busy waiting */ + cond_resched(); } /** -- cgit v1.2.3