123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- From 556351f14e74db4cd3ddde386457edce7bf0b27f Mon Sep 17 00:00:00 2001
- From: Vignesh R <vigneshr@ti.com>
- Date: Fri, 11 Dec 2015 09:39:56 +0530
- Subject: [PATCH] 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 <vigneshr@ti.com>
- Signed-off-by: Mark Brown <broonie@kernel.org>
- ---
- --- a/drivers/spi/spi.c
- +++ b/drivers/spi/spi.c
- @@ -1135,6 +1135,7 @@ static void __spi_pump_messages(struct s
- }
- }
-
- + mutex_lock(&master->bus_lock_mutex);
- trace_spi_message_start(master->cur_msg);
-
- if (master->prepare_message) {
- @@ -1144,6 +1145,7 @@ static void __spi_pump_messages(struct s
- "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;
- @@ -1153,6 +1155,7 @@ static void __spi_pump_messages(struct s
- if (ret) {
- master->cur_msg->status = ret;
- spi_finalize_current_message(master);
- + mutex_unlock(&master->bus_lock_mutex);
- return;
- }
-
- @@ -1160,8 +1163,10 @@ static void __spi_pump_messages(struct s
- 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);
- }
-
- /**
- @@ -2329,6 +2334,46 @@ int spi_async_locked(struct spi_device *
- 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
- --- 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
- * @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).
- @@ -507,6 +510,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
- @@ -999,6 +1004,42 @@ static inline ssize_t spi_w8r16be(struct
- 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);
- +
- /*---------------------------------------------------------------------------*/
-
- /*
|