mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
spi: spidev_test: add option to split message into multiple transfers
SPI_IOC_MESSAGE() submits a single SPI message containing one or more transfers. Introduce an option to allow splitting the message into multiple transfers. Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> Signed-off-by: Jonas Rebmann <jre@pengutronix.de> Link: https://patch.msgid.link/20260924-spi-sun4i-spidev_test-v7-11-126e31a07fdc@pengutronix.de Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
c807c71d21
commit
31ce698070
|
|
@ -42,6 +42,7 @@ static uint16_t delay;
|
|||
static uint16_t word_delay;
|
||||
static int verbose;
|
||||
static int transfer_size = -1;
|
||||
static int transfers = 1;
|
||||
static int iterations;
|
||||
static int interval = 5; /* interval in seconds for showing transfer rate */
|
||||
static int compare;
|
||||
|
|
@ -123,40 +124,79 @@ static int unescape(char *_dst, char *_src, size_t len)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
|
||||
static void transfer(int fd, uint8_t const * const tx, uint8_t const * const rx, size_t len)
|
||||
{
|
||||
int ret;
|
||||
int out_fd;
|
||||
struct spi_ioc_transfer tr = {
|
||||
.tx_buf = (unsigned long)tx,
|
||||
.rx_buf = (unsigned long)rx,
|
||||
.len = len,
|
||||
.delay_usecs = delay,
|
||||
.word_delay_usecs = word_delay,
|
||||
.speed_hz = speed,
|
||||
.bits_per_word = bits,
|
||||
};
|
||||
size_t bytes_per_word = DIV_ROUND_UP(bits, 8);
|
||||
int effective_transfers;
|
||||
struct spi_ioc_transfer *tr;
|
||||
size_t len_per_transfer;
|
||||
const uint8_t *tx_buf = tx;
|
||||
const uint8_t *rx_buf = rx;
|
||||
size_t rem;
|
||||
|
||||
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_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_OCTAL | SPI_TX_QUAD | SPI_TX_DUAL))
|
||||
tr.rx_buf = 0;
|
||||
else if (mode & (SPI_RX_OCTAL | SPI_RX_QUAD | SPI_RX_DUAL))
|
||||
tr.tx_buf = 0;
|
||||
if (len) {
|
||||
effective_transfers = min_t(size_t, transfers, DIV_ROUND_UP(len, bytes_per_word));
|
||||
len_per_transfer = roundup(DIV_ROUND_UP(len, effective_transfers), bytes_per_word);
|
||||
} else {
|
||||
/* zero-length transfers may be handled by the driver, deliver as ordered */
|
||||
effective_transfers = transfers;
|
||||
len_per_transfer = 0;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
|
||||
if (SPI_MSGSIZE(effective_transfers) == 0)
|
||||
pabort("too many transfers, SPI_IOC_MESSAGE size limit exceeded");
|
||||
|
||||
tr = calloc(effective_transfers, sizeof(*tr));
|
||||
if (!tr)
|
||||
pabort("can't allocate transfer array");
|
||||
|
||||
rem = len;
|
||||
|
||||
for (int i = 0; i < effective_transfers; i++) {
|
||||
size_t n = min(rem, len_per_transfer);
|
||||
|
||||
tr[i] = (struct spi_ioc_transfer) {
|
||||
.tx_buf = (unsigned long)tx_buf,
|
||||
.rx_buf = (unsigned long)rx_buf,
|
||||
.len = n,
|
||||
.delay_usecs = delay,
|
||||
.word_delay_usecs = word_delay,
|
||||
.speed_hz = speed,
|
||||
.bits_per_word = bits,
|
||||
};
|
||||
|
||||
if (tx_buf)
|
||||
tx_buf += n;
|
||||
|
||||
if (rx_buf)
|
||||
rx_buf += n;
|
||||
|
||||
rem -= n;
|
||||
|
||||
if (mode & SPI_TX_OCTAL)
|
||||
tr[i].tx_nbits = 8;
|
||||
else if (mode & SPI_TX_QUAD)
|
||||
tr[i].tx_nbits = 4;
|
||||
else if (mode & SPI_TX_DUAL)
|
||||
tr[i].tx_nbits = 2;
|
||||
if (mode & SPI_RX_OCTAL)
|
||||
tr[i].rx_nbits = 8;
|
||||
else if (mode & SPI_RX_QUAD)
|
||||
tr[i].rx_nbits = 4;
|
||||
else if (mode & SPI_RX_DUAL)
|
||||
tr[i].rx_nbits = 2;
|
||||
if (!(mode & SPI_LOOP)) {
|
||||
if (mode & (SPI_TX_OCTAL | SPI_TX_QUAD | SPI_TX_DUAL))
|
||||
tr[i].rx_buf = 0;
|
||||
else if (mode & (SPI_RX_OCTAL | SPI_RX_QUAD | SPI_RX_DUAL))
|
||||
tr[i].tx_buf = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_MESSAGE(effective_transfers), tr);
|
||||
free(tr);
|
||||
if (ret < 0)
|
||||
pabort("can't send spi message");
|
||||
|
||||
|
|
@ -190,7 +230,7 @@ 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 [-2348CDFHILMNOPRSZbcdiloprstvwz]\n", prog);
|
||||
printf("Usage: %s [-2348CDFHILMNOPRSTZbcdiloprstvwz]\n", prog);
|
||||
puts("general device settings:\n"
|
||||
" -D --device device to use (default /dev/spidev1.1)\n"
|
||||
" -s --speed max speed (Hz)\n"
|
||||
|
|
@ -225,6 +265,7 @@ static void print_usage(const char *prog)
|
|||
" -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"
|
||||
" -T --transfers number of transfers\n"
|
||||
"misc:\n"
|
||||
" -v --verbose Verbose (show tx buffer)\n");
|
||||
exit(1);
|
||||
|
|
@ -262,12 +303,13 @@ static void parse_opts(int argc, char *argv[])
|
|||
{ "ready", 0, 0, 'R' },
|
||||
{ "mosi-idle-low", 0, 0, 'M' },
|
||||
{ "predictable", 1, 0, 'P' },
|
||||
{ "transfers", 1, 0, 'T' },
|
||||
{ "verbose", 0, 0, 'v' },
|
||||
{ NULL, 0, 0, 0 },
|
||||
};
|
||||
int c;
|
||||
|
||||
c = getopt_long(argc, argv, "D:s:d:w:b:i:o:lctrHOLC3ZFMNR248p:P:vS:zI:",
|
||||
c = getopt_long(argc, argv, "D:s:d:w:b:i:o:lctrHOLC3ZFMNR248p:P:T:vS:zI:",
|
||||
lopts, NULL);
|
||||
|
||||
if (c == -1)
|
||||
|
|
@ -332,6 +374,9 @@ static void parse_opts(int argc, char *argv[])
|
|||
case 'M':
|
||||
mode |= SPI_MOSI_IDLE_LOW;
|
||||
break;
|
||||
case 'T':
|
||||
transfers = atoi(optarg);
|
||||
break;
|
||||
case 'N':
|
||||
mode |= SPI_NO_CS;
|
||||
break;
|
||||
|
|
@ -533,6 +578,12 @@ int main(int argc, char *argv[])
|
|||
if (compare && mode & (SPI_TX_OCTAL | SPI_TX_QUAD | SPI_TX_DUAL))
|
||||
pabort("-c (--compare) conflicts with -2 (--dual), -4 (--quad) or -8 (--octal)");
|
||||
|
||||
if (transfers < 1)
|
||||
pabort("-T (--transfers) must be 1 or above");
|
||||
|
||||
if (bits < 1)
|
||||
pabort("-b (--bpw) must be 1 or above");
|
||||
|
||||
fd = open(device, O_RDWR);
|
||||
if (fd < 0)
|
||||
pabort("can't open device");
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user