|
@@ -526,6 +526,95 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n)
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
+static void spi_set_cs(struct spi_device *spi, bool enable)
|
|
|
+{
|
|
|
+ if (spi->mode & SPI_CS_HIGH)
|
|
|
+ enable = !enable;
|
|
|
+
|
|
|
+ if (spi->cs_gpio >= 0)
|
|
|
+ gpio_set_value(spi->cs_gpio, !enable);
|
|
|
+ else if (spi->master->set_cs)
|
|
|
+ spi->master->set_cs(spi, !enable);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * spi_transfer_one_message - Default implementation of transfer_one_message()
|
|
|
+ *
|
|
|
+ * This is a standard implementation of transfer_one_message() for
|
|
|
+ * drivers which impelment a transfer_one() operation. It provides
|
|
|
+ * standard handling of delays and chip select management.
|
|
|
+ */
|
|
|
+static int spi_transfer_one_message(struct spi_master *master,
|
|
|
+ struct spi_message *msg)
|
|
|
+{
|
|
|
+ struct spi_transfer *xfer;
|
|
|
+ bool cur_cs = true;
|
|
|
+ bool keep_cs = false;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ spi_set_cs(msg->spi, true);
|
|
|
+
|
|
|
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
|
|
+ trace_spi_transfer_start(msg, xfer);
|
|
|
+
|
|
|
+ INIT_COMPLETION(master->xfer_completion);
|
|
|
+
|
|
|
+ ret = master->transfer_one(master, msg->spi, xfer);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(&msg->spi->dev,
|
|
|
+ "SPI transfer failed: %d\n", ret);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ret > 0)
|
|
|
+ wait_for_completion(&master->xfer_completion);
|
|
|
+
|
|
|
+ trace_spi_transfer_stop(msg, xfer);
|
|
|
+
|
|
|
+ if (msg->status != -EINPROGRESS)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ if (xfer->delay_usecs)
|
|
|
+ udelay(xfer->delay_usecs);
|
|
|
+
|
|
|
+ if (xfer->cs_change) {
|
|
|
+ if (list_is_last(&xfer->transfer_list,
|
|
|
+ &msg->transfers)) {
|
|
|
+ keep_cs = true;
|
|
|
+ } else {
|
|
|
+ cur_cs = !cur_cs;
|
|
|
+ spi_set_cs(msg->spi, cur_cs);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ msg->actual_length += xfer->len;
|
|
|
+ }
|
|
|
+
|
|
|
+out:
|
|
|
+ if (ret != 0 || !keep_cs)
|
|
|
+ spi_set_cs(msg->spi, false);
|
|
|
+
|
|
|
+ if (msg->status == -EINPROGRESS)
|
|
|
+ msg->status = ret;
|
|
|
+
|
|
|
+ spi_finalize_current_message(master);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * spi_finalize_current_transfer - report completion of a transfer
|
|
|
+ *
|
|
|
+ * Called by SPI drivers using the core transfer_one_message()
|
|
|
+ * implementation to notify it that the current interrupt driven
|
|
|
+ * transfer has finised and the next one may be scheduled.
|
|
|
+ */
|
|
|
+void spi_finalize_current_transfer(struct spi_master *master)
|
|
|
+{
|
|
|
+ complete(&master->xfer_completion);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
|
|
|
+
|
|
|
/**
|
|
|
* spi_pump_messages - kthread work function which processes spi message queue
|
|
|
* @work: pointer to kthread work struct contained in the master struct
|
|
@@ -836,6 +925,8 @@ static int spi_master_initialize_queue(struct spi_master *master)
|
|
|
|
|
|
master->queued = true;
|
|
|
master->transfer = spi_queued_transfer;
|
|
|
+ if (!master->transfer_one_message)
|
|
|
+ master->transfer_one_message = spi_transfer_one_message;
|
|
|
|
|
|
/* Initialize and start queue */
|
|
|
ret = spi_init_queue(master);
|
|
@@ -1242,6 +1333,7 @@ int spi_register_master(struct spi_master *master)
|
|
|
spin_lock_init(&master->bus_lock_spinlock);
|
|
|
mutex_init(&master->bus_lock_mutex);
|
|
|
master->bus_lock_flag = 0;
|
|
|
+ init_completion(&master->xfer_completion);
|
|
|
|
|
|
/* register the device, then userspace will see it.
|
|
|
* registration fails if the bus ID is in use.
|