Merge branch 'spi-5.5' into spi-next
[linux-2.6-microblaze.git] / drivers / spi / spi.c
index 26b91ee..5e4c453 100644 (file)
@@ -92,7 +92,7 @@ static ssize_t driver_override_store(struct device *dev,
        if (len) {
                spi->driver_override = driver_override;
        } else {
-               /* Emptry string, disable driver override */
+               /* Empty string, disable driver override */
                spi->driver_override = NULL;
                kfree(driver_override);
        }
@@ -469,7 +469,7 @@ static LIST_HEAD(board_list);
 static LIST_HEAD(spi_controller_list);
 
 /*
- * Used to protect add/del opertion for board_info list and
+ * Used to protect add/del operation for board_info list and
  * spi_controller list, and their matching process
  * also used to protect object of type struct idr
  */
@@ -775,6 +775,15 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n)
 
 static void spi_set_cs(struct spi_device *spi, bool enable)
 {
+       bool enable1 = enable;
+
+       if (!spi->controller->set_cs_timing) {
+               if (enable1)
+                       spi_delay_exec(&spi->controller->cs_setup, NULL);
+               else
+                       spi_delay_exec(&spi->controller->cs_hold, NULL);
+       }
+
        if (spi->mode & SPI_CS_HIGH)
                enable = !enable;
 
@@ -800,6 +809,11 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
        } else if (spi->controller->set_cs) {
                spi->controller->set_cs(spi, !enable);
        }
+
+       if (!spi->controller->set_cs_timing) {
+               if (!enable1)
+                       spi_delay_exec(&spi->controller->cs_inactive, NULL);
+       }
 }
 
 #ifdef CONFIG_HAS_DMA
@@ -1106,42 +1120,79 @@ static void _spi_transfer_delay_ns(u32 ns)
        }
 }
 
-static void _spi_transfer_cs_change_delay(struct spi_message *msg,
-                                         struct spi_transfer *xfer)
+int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer)
 {
-       u32 delay = xfer->cs_change_delay;
-       u32 unit = xfer->cs_change_delay_unit;
+       u32 delay = _delay->value;
+       u32 unit = _delay->unit;
        u32 hz;
 
-       /* return early on "fast" mode - for everything but USECS */
-       if (!delay && unit != SPI_DELAY_UNIT_USECS)
-               return;
+       if (!delay)
+               return 0;
 
        switch (unit) {
        case SPI_DELAY_UNIT_USECS:
-               /* for compatibility use default of 10us */
-               if (!delay)
-                       delay = 10000;
-               else
-                       delay *= 1000;
+               delay *= 1000;
                break;
        case SPI_DELAY_UNIT_NSECS: /* nothing to do here */
                break;
        case SPI_DELAY_UNIT_SCK:
+               /* clock cycles need to be obtained from spi_transfer */
+               if (!xfer)
+                       return -EINVAL;
                /* if there is no effective speed know, then approximate
                 * by underestimating with half the requested hz
                 */
                hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2;
+               if (!hz)
+                       return -EINVAL;
                delay *= DIV_ROUND_UP(1000000000, hz);
                break;
        default:
+               return -EINVAL;
+       }
+
+       return delay;
+}
+EXPORT_SYMBOL_GPL(spi_delay_to_ns);
+
+int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer)
+{
+       int delay;
+
+       if (!_delay)
+               return -EINVAL;
+
+       delay = spi_delay_to_ns(_delay, xfer);
+       if (delay < 0)
+               return delay;
+
+       _spi_transfer_delay_ns(delay);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(spi_delay_exec);
+
+static void _spi_transfer_cs_change_delay(struct spi_message *msg,
+                                         struct spi_transfer *xfer)
+{
+       u32 delay = xfer->cs_change_delay.value;
+       u32 unit = xfer->cs_change_delay.unit;
+       int ret;
+
+       /* return early on "fast" mode - for everything but USECS */
+       if (!delay) {
+               if (unit == SPI_DELAY_UNIT_USECS)
+                       _spi_transfer_delay_ns(10000);
+               return;
+       }
+
+       ret = spi_delay_exec(&xfer->cs_change_delay, xfer);
+       if (ret) {
                dev_err_once(&msg->spi->dev,
                             "Use of unsupported delay unit %i, using default of 10us\n",
-                            xfer->cs_change_delay_unit);
-               delay = 10000;
+                            unit);
+               _spi_transfer_delay_ns(10000);
        }
-       /* now sleep for the requested amount of time */
-       _spi_transfer_delay_ns(delay);
 }
 
 /*
@@ -1171,6 +1222,11 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
                spi_statistics_add_transfer_stats(statm, xfer, ctlr);
                spi_statistics_add_transfer_stats(stats, xfer, ctlr);
 
+               if (!ctlr->ptp_sts_supported) {
+                       xfer->ptp_sts_word_pre = 0;
+                       ptp_read_system_prets(xfer->ptp_sts);
+               }
+
                if (xfer->tx_buf || xfer->rx_buf) {
                        reinit_completion(&ctlr->xfer_completion);
 
@@ -1197,13 +1253,17 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
                                        xfer->len);
                }
 
+               if (!ctlr->ptp_sts_supported) {
+                       ptp_read_system_postts(xfer->ptp_sts);
+                       xfer->ptp_sts_word_post = xfer->len;
+               }
+
                trace_spi_transfer_stop(msg, xfer);
 
                if (msg->status != -EINPROGRESS)
                        goto out;
 
-               if (xfer->delay_usecs)
-                       _spi_transfer_delay_ns(xfer->delay_usecs * 1000);
+               spi_transfer_delay_exec(xfer);
 
                if (xfer->cs_change) {
                        if (list_is_last(&xfer->transfer_list,
@@ -1265,6 +1325,7 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
  */
 static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
 {
+       struct spi_transfer *xfer;
        struct spi_message *msg;
        bool was_busy = false;
        unsigned long flags;
@@ -1391,6 +1452,13 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
                goto out;
        }
 
+       if (!ctlr->ptp_sts_supported && !ctlr->transfer_one) {
+               list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+                       xfer->ptp_sts_word_pre = 0;
+                       ptp_read_system_prets(xfer->ptp_sts);
+               }
+       }
+
        ret = ctlr->transfer_one_message(ctlr, msg);
        if (ret) {
                dev_err(&ctlr->dev,
@@ -1418,6 +1486,99 @@ static void spi_pump_messages(struct kthread_work *work)
        __spi_pump_messages(ctlr, true);
 }
 
+/**
+ * spi_take_timestamp_pre - helper for drivers to collect the beginning of the
+ *                         TX timestamp for the requested byte from the SPI
+ *                         transfer. The frequency with which this function
+ *                         must be called (once per word, once for the whole
+ *                         transfer, once per batch of words etc) is arbitrary
+ *                         as long as the @tx buffer offset is greater than or
+ *                         equal to the requested byte at the time of the
+ *                         call. The timestamp is only taken once, at the
+ *                         first such call. It is assumed that the driver
+ *                         advances its @tx buffer pointer monotonically.
+ * @ctlr: Pointer to the spi_controller structure of the driver
+ * @xfer: Pointer to the transfer being timestamped
+ * @tx: Pointer to the current word within the xfer->tx_buf that the driver is
+ *     preparing to transmit right now.
+ * @irqs_off: If true, will disable IRQs and preemption for the duration of the
+ *           transfer, for less jitter in time measurement. Only compatible
+ *           with PIO drivers. If true, must follow up with
+ *           spi_take_timestamp_post or otherwise system will crash.
+ *           WARNING: for fully predictable results, the CPU frequency must
+ *           also be under control (governor).
+ */
+void spi_take_timestamp_pre(struct spi_controller *ctlr,
+                           struct spi_transfer *xfer,
+                           const void *tx, bool irqs_off)
+{
+       u8 bytes_per_word = DIV_ROUND_UP(xfer->bits_per_word, 8);
+
+       if (!xfer->ptp_sts)
+               return;
+
+       if (xfer->timestamped_pre)
+               return;
+
+       if (tx < (xfer->tx_buf + xfer->ptp_sts_word_pre * bytes_per_word))
+               return;
+
+       /* Capture the resolution of the timestamp */
+       xfer->ptp_sts_word_pre = (tx - xfer->tx_buf) / bytes_per_word;
+
+       xfer->timestamped_pre = true;
+
+       if (irqs_off) {
+               local_irq_save(ctlr->irq_flags);
+               preempt_disable();
+       }
+
+       ptp_read_system_prets(xfer->ptp_sts);
+}
+EXPORT_SYMBOL_GPL(spi_take_timestamp_pre);
+
+/**
+ * spi_take_timestamp_post - helper for drivers to collect the end of the
+ *                          TX timestamp for the requested byte from the SPI
+ *                          transfer. Can be called with an arbitrary
+ *                          frequency: only the first call where @tx exceeds
+ *                          or is equal to the requested word will be
+ *                          timestamped.
+ * @ctlr: Pointer to the spi_controller structure of the driver
+ * @xfer: Pointer to the transfer being timestamped
+ * @tx: Pointer to the current word within the xfer->tx_buf that the driver has
+ *     just transmitted.
+ * @irqs_off: If true, will re-enable IRQs and preemption for the local CPU.
+ */
+void spi_take_timestamp_post(struct spi_controller *ctlr,
+                            struct spi_transfer *xfer,
+                            const void *tx, bool irqs_off)
+{
+       u8 bytes_per_word = DIV_ROUND_UP(xfer->bits_per_word, 8);
+
+       if (!xfer->ptp_sts)
+               return;
+
+       if (xfer->timestamped_post)
+               return;
+
+       if (tx < (xfer->tx_buf + xfer->ptp_sts_word_post * bytes_per_word))
+               return;
+
+       ptp_read_system_postts(xfer->ptp_sts);
+
+       if (irqs_off) {
+               local_irq_restore(ctlr->irq_flags);
+               preempt_enable();
+       }
+
+       /* Capture the resolution of the timestamp */
+       xfer->ptp_sts_word_post = (tx - xfer->tx_buf) / bytes_per_word;
+
+       xfer->timestamped_post = true;
+}
+EXPORT_SYMBOL_GPL(spi_take_timestamp_post);
+
 /**
  * spi_set_thread_rt - set the controller to pump at realtime priority
  * @ctlr: controller to boost priority of
@@ -1503,6 +1664,7 @@ EXPORT_SYMBOL_GPL(spi_get_next_queued_message);
  */
 void spi_finalize_current_message(struct spi_controller *ctlr)
 {
+       struct spi_transfer *xfer;
        struct spi_message *mesg;
        unsigned long flags;
        int ret;
@@ -1511,6 +1673,13 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
        mesg = ctlr->cur_msg;
        spin_unlock_irqrestore(&ctlr->queue_lock, flags);
 
+       if (!ctlr->ptp_sts_supported && !ctlr->transfer_one) {
+               list_for_each_entry(xfer, &mesg->transfers, transfer_list) {
+                       ptp_read_system_postts(xfer->ptp_sts);
+                       xfer->ptp_sts_word_post = xfer->len;
+               }
+       }
+
        spi_unmap_msg(ctlr, mesg);
 
        if (ctlr->cur_msg_prepared && ctlr->unprepare_message) {
@@ -2872,10 +3041,11 @@ struct spi_replaced_transfers *spi_replace_transfers(
                /* add to list */
                list_add(&xfer->transfer_list, rxfer->replaced_after);
 
-               /* clear cs_change and delay_usecs for all but the last */
+               /* clear cs_change and delay for all but the last */
                if (i) {
                        xfer->cs_change = false;
                        xfer->delay_usecs = 0;
+                       xfer->delay.value = 0;
                }
        }
 
@@ -3092,7 +3262,29 @@ int spi_setup(struct spi_device *spi)
        if (spi->controller->setup)
                status = spi->controller->setup(spi);
 
-       spi_set_cs(spi, false);
+       if (spi->controller->auto_runtime_pm && spi->controller->set_cs) {
+               status = pm_runtime_get_sync(spi->controller->dev.parent);
+               if (status < 0) {
+                       pm_runtime_put_noidle(spi->controller->dev.parent);
+                       dev_err(&spi->controller->dev, "Failed to power device: %d\n",
+                               status);
+                       return status;
+               }
+
+               /*
+                * We do not want to return positive value from pm_runtime_get,
+                * there are many instances of devices calling spi_setup() and
+                * checking for a non-zero return value instead of a negative
+                * return value.
+                */
+               status = 0;
+
+               spi_set_cs(spi, false);
+               pm_runtime_mark_last_busy(spi->controller->dev.parent);
+               pm_runtime_put_autosuspend(spi->controller->dev.parent);
+       } else {
+               spi_set_cs(spi, false);
+       }
 
        if (spi->rt && !spi->controller->rt) {
                spi->controller->rt = true;
@@ -3115,18 +3307,71 @@ EXPORT_SYMBOL_GPL(spi_setup);
 /**
  * spi_set_cs_timing - configure CS setup, hold, and inactive delays
  * @spi: the device that requires specific CS timing configuration
- * @setup: CS setup time in terms of clock count
- * @hold: CS hold time in terms of clock count
- * @inactive_dly: CS inactive delay between transfers in terms of clock count
+ * @setup: CS setup time specified via @spi_delay
+ * @hold: CS hold time specified via @spi_delay
+ * @inactive: CS inactive delay between transfers specified via @spi_delay
+ *
+ * Return: zero on success, else a negative error code.
  */
-void spi_set_cs_timing(struct spi_device *spi, u8 setup, u8 hold,
-                      u8 inactive_dly)
+int spi_set_cs_timing(struct spi_device *spi, struct spi_delay *setup,
+                     struct spi_delay *hold, struct spi_delay *inactive)
 {
+       size_t len;
+
        if (spi->controller->set_cs_timing)
-               spi->controller->set_cs_timing(spi, setup, hold, inactive_dly);
+               return spi->controller->set_cs_timing(spi, setup, hold,
+                                                     inactive);
+
+       if ((setup && setup->unit == SPI_DELAY_UNIT_SCK) ||
+           (hold && hold->unit == SPI_DELAY_UNIT_SCK) ||
+           (inactive && inactive->unit == SPI_DELAY_UNIT_SCK)) {
+               dev_err(&spi->dev,
+                       "Clock-cycle delays for CS not supported in SW mode\n");
+               return -ENOTSUPP;
+       }
+
+       len = sizeof(struct spi_delay);
+
+       /* copy delays to controller */
+       if (setup)
+               memcpy(&spi->controller->cs_setup, setup, len);
+       else
+               memset(&spi->controller->cs_setup, 0, len);
+
+       if (hold)
+               memcpy(&spi->controller->cs_hold, hold, len);
+       else
+               memset(&spi->controller->cs_hold, 0, len);
+
+       if (inactive)
+               memcpy(&spi->controller->cs_inactive, inactive, len);
+       else
+               memset(&spi->controller->cs_inactive, 0, len);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(spi_set_cs_timing);
 
+static int _spi_xfer_word_delay_update(struct spi_transfer *xfer,
+                                      struct spi_device *spi)
+{
+       int delay1, delay2;
+
+       delay1 = spi_delay_to_ns(&xfer->word_delay, xfer);
+       if (delay1 < 0)
+               return delay1;
+
+       delay2 = spi_delay_to_ns(&spi->word_delay, xfer);
+       if (delay2 < 0)
+               return delay2;
+
+       if (delay1 < delay2)
+               memcpy(&xfer->word_delay, &spi->word_delay,
+                      sizeof(xfer->word_delay));
+
+       return 0;
+}
+
 static int __spi_validate(struct spi_device *spi, struct spi_message *message)
 {
        struct spi_controller *ctlr = spi->controller;
@@ -3262,8 +3507,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
                                return -EINVAL;
                }
 
-               if (xfer->word_delay_usecs < spi->word_delay_usecs)
-                       xfer->word_delay_usecs = spi->word_delay_usecs;
+               if (_spi_xfer_word_delay_update(xfer, spi))
+                       return -EINVAL;
        }
 
        message->status = -EINPROGRESS;
@@ -3274,6 +3519,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
 static int __spi_async(struct spi_device *spi, struct spi_message *message)
 {
        struct spi_controller *ctlr = spi->controller;
+       struct spi_transfer *xfer;
 
        /*
         * Some controllers do not support doing regular SPI transfers. Return
@@ -3289,6 +3535,13 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
 
        trace_spi_message_submit(message);
 
+       if (!ctlr->ptp_sts_supported) {
+               list_for_each_entry(xfer, &message->transfers, transfer_list) {
+                       xfer->ptp_sts_word_pre = 0;
+                       ptp_read_system_prets(xfer->ptp_sts);
+               }
+       }
+
        return ctlr->transfer(spi, message);
 }