diff options
Diffstat (limited to 'tools/spi/spidev_test.c')
| -rw-r--r-- | tools/spi/spidev_test.c | 169 |
1 files changed, 110 insertions, 59 deletions
diff --git a/tools/spi/spidev_test.c b/tools/spi/spidev_test.c index 4c12e6aea5d5..f2135d619a0b 100644 --- a/tools/spi/spidev_test.c +++ b/tools/spi/spidev_test.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPI testing utility (using spidev driver) * * Copyright (c) 2007 MontaVista Software, Inc. * Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License. - * * Cross-compile with cross-gcc -I/path/to/cross-kernel/include */ @@ -16,6 +13,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <errno.h> #include <getopt.h> #include <fcntl.h> #include <time.h> @@ -29,7 +27,11 @@ static void pabort(const char *s) { - perror(s); + if (errno != 0) + perror(s); + else + printf("%s\n", s); + abort(); } @@ -40,12 +42,13 @@ static char *input_file; static char *output_file; static uint32_t speed = 500000; static uint16_t delay; +static uint16_t word_delay; static int verbose; static int transfer_size; static int iterations; static int interval = 5; /* interval in seconds for showing transfer rate */ -uint8_t default_tx[] = { +static uint8_t default_tx[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -54,8 +57,8 @@ uint8_t default_tx[] = { 0xF0, 0x0D, }; -uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, }; -char *input_tx; +static uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, }; +static char *input_tx; static void hex_dump(const void *src, size_t length, size_t line_size, char *prefix) @@ -122,22 +125,27 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) .rx_buf = (unsigned long)rx, .len = len, .delay_usecs = delay, + .word_delay_usecs = word_delay, .speed_hz = speed, .bits_per_word = bits, }; - if (mode & SPI_TX_QUAD) + if (mode & SPI_TX_OCTAL) + tr.tx_nbits = 8; + else if (mode & SPI_TX_QUAD) tr.tx_nbits = 4; else if (mode & SPI_TX_DUAL) tr.tx_nbits = 2; - if (mode & SPI_RX_QUAD) + if (mode & SPI_RX_OCTAL) + tr.rx_nbits = 8; + else if (mode & SPI_RX_QUAD) tr.rx_nbits = 4; else if (mode & SPI_RX_DUAL) tr.rx_nbits = 2; if (!(mode & SPI_LOOP)) { - if (mode & (SPI_TX_QUAD | SPI_TX_DUAL)) + if (mode & (SPI_TX_OCTAL | SPI_TX_QUAD | SPI_TX_DUAL)) tr.rx_buf = 0; - else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL)) + else if (mode & (SPI_RX_OCTAL | SPI_RX_QUAD | SPI_RX_DUAL)) tr.tx_buf = 0; } @@ -166,27 +174,38 @@ 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" - " -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" - " -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" - " -2 --dual dual transfer\n" - " -4 --quad quad transfer\n" - " -S --size transfer size\n" - " -I --iter iterations\n"); + printf("Usage: %s [-2348CDFHILMNORSZbdilopsvw]\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" + " -w --word-delay word delay (usec)\n" + " -l --loop loopback\n" + "spi mode:\n" + " -H --cpha clock phase\n" + " -O --cpol clock polarity\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" + "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); } @@ -194,30 +213,35 @@ static void parse_opts(int argc, char *argv[]) { while (1) { static const struct option lopts[] = { - { "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' }, - { "dual", 0, 0, '2' }, - { "verbose", 0, 0, 'v' }, - { "quad", 0, 0, '4' }, - { "size", 1, 0, 'S' }, - { "iter", 1, 0, 'I' }, + { "device", 1, 0, 'D' }, + { "speed", 1, 0, 's' }, + { "delay", 1, 0, 'd' }, + { "word-delay", 1, 0, 'w' }, + { "loop", 0, 0, 'l' }, + { "cpha", 0, 0, 'H' }, + { "cpol", 0, 0, 'O' }, + { "rx-cpha-flip", 0, 0, 'F' }, + { "dual", 0, 0, '2' }, + { "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:lHOLC3NR24p:vS:I:", + c = getopt_long(argc, argv, "D:s:d:w:b:i:o:lHOLC3ZFMNR248p:vS:I:", lopts, NULL); if (c == -1) @@ -233,6 +257,9 @@ static void parse_opts(int argc, char *argv[]) case 'd': delay = atoi(optarg); break; + case 'w': + word_delay = atoi(optarg); + break; case 'b': bits = atoi(optarg); break; @@ -260,6 +287,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; @@ -278,6 +314,9 @@ static void parse_opts(int argc, char *argv[]) case '4': mode |= SPI_TX_QUAD; break; + case '8': + mode |= SPI_TX_OCTAL; + break; case 'S': transfer_size = atoi(optarg); break; @@ -286,7 +325,6 @@ static void parse_opts(int argc, char *argv[]) break; default: print_usage(argv[0]); - break; } } if (mode & SPI_LOOP) { @@ -294,6 +332,8 @@ static void parse_opts(int argc, char *argv[]) mode |= SPI_RX_DUAL; if (mode & SPI_TX_QUAD) mode |= SPI_RX_QUAD; + if (mode & SPI_TX_OCTAL) + mode |= SPI_RX_OCTAL; } } @@ -405,9 +445,13 @@ int main(int argc, char *argv[]) { int ret = 0; int fd; + uint32_t request; parse_opts(argc, argv); + if (input_tx && input_file) + pabort("only one of -p and --input may be selected"); + fd = open(device, O_RDWR); if (fd < 0) pabort("can't open device"); @@ -415,13 +459,23 @@ int main(int argc, char *argv[]) /* * spi mode */ + /* WR is make a request to assign 'mode' */ + request = mode; ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode); if (ret == -1) pabort("can't set spi mode"); + /* RD is read what mode the device actually is in */ ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode); if (ret == -1) pabort("can't get spi mode"); + /* Drivers can reject some mode bits without returning an error. + * Read the current value to identify what mode it is in, and if it + * differs from the requested mode, warn the user. + */ + if (request != mode) + printf("WARNING device does not support requested mode 0x%x\n", + request); /* * bits per word @@ -446,11 +500,8 @@ int main(int argc, char *argv[]) pabort("can't get max speed hz"); printf("spi mode: 0x%x\n", mode); - printf("bits per word: %d\n", bits); - printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); - - if (input_tx && input_file) - pabort("only one of -p and --input may be selected"); + printf("bits per word: %u\n", bits); + printf("max speed: %u Hz (%u kHz)\n", speed, speed/1000); if (input_tx) transfer_escaped_string(fd, input_tx); |
