aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Sperl <kernel@martin.sperl.org>2019-02-23 03:49:48 -0500
committerMark Brown <broonie@kernel.org>2019-05-08 05:28:51 -0400
commit0ff2de8bb163551ec4230a5a6f3c40c1f6adec4f (patch)
treee144d1f35586e40c4048cf982a63eeff126186ba
parent154f7da56f1ecba42021d550c9e8432ac8d32c26 (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.c59
-rw-r--r--include/linux/spi/spi.h7
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
1093static 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
1109static 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 */
3759postcore_initcall(spi_init); 3799postcore_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