Merge remote-tracking branch 'spi/topic/dma' into spi-next
[cascardo/linux.git] / drivers / spi / spi.c
index 47eff80..89158c6 100644 (file)
@@ -702,6 +702,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
                       enum dma_data_direction dir)
 {
        const bool vmalloced_buf = is_vmalloc_addr(buf);
+       unsigned int max_seg_size = dma_get_max_seg_size(dev);
        int desc_len;
        int sgs;
        struct page *vm_page;
@@ -710,10 +711,10 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
        int i, ret;
 
        if (vmalloced_buf) {
-               desc_len = PAGE_SIZE;
+               desc_len = min_t(int, max_seg_size, PAGE_SIZE);
                sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len);
        } else {
-               desc_len = master->max_dma_len;
+               desc_len = min_t(int, max_seg_size, master->max_dma_len);
                sgs = DIV_ROUND_UP(len, desc_len);
        }
 
@@ -739,7 +740,6 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
                        sg_set_buf(&sgt->sgl[i], sg_buf, min);
                }
 
-
                buf += min;
                len -= min;
        }
@@ -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