diff options
author | Martin Sperl <kernel@martin.sperl.org> | 2019-02-23 03:49:48 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-05-08 05:28:51 -0400 |
commit | 0ff2de8bb163551ec4230a5a6f3c40c1f6adec4f (patch) | |
tree | e144d1f35586e40c4048cf982a63eeff126186ba | |
parent | 154f7da56f1ecba42021d550c9e8432ac8d32c26 (diff) |
spi: core: allow defining time that cs is deasserted
For some SPI devices that support speed_hz > 1MHz the default 10 us delay
when cs_change = 1 is typically way to long and may result in poor spi bus
utilization.
This patch makes it possible to control the delay at micro or nano second
resolution on a per spi_transfer basis. It even allows an "as fast as
possible" mode with:
xfer.cs_change_delay_unit = SPI_DELAY_UNIT_NSECS;
xfer.cs_change_delay = 0;
The delay code is shared between delay_usecs and cs_change_delay for
consistency and reuse, so in the future this change_delay_unit could also
apply to delay_usec as well.
Note that on slower SOCs/CPU actually reaching ns deasserts on cs is not
realistic as the gpio overhead alone (without any delays added ) may
already leave cs deasserted for more than 1us - at least on a raspberry pi.
But at the very least this way we can keep it as short as possible.
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | drivers/spi/spi.c | 59 | ||||
-rw-r--r-- | include/linux/spi/spi.h | 7 |
2 files changed, 56 insertions, 10 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5e75944ad5d1..7e8ffe3fdc00 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -1090,6 +1090,52 @@ static int spi_transfer_wait(struct spi_controller *ctlr, | |||
1090 | return 0; | 1090 | return 0; |
1091 | } | 1091 | } |
1092 | 1092 | ||
1093 | static void _spi_transfer_delay_ns(u32 ns) | ||
1094 | { | ||
1095 | if (!ns) | ||
1096 | return; | ||
1097 | if (ns <= 1000) { | ||
1098 | ndelay(ns); | ||
1099 | } else { | ||
1100 | u32 us = DIV_ROUND_UP(ns, 1000); | ||
1101 | |||
1102 | if (us <= 10) | ||
1103 | udelay(us); | ||
1104 | else | ||
1105 | usleep_range(us, us + DIV_ROUND_UP(us, 10)); | ||
1106 | } | ||
1107 | } | ||
1108 | |||
1109 | static void _spi_transfer_cs_change_delay(struct spi_message *msg, | ||
1110 | struct spi_transfer *xfer) | ||
1111 | { | ||
1112 | u32 delay = xfer->cs_change_delay; | ||
1113 | u32 unit = xfer->cs_change_delay_unit; | ||
1114 | |||
1115 | /* return early on "fast" mode - for everything but USECS */ | ||
1116 | if (!delay && unit != SPI_DELAY_UNIT_USECS) | ||
1117 | return; | ||
1118 | |||
1119 | switch (unit) { | ||
1120 | case SPI_DELAY_UNIT_USECS: | ||
1121 | /* for compatibility use default of 10us */ | ||
1122 | if (!delay) | ||
1123 | delay = 10000; | ||
1124 | else | ||
1125 | delay *= 1000; | ||
1126 | break; | ||
1127 | case SPI_DELAY_UNIT_NSECS: /* nothing to do here */ | ||
1128 | break; | ||
1129 | default: | ||
1130 | dev_err_once(&msg->spi->dev, | ||
1131 | "Use of unsupported delay unit %i, using default of 10us\n", | ||
1132 | xfer->cs_change_delay_unit); | ||
1133 | delay = 10000; | ||
1134 | } | ||
1135 | /* now sleep for the requested amount of time */ | ||
1136 | _spi_transfer_delay_ns(delay); | ||
1137 | } | ||
1138 | |||
1093 | /* | 1139 | /* |
1094 | * spi_transfer_one_message - Default implementation of transfer_one_message() | 1140 | * spi_transfer_one_message - Default implementation of transfer_one_message() |
1095 | * | 1141 | * |
@@ -1148,14 +1194,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, | |||
1148 | if (msg->status != -EINPROGRESS) | 1194 | if (msg->status != -EINPROGRESS) |
1149 | goto out; | 1195 | goto out; |
1150 | 1196 | ||
1151 | if (xfer->delay_usecs) { | 1197 | if (xfer->delay_usecs) |
1152 | u16 us = xfer->delay_usecs; | 1198 | _spi_transfer_delay_ns(xfer->delay_usecs * 1000); |
1153 | |||
1154 | if (us <= 10) | ||
1155 | udelay(us); | ||
1156 | else | ||
1157 | usleep_range(us, us + DIV_ROUND_UP(us, 10)); | ||
1158 | } | ||
1159 | 1199 | ||
1160 | if (xfer->cs_change) { | 1200 | if (xfer->cs_change) { |
1161 | if (list_is_last(&xfer->transfer_list, | 1201 | if (list_is_last(&xfer->transfer_list, |
@@ -1163,7 +1203,7 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, | |||
1163 | keep_cs = true; | 1203 | keep_cs = true; |
1164 | } else { | 1204 | } else { |
1165 | spi_set_cs(msg->spi, false); | 1205 | spi_set_cs(msg->spi, false); |
1166 | udelay(10); | 1206 | _spi_transfer_cs_change_delay(msg, xfer); |
1167 | spi_set_cs(msg->spi, true); | 1207 | spi_set_cs(msg->spi, true); |
1168 | } | 1208 | } |
1169 | } | 1209 | } |
@@ -3757,4 +3797,3 @@ err0: | |||
3757 | * include needing to have boardinfo data structures be much more public. | 3797 | * include needing to have boardinfo data structures be much more public. |
3758 | */ | 3798 | */ |
3759 | postcore_initcall(spi_init); | 3799 | postcore_initcall(spi_init); |
3760 | |||
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 053abd22ad31..023beb9e9e4b 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h | |||
@@ -735,6 +735,9 @@ extern void spi_res_release(struct spi_controller *ctlr, | |||
735 | * @bits_per_word: select a bits_per_word other than the device default | 735 | * @bits_per_word: select a bits_per_word other than the device default |
736 | * for this transfer. If 0 the default (from @spi_device) is used. | 736 | * for this transfer. If 0 the default (from @spi_device) is used. |
737 | * @cs_change: affects chipselect after this transfer completes | 737 | * @cs_change: affects chipselect after this transfer completes |
738 | * @cs_change_delay: delay between cs deassert and assert when | ||
739 | * @cs_change is set and @spi_transfer is not the last in @spi_message | ||
740 | * @cs_change_delay_unit: unit of cs_change_delay | ||
738 | * @delay_usecs: microseconds to delay after this transfer before | 741 | * @delay_usecs: microseconds to delay after this transfer before |
739 | * (optionally) changing the chipselect status, then starting | 742 | * (optionally) changing the chipselect status, then starting |
740 | * the next transfer or completing this @spi_message. | 743 | * the next transfer or completing this @spi_message. |
@@ -824,6 +827,10 @@ struct spi_transfer { | |||
824 | u8 bits_per_word; | 827 | u8 bits_per_word; |
825 | u8 word_delay_usecs; | 828 | u8 word_delay_usecs; |
826 | u16 delay_usecs; | 829 | u16 delay_usecs; |
830 | u16 cs_change_delay; | ||
831 | u8 cs_change_delay_unit; | ||
832 | #define SPI_DELAY_UNIT_USECS 0 | ||
833 | #define SPI_DELAY_UNIT_NSECS 1 | ||
827 | u32 speed_hz; | 834 | u32 speed_hz; |
828 | u16 word_delay; | 835 | u16 word_delay; |
829 | 836 | ||