diff options
author | Daniel Kurtz <djkurtz@chromium.org> | 2016-10-07 06:55:47 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-10-26 07:35:17 -0400 |
commit | 8244bd3ab405a1268223a282b32d28031f7e16fe (patch) | |
tree | e2e100f44d7c548d2bc436612751a1f0b26590e7 /drivers/spi/spi.c | |
parent | 1001354ca34179f3db924eb66672442a173147dc (diff) |
spi: change post transfer udelay() to usleep_range() for long delays
The spi_transfer parameter delay_usecs allows specifying a time to wait
after transferring a spi message. This wait can be quite long - some
devices, such as some Chrome OS ECs, require as much as 2000 usecs after
a SPI transaction, before it can respond.
(cf: arch/arm64/boot/dts/nvidia/tegra132-norrin.dts:
google,cros-ec-spi-msg-delay = <2000>
)
Blocking a CPU for 2 msecs in a busy loop like this doesn't seem very
friendly to other processes, so change the blocking delay to a sleep
to allow other things to use this CPU (or so it can sleep).
This should be safe to do, because:
(a) A post-transaction delay like this is always specified as a minimum
wait time
(b) A delay here is most likely not very time sensitive, as it occurs
after all data has been transferred
(c) This delay occurs in a non-critical section of the spi worker thread
so where it is safe to sleep.
Two caveats:
1) To avoid penalizing short delays, still use udelay for delays < 10us.
2) usleep_range() very often picks the upper bound, an upper bounds 10%
should be plenty.
Signed-off-by: Daniel Kurtz <djkurtz@chromium.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi/spi.c')
-rw-r--r-- | drivers/spi/spi.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5787b723b593..42f3e1cb9212 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -1034,8 +1034,14 @@ static int spi_transfer_one_message(struct spi_master *master, | |||
1034 | if (msg->status != -EINPROGRESS) | 1034 | if (msg->status != -EINPROGRESS) |
1035 | goto out; | 1035 | goto out; |
1036 | 1036 | ||
1037 | if (xfer->delay_usecs) | 1037 | if (xfer->delay_usecs) { |
1038 | udelay(xfer->delay_usecs); | 1038 | u16 us = xfer->delay_usecs; |
1039 | |||
1040 | if (us <= 10) | ||
1041 | udelay(us); | ||
1042 | else | ||
1043 | usleep_range(us, us + DIV_ROUND_UP(us, 10)); | ||
1044 | } | ||
1039 | 1045 | ||
1040 | if (xfer->cs_change) { | 1046 | if (xfer->cs_change) { |
1041 | if (list_is_last(&xfer->transfer_list, | 1047 | if (list_is_last(&xfer->transfer_list, |