Unverified Commit fe732455 authored by Mark Brown's avatar Mark Brown
Browse files

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
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -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_SBBCTRL(cs)	(1 << ((cs & 3) +  8))
#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_INT		0x10
@@ -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));
	}

	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)
		cfg |= MX51_ECSPI_CONFIG_SSBPOL(spi_get_chipselect(spi, 0));
	else
@@ -1743,7 +1749,8 @@ static int spi_imx_probe(struct platform_device *pdev)
	controller->prepare_message = spi_imx_prepare_message;
	controller->unprepare_message = spi_imx_unprepare_message;
	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) ||
	    is_imx53_ecspi(spi_imx))
+2 −1
Original line number Diff line number Diff line
@@ -64,7 +64,8 @@ static_assert(N_SPI_MINORS > 0 && N_SPI_MINORS <= 256);
				| SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
				| SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \
				| SPI_RX_QUAD | SPI_RX_OCTAL \
				| SPI_RX_CPHA_FLIP)
				| SPI_RX_CPHA_FLIP | SPI_3WIRE_HIZ \
				| SPI_MOSI_IDLE_LOW)

struct spidev_data {
	dev_t			devt;
+2 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#define	SPI_RX_OCTAL		_BITUL(14)	/* receive with 8 wires */
#define	SPI_3WIRE_HIZ		_BITUL(15)	/* high impedance turnaround */
#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.
@@ -37,6 +38,6 @@
 * 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.
 */
#define SPI_MODE_USER_MASK	(_BITUL(17) - 1)
#define SPI_MODE_USER_MASK	(_BITUL(18) - 1)

#endif /* _UAPI_SPI_H */
+64 −43
Original line number Diff line number Diff line
@@ -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)
{
	printf("Usage: %s [-DsbdlHOLC3vpNR24SI]\n", prog);
	puts("  -D --device   device to use (default /dev/spidev1.1)\n"
	printf("Usage: %s [-2348CDFHILMNORSZbdilopsv]\n", prog);
	puts("general device settings:\n"
		 "  -D --device         device to use (default /dev/spidev1.1)\n"
		 "  -s --speed          max speed (Hz)\n"
		 "  -d --delay          delay (usec)\n"
	     "  -b --bpw      bits per word\n"
	     "  -i --input    input data from a file (e.g. \"test.bin\")\n"
	     "  -o --output   output data to a file (e.g. \"results.bin\")\n"
		 "  -l --loop           loopback\n"
		 "spi mode:\n"
		 "  -H --cpha           clock phase\n"
		 "  -O --cpol           clock polarity\n"
	     "  -L --lsb      least significant bit first\n"
	     "  -C --cs-high  chip select active high\n"
	     "  -3 --3wire    SI/SO signals shared\n"
	     "  -v --verbose  Verbose (show tx buffer)\n"
	     "  -p            Send data (e.g. \"1234\\xde\\xad\")\n"
	     "  -N --no-cs    no chip select\n"
	     "  -R --ready    slave pulls low to pause\n"
		 "  -F --rx-cpha-flip   flip CPHA on Rx only xfer\n"
		 "number of wires for transmission:\n"
		 "  -2 --dual           dual transfer\n"
		 "  -4 --quad           quad transfer\n"
		 "  -8 --octal          octal transfer\n"
		 "  -3 --3wire          SI/SO signals shared\n"
		 "  -Z --3wire-hiz      high impedance turnaround\n"
		 "data:\n"
		 "  -i --input          input data from a file (e.g. \"test.bin\")\n"
		 "  -o --output         output data to a file (e.g. \"results.bin\")\n"
		 "  -p                  Send data (e.g. \"1234\\xde\\xad\")\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);
}

@@ -204,28 +213,31 @@ static void parse_opts(int argc, char *argv[])
			{ "device",        1, 0, 'D' },
			{ "speed",         1, 0, 's' },
			{ "delay",         1, 0, 'd' },
			{ "bpw",     1, 0, 'b' },
			{ "input",   1, 0, 'i' },
			{ "output",  1, 0, 'o' },
			{ "loop",          0, 0, 'l' },
			{ "cpha",          0, 0, 'H' },
			{ "cpol",          0, 0, 'O' },
			{ "lsb",     0, 0, 'L' },
			{ "cs-high", 0, 0, 'C' },
			{ "3wire",   0, 0, '3' },
			{ "no-cs",   0, 0, 'N' },
			{ "ready",   0, 0, 'R' },
			{ "rx-cpha-flip",  0, 0, 'F' },
			{ "dual",          0, 0, '2' },
			{ "verbose", 0, 0, 'v' },
			{ "quad",          0, 0, '4' },
			{ "octal",         0, 0, '8' },
			{ "3wire",         0, 0, '3' },
			{ "3wire-hiz",     0, 0, 'Z' },
			{ "input",         1, 0, 'i' },
			{ "output",        1, 0, 'o' },
			{ "size",          1, 0, 'S' },
			{ "iter",          1, 0, 'I' },
			{ "bpw",           1, 0, 'b' },
			{ "lsb",           0, 0, 'L' },
			{ "cs-high",       0, 0, 'C' },
			{ "no-cs",         0, 0, 'N' },
			{ "ready",         0, 0, 'R' },
			{ "mosi-idle-low", 0, 0, 'M' },
			{ "verbose",       0, 0, 'v' },
			{ NULL, 0, 0, 0 },
		};
		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);

		if (c == -1)
@@ -268,6 +280,15 @@ static void parse_opts(int argc, char *argv[])
		case '3':
			mode |= SPI_3WIRE;
			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':
			mode |= SPI_NO_CS;
			break;