Skip to content

Commit fe73245

Browse files
committed
spi: add SPI_MOSI_IDLE_LOW mode bit
Merge series from Boerge Struempfel <boerge.struempfel@gmail.com>: Some spi controller switch the mosi line to high, whenever they are idle. This may not be desired in all use cases. For example neopixel leds can get confused and flicker due to misinterpreting the idle state. Therefore, we introduce a new spi-mode bit, with which the idle behaviour can be overwritten on a per device basis.
2 parents 0bbb363 + b229a7f commit fe73245

4 files changed

Lines changed: 76 additions & 46 deletions

File tree

drivers/spi/spi-imx.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
281281
#define MX51_ECSPI_CONFIG_SCLKPOL(cs) (1 << ((cs & 3) + 4))
282282
#define MX51_ECSPI_CONFIG_SBBCTRL(cs) (1 << ((cs & 3) + 8))
283283
#define MX51_ECSPI_CONFIG_SSBPOL(cs) (1 << ((cs & 3) + 12))
284+
#define MX51_ECSPI_CONFIG_DATACTL(cs) (1 << ((cs & 3) + 16))
284285
#define MX51_ECSPI_CONFIG_SCLKCTL(cs) (1 << ((cs & 3) + 20))
285286

286287
#define MX51_ECSPI_INT 0x10
@@ -573,6 +574,11 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
573574
cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(spi_get_chipselect(spi, 0));
574575
}
575576

577+
if (spi->mode & SPI_MOSI_IDLE_LOW)
578+
cfg |= MX51_ECSPI_CONFIG_DATACTL(spi_get_chipselect(spi, 0));
579+
else
580+
cfg &= ~MX51_ECSPI_CONFIG_DATACTL(spi_get_chipselect(spi, 0));
581+
576582
if (spi->mode & SPI_CS_HIGH)
577583
cfg |= MX51_ECSPI_CONFIG_SSBPOL(spi_get_chipselect(spi, 0));
578584
else
@@ -1743,7 +1749,8 @@ static int spi_imx_probe(struct platform_device *pdev)
17431749
controller->prepare_message = spi_imx_prepare_message;
17441750
controller->unprepare_message = spi_imx_unprepare_message;
17451751
controller->slave_abort = spi_imx_slave_abort;
1746-
controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS;
1752+
controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS |
1753+
SPI_MOSI_IDLE_LOW;
17471754

17481755
if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) ||
17491756
is_imx53_ecspi(spi_imx))

drivers/spi/spidev.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ static_assert(N_SPI_MINORS > 0 && N_SPI_MINORS <= 256);
6464
| SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
6565
| SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \
6666
| SPI_RX_QUAD | SPI_RX_OCTAL \
67-
| SPI_RX_CPHA_FLIP)
67+
| SPI_RX_CPHA_FLIP | SPI_3WIRE_HIZ \
68+
| SPI_MOSI_IDLE_LOW)
6869

6970
struct spidev_data {
7071
dev_t devt;

include/uapi/linux/spi/spi.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#define SPI_RX_OCTAL _BITUL(14) /* receive with 8 wires */
2929
#define SPI_3WIRE_HIZ _BITUL(15) /* high impedance turnaround */
3030
#define SPI_RX_CPHA_FLIP _BITUL(16) /* flip CPHA on Rx only xfer */
31+
#define SPI_MOSI_IDLE_LOW _BITUL(17) /* leave mosi line low when idle */
3132

3233
/*
3334
* All the bits defined above should be covered by SPI_MODE_USER_MASK.
@@ -37,6 +38,6 @@
3738
* These bits must not overlap. A static assert check should make sure of that.
3839
* If adding extra bits, make sure to increase the bit index below as well.
3940
*/
40-
#define SPI_MODE_USER_MASK (_BITUL(17) - 1)
41+
#define SPI_MODE_USER_MASK (_BITUL(18) - 1)
4142

4243
#endif /* _UAPI_SPI_H */

tools/spi/spidev_test.c

Lines changed: 64 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -172,60 +172,72 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
172172

173173
static void print_usage(const char *prog)
174174
{
175-
printf("Usage: %s [-DsbdlHOLC3vpNR24SI]\n", prog);
176-
puts(" -D --device device to use (default /dev/spidev1.1)\n"
177-
" -s --speed max speed (Hz)\n"
178-
" -d --delay delay (usec)\n"
179-
" -b --bpw bits per word\n"
180-
" -i --input input data from a file (e.g. \"test.bin\")\n"
181-
" -o --output output data to a file (e.g. \"results.bin\")\n"
182-
" -l --loop loopback\n"
183-
" -H --cpha clock phase\n"
184-
" -O --cpol clock polarity\n"
185-
" -L --lsb least significant bit first\n"
186-
" -C --cs-high chip select active high\n"
187-
" -3 --3wire SI/SO signals shared\n"
188-
" -v --verbose Verbose (show tx buffer)\n"
189-
" -p Send data (e.g. \"1234\\xde\\xad\")\n"
190-
" -N --no-cs no chip select\n"
191-
" -R --ready slave pulls low to pause\n"
192-
" -2 --dual dual transfer\n"
193-
" -4 --quad quad transfer\n"
194-
" -8 --octal octal transfer\n"
195-
" -S --size transfer size\n"
196-
" -I --iter iterations\n");
175+
printf("Usage: %s [-2348CDFHILMNORSZbdilopsv]\n", prog);
176+
puts("general device settings:\n"
177+
" -D --device device to use (default /dev/spidev1.1)\n"
178+
" -s --speed max speed (Hz)\n"
179+
" -d --delay delay (usec)\n"
180+
" -l --loop loopback\n"
181+
"spi mode:\n"
182+
" -H --cpha clock phase\n"
183+
" -O --cpol clock polarity\n"
184+
" -F --rx-cpha-flip flip CPHA on Rx only xfer\n"
185+
"number of wires for transmission:\n"
186+
" -2 --dual dual transfer\n"
187+
" -4 --quad quad transfer\n"
188+
" -8 --octal octal transfer\n"
189+
" -3 --3wire SI/SO signals shared\n"
190+
" -Z --3wire-hiz high impedance turnaround\n"
191+
"data:\n"
192+
" -i --input input data from a file (e.g. \"test.bin\")\n"
193+
" -o --output output data to a file (e.g. \"results.bin\")\n"
194+
" -p Send data (e.g. \"1234\\xde\\xad\")\n"
195+
" -S --size transfer size\n"
196+
" -I --iter iterations\n"
197+
"additional parameters:\n"
198+
" -b --bpw bits per word\n"
199+
" -L --lsb least significant bit first\n"
200+
" -C --cs-high chip select active high\n"
201+
" -N --no-cs no chip select\n"
202+
" -R --ready slave pulls low to pause\n"
203+
" -M --mosi-idle-low leave mosi line low when idle\n"
204+
"misc:\n"
205+
" -v --verbose Verbose (show tx buffer)\n");
197206
exit(1);
198207
}
199208

200209
static void parse_opts(int argc, char *argv[])
201210
{
202211
while (1) {
203212
static const struct option lopts[] = {
204-
{ "device", 1, 0, 'D' },
205-
{ "speed", 1, 0, 's' },
206-
{ "delay", 1, 0, 'd' },
207-
{ "bpw", 1, 0, 'b' },
208-
{ "input", 1, 0, 'i' },
209-
{ "output", 1, 0, 'o' },
210-
{ "loop", 0, 0, 'l' },
211-
{ "cpha", 0, 0, 'H' },
212-
{ "cpol", 0, 0, 'O' },
213-
{ "lsb", 0, 0, 'L' },
214-
{ "cs-high", 0, 0, 'C' },
215-
{ "3wire", 0, 0, '3' },
216-
{ "no-cs", 0, 0, 'N' },
217-
{ "ready", 0, 0, 'R' },
218-
{ "dual", 0, 0, '2' },
219-
{ "verbose", 0, 0, 'v' },
220-
{ "quad", 0, 0, '4' },
221-
{ "octal", 0, 0, '8' },
222-
{ "size", 1, 0, 'S' },
223-
{ "iter", 1, 0, 'I' },
213+
{ "device", 1, 0, 'D' },
214+
{ "speed", 1, 0, 's' },
215+
{ "delay", 1, 0, 'd' },
216+
{ "loop", 0, 0, 'l' },
217+
{ "cpha", 0, 0, 'H' },
218+
{ "cpol", 0, 0, 'O' },
219+
{ "rx-cpha-flip", 0, 0, 'F' },
220+
{ "dual", 0, 0, '2' },
221+
{ "quad", 0, 0, '4' },
222+
{ "octal", 0, 0, '8' },
223+
{ "3wire", 0, 0, '3' },
224+
{ "3wire-hiz", 0, 0, 'Z' },
225+
{ "input", 1, 0, 'i' },
226+
{ "output", 1, 0, 'o' },
227+
{ "size", 1, 0, 'S' },
228+
{ "iter", 1, 0, 'I' },
229+
{ "bpw", 1, 0, 'b' },
230+
{ "lsb", 0, 0, 'L' },
231+
{ "cs-high", 0, 0, 'C' },
232+
{ "no-cs", 0, 0, 'N' },
233+
{ "ready", 0, 0, 'R' },
234+
{ "mosi-idle-low", 0, 0, 'M' },
235+
{ "verbose", 0, 0, 'v' },
224236
{ NULL, 0, 0, 0 },
225237
};
226238
int c;
227239

228-
c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR248p:vS:I:",
240+
c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3ZFMNR248p:vS:I:",
229241
lopts, NULL);
230242

231243
if (c == -1)
@@ -268,6 +280,15 @@ static void parse_opts(int argc, char *argv[])
268280
case '3':
269281
mode |= SPI_3WIRE;
270282
break;
283+
case 'Z':
284+
mode |= SPI_3WIRE_HIZ;
285+
break;
286+
case 'F':
287+
mode |= SPI_RX_CPHA_FLIP;
288+
break;
289+
case 'M':
290+
mode |= SPI_MOSI_IDLE_LOW;
291+
break;
271292
case 'N':
272293
mode |= SPI_NO_CS;
273294
break;

0 commit comments

Comments
 (0)