Commit fe732455 authored by Mark Brown's avatar Mark Brown

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.
parents 0bbb363f b229a7f5
...@@ -281,6 +281,7 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device ...@@ -281,6 +281,7 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
#define MX51_ECSPI_CONFIG_SCLKPOL(cs) (1 << ((cs & 3) + 4)) #define MX51_ECSPI_CONFIG_SCLKPOL(cs) (1 << ((cs & 3) + 4))
#define MX51_ECSPI_CONFIG_SBBCTRL(cs) (1 << ((cs & 3) + 8)) #define MX51_ECSPI_CONFIG_SBBCTRL(cs) (1 << ((cs & 3) + 8))
#define MX51_ECSPI_CONFIG_SSBPOL(cs) (1 << ((cs & 3) + 12)) #define MX51_ECSPI_CONFIG_SSBPOL(cs) (1 << ((cs & 3) + 12))
#define MX51_ECSPI_CONFIG_DATACTL(cs) (1 << ((cs & 3) + 16))
#define MX51_ECSPI_CONFIG_SCLKCTL(cs) (1 << ((cs & 3) + 20)) #define MX51_ECSPI_CONFIG_SCLKCTL(cs) (1 << ((cs & 3) + 20))
#define MX51_ECSPI_INT 0x10 #define MX51_ECSPI_INT 0x10
...@@ -573,6 +574,11 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx, ...@@ -573,6 +574,11 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(spi_get_chipselect(spi, 0)); cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(spi_get_chipselect(spi, 0));
} }
if (spi->mode & SPI_MOSI_IDLE_LOW)
cfg |= MX51_ECSPI_CONFIG_DATACTL(spi_get_chipselect(spi, 0));
else
cfg &= ~MX51_ECSPI_CONFIG_DATACTL(spi_get_chipselect(spi, 0));
if (spi->mode & SPI_CS_HIGH) if (spi->mode & SPI_CS_HIGH)
cfg |= MX51_ECSPI_CONFIG_SSBPOL(spi_get_chipselect(spi, 0)); cfg |= MX51_ECSPI_CONFIG_SSBPOL(spi_get_chipselect(spi, 0));
else else
...@@ -1743,7 +1749,8 @@ static int spi_imx_probe(struct platform_device *pdev) ...@@ -1743,7 +1749,8 @@ static int spi_imx_probe(struct platform_device *pdev)
controller->prepare_message = spi_imx_prepare_message; controller->prepare_message = spi_imx_prepare_message;
controller->unprepare_message = spi_imx_unprepare_message; controller->unprepare_message = spi_imx_unprepare_message;
controller->slave_abort = spi_imx_slave_abort; controller->slave_abort = spi_imx_slave_abort;
controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS; controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS |
SPI_MOSI_IDLE_LOW;
if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) || if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) ||
is_imx53_ecspi(spi_imx)) is_imx53_ecspi(spi_imx))
......
...@@ -64,7 +64,8 @@ static_assert(N_SPI_MINORS > 0 && N_SPI_MINORS <= 256); ...@@ -64,7 +64,8 @@ static_assert(N_SPI_MINORS > 0 && N_SPI_MINORS <= 256);
| SPI_NO_CS | SPI_READY | SPI_TX_DUAL \ | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
| SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \ | SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \
| SPI_RX_QUAD | SPI_RX_OCTAL \ | SPI_RX_QUAD | SPI_RX_OCTAL \
| SPI_RX_CPHA_FLIP) | SPI_RX_CPHA_FLIP | SPI_3WIRE_HIZ \
| SPI_MOSI_IDLE_LOW)
struct spidev_data { struct spidev_data {
dev_t devt; dev_t devt;
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#define SPI_RX_OCTAL _BITUL(14) /* receive with 8 wires */ #define SPI_RX_OCTAL _BITUL(14) /* receive with 8 wires */
#define SPI_3WIRE_HIZ _BITUL(15) /* high impedance turnaround */ #define SPI_3WIRE_HIZ _BITUL(15) /* high impedance turnaround */
#define SPI_RX_CPHA_FLIP _BITUL(16) /* flip CPHA on Rx only xfer */ #define SPI_RX_CPHA_FLIP _BITUL(16) /* flip CPHA on Rx only xfer */
#define SPI_MOSI_IDLE_LOW _BITUL(17) /* leave mosi line low when idle */
/* /*
* All the bits defined above should be covered by SPI_MODE_USER_MASK. * All the bits defined above should be covered by SPI_MODE_USER_MASK.
...@@ -37,6 +38,6 @@ ...@@ -37,6 +38,6 @@
* These bits must not overlap. A static assert check should make sure of that. * These bits must not overlap. A static assert check should make sure of that.
* If adding extra bits, make sure to increase the bit index below as well. * If adding extra bits, make sure to increase the bit index below as well.
*/ */
#define SPI_MODE_USER_MASK (_BITUL(17) - 1) #define SPI_MODE_USER_MASK (_BITUL(18) - 1)
#endif /* _UAPI_SPI_H */ #endif /* _UAPI_SPI_H */
...@@ -172,28 +172,37 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) ...@@ -172,28 +172,37 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
static void print_usage(const char *prog) static void print_usage(const char *prog)
{ {
printf("Usage: %s [-DsbdlHOLC3vpNR24SI]\n", prog); printf("Usage: %s [-2348CDFHILMNORSZbdilopsv]\n", prog);
puts(" -D --device device to use (default /dev/spidev1.1)\n" puts("general device settings:\n"
" -s --speed max speed (Hz)\n" " -D --device device to use (default /dev/spidev1.1)\n"
" -d --delay delay (usec)\n" " -s --speed max speed (Hz)\n"
" -b --bpw bits per word\n" " -d --delay delay (usec)\n"
" -i --input input data from a file (e.g. \"test.bin\")\n" " -l --loop loopback\n"
" -o --output output data to a file (e.g. \"results.bin\")\n" "spi mode:\n"
" -l --loop loopback\n" " -H --cpha clock phase\n"
" -H --cpha clock phase\n" " -O --cpol clock polarity\n"
" -O --cpol clock polarity\n" " -F --rx-cpha-flip flip CPHA on Rx only xfer\n"
" -L --lsb least significant bit first\n" "number of wires for transmission:\n"
" -C --cs-high chip select active high\n" " -2 --dual dual transfer\n"
" -3 --3wire SI/SO signals shared\n" " -4 --quad quad transfer\n"
" -v --verbose Verbose (show tx buffer)\n" " -8 --octal octal transfer\n"
" -p Send data (e.g. \"1234\\xde\\xad\")\n" " -3 --3wire SI/SO signals shared\n"
" -N --no-cs no chip select\n" " -Z --3wire-hiz high impedance turnaround\n"
" -R --ready slave pulls low to pause\n" "data:\n"
" -2 --dual dual transfer\n" " -i --input input data from a file (e.g. \"test.bin\")\n"
" -4 --quad quad transfer\n" " -o --output output data to a file (e.g. \"results.bin\")\n"
" -8 --octal octal transfer\n" " -p Send data (e.g. \"1234\\xde\\xad\")\n"
" -S --size transfer size\n" " -S --size transfer size\n"
" -I --iter iterations\n"); " -I --iter iterations\n"
"additional parameters:\n"
" -b --bpw bits per word\n"
" -L --lsb least significant bit first\n"
" -C --cs-high chip select active high\n"
" -N --no-cs no chip select\n"
" -R --ready slave pulls low to pause\n"
" -M --mosi-idle-low leave mosi line low when idle\n"
"misc:\n"
" -v --verbose Verbose (show tx buffer)\n");
exit(1); exit(1);
} }
...@@ -201,31 +210,34 @@ static void parse_opts(int argc, char *argv[]) ...@@ -201,31 +210,34 @@ static void parse_opts(int argc, char *argv[])
{ {
while (1) { while (1) {
static const struct option lopts[] = { static const struct option lopts[] = {
{ "device", 1, 0, 'D' }, { "device", 1, 0, 'D' },
{ "speed", 1, 0, 's' }, { "speed", 1, 0, 's' },
{ "delay", 1, 0, 'd' }, { "delay", 1, 0, 'd' },
{ "bpw", 1, 0, 'b' }, { "loop", 0, 0, 'l' },
{ "input", 1, 0, 'i' }, { "cpha", 0, 0, 'H' },
{ "output", 1, 0, 'o' }, { "cpol", 0, 0, 'O' },
{ "loop", 0, 0, 'l' }, { "rx-cpha-flip", 0, 0, 'F' },
{ "cpha", 0, 0, 'H' }, { "dual", 0, 0, '2' },
{ "cpol", 0, 0, 'O' }, { "quad", 0, 0, '4' },
{ "lsb", 0, 0, 'L' }, { "octal", 0, 0, '8' },
{ "cs-high", 0, 0, 'C' }, { "3wire", 0, 0, '3' },
{ "3wire", 0, 0, '3' }, { "3wire-hiz", 0, 0, 'Z' },
{ "no-cs", 0, 0, 'N' }, { "input", 1, 0, 'i' },
{ "ready", 0, 0, 'R' }, { "output", 1, 0, 'o' },
{ "dual", 0, 0, '2' }, { "size", 1, 0, 'S' },
{ "verbose", 0, 0, 'v' }, { "iter", 1, 0, 'I' },
{ "quad", 0, 0, '4' }, { "bpw", 1, 0, 'b' },
{ "octal", 0, 0, '8' }, { "lsb", 0, 0, 'L' },
{ "size", 1, 0, 'S' }, { "cs-high", 0, 0, 'C' },
{ "iter", 1, 0, 'I' }, { "no-cs", 0, 0, 'N' },
{ "ready", 0, 0, 'R' },
{ "mosi-idle-low", 0, 0, 'M' },
{ "verbose", 0, 0, 'v' },
{ NULL, 0, 0, 0 }, { NULL, 0, 0, 0 },
}; };
int c; int c;
c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR248p:vS:I:", c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3ZFMNR248p:vS:I:",
lopts, NULL); lopts, NULL);
if (c == -1) if (c == -1)
...@@ -268,6 +280,15 @@ static void parse_opts(int argc, char *argv[]) ...@@ -268,6 +280,15 @@ static void parse_opts(int argc, char *argv[])
case '3': case '3':
mode |= SPI_3WIRE; mode |= SPI_3WIRE;
break; break;
case 'Z':
mode |= SPI_3WIRE_HIZ;
break;
case 'F':
mode |= SPI_RX_CPHA_FLIP;
break;
case 'M':
mode |= SPI_MOSI_IDLE_LOW;
break;
case 'N': case 'N':
mode |= SPI_NO_CS; mode |= SPI_NO_CS;
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment