diff options
author | Mark Brown <broonie@kernel.org> | 2016-03-11 14:28:17 +0700 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-03-11 14:28:17 +0700 |
commit | df9633a7805e6208fddd8248603a2543fe997b0a (patch) | |
tree | 811395e55093a425da3c71a9574e8a99d676e271 | |
parent | bad0ae3f3c5cf0eceae5bb1def341efb5b972ce7 (diff) | |
parent | 628269704f19fcfc765499b7158effccfc79b6cf (diff) |
Merge remote-tracking branch 'spi/topic/core' into spi-next
-rw-r--r-- | drivers/spi/spi.c | 48 | ||||
-rw-r--r-- | include/linux/spi/spi.h | 41 |
2 files changed, 89 insertions, 0 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 47eff8012a77..0b2bbf144460 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,13 @@ 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); + + /* Prod the scheduler in case transfer_one() was busy waiting */ + cond_resched(); } /** @@ -2351,6 +2359,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 diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 53be3a4c60cb..ba0dee9d05a3 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -25,6 +25,7 @@ struct dma_chan; struct spi_master; struct spi_transfer; +struct spi_flash_read_message; /* * INTERFACES between SPI master-side drivers and SPI infrastructure. @@ -361,6 +362,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @handle_err: the subsystem calls the driver to handle an error that occurs * in the generic implementation of transfer_one_message(). * @unprepare_message: undo any work done by prepare_message(). + * @spi_flash_read: to support spi-controller hardwares that provide + * accelerated interface to read from flash devices. * @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). @@ -513,6 +516,8 @@ struct spi_master { struct spi_message *message); int (*unprepare_message)(struct spi_master *master, struct spi_message *message); + int (*spi_flash_read)(struct spi_device *spi, + struct spi_flash_read_message *msg); /* * These hooks are for drivers that use a generic implementation @@ -1019,6 +1024,42 @@ static inline ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd) return be16_to_cpu(result); } +/** + * struct spi_flash_read_message - flash specific information for + * spi-masters that provide accelerated flash read interfaces + * @buf: buffer to read data + * @from: offset within the flash from where data is to be read + * @len: length of data to be read + * @retlen: actual length of data read + * @read_opcode: read_opcode to be used to communicate with flash + * @addr_width: number of address bytes + * @dummy_bytes: number of dummy bytes + * @opcode_nbits: number of lines to send opcode + * @addr_nbits: number of lines to send address + * @data_nbits: number of lines for data + */ +struct spi_flash_read_message { + void *buf; + loff_t from; + size_t len; + size_t retlen; + u8 read_opcode; + u8 addr_width; + u8 dummy_bytes; + u8 opcode_nbits; + u8 addr_nbits; + u8 data_nbits; +}; + +/* SPI core interface for flash read support */ +static inline bool spi_flash_read_supported(struct spi_device *spi) +{ + return spi->master->spi_flash_read ? true : false; +} + +int spi_flash_read(struct spi_device *spi, + struct spi_flash_read_message *msg); + /*---------------------------------------------------------------------------*/ /* |