Merge remote-tracking branches 'spi/topic/lp8841', 'spi/topic/msg', 'spi/topic/pl022...
[cascardo/linux.git] / drivers / spi / spi.c
index c881493..de2f2f9 100644 (file)
@@ -706,6 +706,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;
@@ -714,10 +715,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);
        }
 
@@ -743,7 +744,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;
        }
@@ -1053,6 +1053,7 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
  * __spi_pump_messages - function which processes spi message queue
  * @master: master to process queue for
  * @in_kthread: true if we are in the context of the message pump thread
+ * @bus_locked: true if the bus mutex is held when calling this function
  *
  * This function checks if there is any spi message in the queue that
  * needs processing and if so call out to the driver to initialize hardware
@@ -1062,7 +1063,8 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
  * inside spi_sync(); the queue extraction handling at the top of the
  * function should deal with this safely.
  */
-static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
+static void __spi_pump_messages(struct spi_master *master, bool in_kthread,
+                               bool bus_locked)
 {
        unsigned long flags;
        bool was_busy = false;
@@ -1158,6 +1160,9 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
                }
        }
 
+       if (!bus_locked)
+               mutex_lock(&master->bus_lock_mutex);
+
        trace_spi_message_start(master->cur_msg);
 
        if (master->prepare_message) {
@@ -1167,7 +1172,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);
-                       return;
+                       goto out;
                }
                master->cur_msg_prepared = true;
        }
@@ -1176,15 +1181,23 @@ static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
        if (ret) {
                master->cur_msg->status = ret;
                spi_finalize_current_message(master);
-               return;
+               goto out;
        }
 
        ret = master->transfer_one_message(master, master->cur_msg);
        if (ret) {
                dev_err(&master->dev,
                        "failed to transfer one message from queue\n");
-               return;
+               goto out;
        }
+
+out:
+       if (!bus_locked)
+               mutex_unlock(&master->bus_lock_mutex);
+
+       /* Prod the scheduler in case transfer_one() was busy waiting */
+       if (!ret)
+               cond_resched();
 }
 
 /**
@@ -1196,7 +1209,7 @@ static void spi_pump_messages(struct kthread_work *work)
        struct spi_master *master =
                container_of(work, struct spi_master, pump_messages);
 
-       __spi_pump_messages(master, true);
+       __spi_pump_messages(master, true, false);
 }
 
 static int spi_init_queue(struct spi_master *master)
@@ -1587,13 +1600,30 @@ static void of_register_spi_devices(struct spi_master *master) { }
 static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
 {
        struct spi_device *spi = data;
+       struct spi_master *master = spi->master;
 
        if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
                struct acpi_resource_spi_serialbus *sb;
 
                sb = &ares->data.spi_serial_bus;
                if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) {
-                       spi->chip_select = sb->device_selection;
+                       /*
+                        * ACPI DeviceSelection numbering is handled by the
+                        * host controller driver in Windows and can vary
+                        * from driver to driver. In Linux we always expect
+                        * 0 .. max - 1 so we need to ask the driver to
+                        * translate between the two schemes.
+                        */
+                       if (master->fw_translate_cs) {
+                               int cs = master->fw_translate_cs(master,
+                                               sb->device_selection);
+                               if (cs < 0)
+                                       return cs;
+                               spi->chip_select = cs;
+                       } else {
+                               spi->chip_select = sb->device_selection;
+                       }
+
                        spi->max_speed_hz = sb->connection_speed;
 
                        if (sb->clock_phase == ACPI_SPI_SECOND_PHASE)
@@ -2687,6 +2717,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
@@ -2750,7 +2820,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
                                                       spi_sync_immediate);
                        SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,
                                                       spi_sync_immediate);
-                       __spi_pump_messages(master, false);
+                       __spi_pump_messages(master, false, bus_locked);
                }
 
                wait_for_completion(&done);