18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SPI testing utility (using spidev driver) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2007 MontaVista Software, Inc. 68c2ecf20Sopenharmony_ci * Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Cross-compile with cross-gcc -I/path/to/cross-kernel/include 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <stdint.h> 128c2ecf20Sopenharmony_ci#include <unistd.h> 138c2ecf20Sopenharmony_ci#include <stdio.h> 148c2ecf20Sopenharmony_ci#include <stdlib.h> 158c2ecf20Sopenharmony_ci#include <string.h> 168c2ecf20Sopenharmony_ci#include <errno.h> 178c2ecf20Sopenharmony_ci#include <getopt.h> 188c2ecf20Sopenharmony_ci#include <fcntl.h> 198c2ecf20Sopenharmony_ci#include <time.h> 208c2ecf20Sopenharmony_ci#include <sys/ioctl.h> 218c2ecf20Sopenharmony_ci#include <linux/ioctl.h> 228c2ecf20Sopenharmony_ci#include <sys/stat.h> 238c2ecf20Sopenharmony_ci#include <linux/types.h> 248c2ecf20Sopenharmony_ci#include <linux/spi/spidev.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic void pabort(const char *s) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci if (errno != 0) 318c2ecf20Sopenharmony_ci perror(s); 328c2ecf20Sopenharmony_ci else 338c2ecf20Sopenharmony_ci printf("%s\n", s); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci abort(); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic const char *device = "/dev/spidev1.1"; 398c2ecf20Sopenharmony_cistatic uint32_t mode; 408c2ecf20Sopenharmony_cistatic uint8_t bits = 8; 418c2ecf20Sopenharmony_cistatic char *input_file; 428c2ecf20Sopenharmony_cistatic char *output_file; 438c2ecf20Sopenharmony_cistatic uint32_t speed = 500000; 448c2ecf20Sopenharmony_cistatic uint16_t delay; 458c2ecf20Sopenharmony_cistatic int verbose; 468c2ecf20Sopenharmony_cistatic int transfer_size; 478c2ecf20Sopenharmony_cistatic int iterations; 488c2ecf20Sopenharmony_cistatic int interval = 5; /* interval in seconds for showing transfer rate */ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic uint8_t default_tx[] = { 518c2ecf20Sopenharmony_ci 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 528c2ecf20Sopenharmony_ci 0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 538c2ecf20Sopenharmony_ci 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 548c2ecf20Sopenharmony_ci 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 558c2ecf20Sopenharmony_ci 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 568c2ecf20Sopenharmony_ci 0xF0, 0x0D, 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, }; 608c2ecf20Sopenharmony_cistatic char *input_tx; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void hex_dump(const void *src, size_t length, size_t line_size, 638c2ecf20Sopenharmony_ci char *prefix) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci int i = 0; 668c2ecf20Sopenharmony_ci const unsigned char *address = src; 678c2ecf20Sopenharmony_ci const unsigned char *line = address; 688c2ecf20Sopenharmony_ci unsigned char c; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci printf("%s | ", prefix); 718c2ecf20Sopenharmony_ci while (length-- > 0) { 728c2ecf20Sopenharmony_ci printf("%02X ", *address++); 738c2ecf20Sopenharmony_ci if (!(++i % line_size) || (length == 0 && i % line_size)) { 748c2ecf20Sopenharmony_ci if (length == 0) { 758c2ecf20Sopenharmony_ci while (i++ % line_size) 768c2ecf20Sopenharmony_ci printf("__ "); 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci printf(" |"); 798c2ecf20Sopenharmony_ci while (line < address) { 808c2ecf20Sopenharmony_ci c = *line++; 818c2ecf20Sopenharmony_ci printf("%c", (c < 32 || c > 126) ? '.' : c); 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci printf("|\n"); 848c2ecf20Sopenharmony_ci if (length > 0) 858c2ecf20Sopenharmony_ci printf("%s | ", prefix); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* 918c2ecf20Sopenharmony_ci * Unescape - process hexadecimal escape character 928c2ecf20Sopenharmony_ci * converts shell input "\x23" -> 0x23 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_cistatic int unescape(char *_dst, char *_src, size_t len) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci int ret = 0; 978c2ecf20Sopenharmony_ci int match; 988c2ecf20Sopenharmony_ci char *src = _src; 998c2ecf20Sopenharmony_ci char *dst = _dst; 1008c2ecf20Sopenharmony_ci unsigned int ch; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci while (*src) { 1038c2ecf20Sopenharmony_ci if (*src == '\\' && *(src+1) == 'x') { 1048c2ecf20Sopenharmony_ci match = sscanf(src + 2, "%2x", &ch); 1058c2ecf20Sopenharmony_ci if (!match) 1068c2ecf20Sopenharmony_ci pabort("malformed input string"); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci src += 4; 1098c2ecf20Sopenharmony_ci *dst++ = (unsigned char)ch; 1108c2ecf20Sopenharmony_ci } else { 1118c2ecf20Sopenharmony_ci *dst++ = *src++; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci ret++; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci return ret; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci int ret; 1218c2ecf20Sopenharmony_ci int out_fd; 1228c2ecf20Sopenharmony_ci struct spi_ioc_transfer tr = { 1238c2ecf20Sopenharmony_ci .tx_buf = (unsigned long)tx, 1248c2ecf20Sopenharmony_ci .rx_buf = (unsigned long)rx, 1258c2ecf20Sopenharmony_ci .len = len, 1268c2ecf20Sopenharmony_ci .delay_usecs = delay, 1278c2ecf20Sopenharmony_ci .speed_hz = speed, 1288c2ecf20Sopenharmony_ci .bits_per_word = bits, 1298c2ecf20Sopenharmony_ci }; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (mode & SPI_TX_OCTAL) 1328c2ecf20Sopenharmony_ci tr.tx_nbits = 8; 1338c2ecf20Sopenharmony_ci else if (mode & SPI_TX_QUAD) 1348c2ecf20Sopenharmony_ci tr.tx_nbits = 4; 1358c2ecf20Sopenharmony_ci else if (mode & SPI_TX_DUAL) 1368c2ecf20Sopenharmony_ci tr.tx_nbits = 2; 1378c2ecf20Sopenharmony_ci if (mode & SPI_RX_OCTAL) 1388c2ecf20Sopenharmony_ci tr.rx_nbits = 8; 1398c2ecf20Sopenharmony_ci else if (mode & SPI_RX_QUAD) 1408c2ecf20Sopenharmony_ci tr.rx_nbits = 4; 1418c2ecf20Sopenharmony_ci else if (mode & SPI_RX_DUAL) 1428c2ecf20Sopenharmony_ci tr.rx_nbits = 2; 1438c2ecf20Sopenharmony_ci if (!(mode & SPI_LOOP)) { 1448c2ecf20Sopenharmony_ci if (mode & (SPI_TX_OCTAL | SPI_TX_QUAD | SPI_TX_DUAL)) 1458c2ecf20Sopenharmony_ci tr.rx_buf = 0; 1468c2ecf20Sopenharmony_ci else if (mode & (SPI_RX_OCTAL | SPI_RX_QUAD | SPI_RX_DUAL)) 1478c2ecf20Sopenharmony_ci tr.tx_buf = 0; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); 1518c2ecf20Sopenharmony_ci if (ret < 1) 1528c2ecf20Sopenharmony_ci pabort("can't send spi message"); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (verbose) 1558c2ecf20Sopenharmony_ci hex_dump(tx, len, 32, "TX"); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (output_file) { 1588c2ecf20Sopenharmony_ci out_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666); 1598c2ecf20Sopenharmony_ci if (out_fd < 0) 1608c2ecf20Sopenharmony_ci pabort("could not open output file"); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci ret = write(out_fd, rx, len); 1638c2ecf20Sopenharmony_ci if (ret != len) 1648c2ecf20Sopenharmony_ci pabort("not all bytes written to output file"); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci close(out_fd); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (verbose) 1708c2ecf20Sopenharmony_ci hex_dump(rx, len, 32, "RX"); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void print_usage(const char *prog) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci printf("Usage: %s [-DsbdlHOLC3vpNR24SI]\n", prog); 1768c2ecf20Sopenharmony_ci puts(" -D --device device to use (default /dev/spidev1.1)\n" 1778c2ecf20Sopenharmony_ci " -s --speed max speed (Hz)\n" 1788c2ecf20Sopenharmony_ci " -d --delay delay (usec)\n" 1798c2ecf20Sopenharmony_ci " -b --bpw bits per word\n" 1808c2ecf20Sopenharmony_ci " -i --input input data from a file (e.g. \"test.bin\")\n" 1818c2ecf20Sopenharmony_ci " -o --output output data to a file (e.g. \"results.bin\")\n" 1828c2ecf20Sopenharmony_ci " -l --loop loopback\n" 1838c2ecf20Sopenharmony_ci " -H --cpha clock phase\n" 1848c2ecf20Sopenharmony_ci " -O --cpol clock polarity\n" 1858c2ecf20Sopenharmony_ci " -L --lsb least significant bit first\n" 1868c2ecf20Sopenharmony_ci " -C --cs-high chip select active high\n" 1878c2ecf20Sopenharmony_ci " -3 --3wire SI/SO signals shared\n" 1888c2ecf20Sopenharmony_ci " -v --verbose Verbose (show tx buffer)\n" 1898c2ecf20Sopenharmony_ci " -p Send data (e.g. \"1234\\xde\\xad\")\n" 1908c2ecf20Sopenharmony_ci " -N --no-cs no chip select\n" 1918c2ecf20Sopenharmony_ci " -R --ready slave pulls low to pause\n" 1928c2ecf20Sopenharmony_ci " -2 --dual dual transfer\n" 1938c2ecf20Sopenharmony_ci " -4 --quad quad transfer\n" 1948c2ecf20Sopenharmony_ci " -8 --octal octal transfer\n" 1958c2ecf20Sopenharmony_ci " -S --size transfer size\n" 1968c2ecf20Sopenharmony_ci " -I --iter iterations\n"); 1978c2ecf20Sopenharmony_ci exit(1); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic void parse_opts(int argc, char *argv[]) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci while (1) { 2038c2ecf20Sopenharmony_ci static const struct option lopts[] = { 2048c2ecf20Sopenharmony_ci { "device", 1, 0, 'D' }, 2058c2ecf20Sopenharmony_ci { "speed", 1, 0, 's' }, 2068c2ecf20Sopenharmony_ci { "delay", 1, 0, 'd' }, 2078c2ecf20Sopenharmony_ci { "bpw", 1, 0, 'b' }, 2088c2ecf20Sopenharmony_ci { "input", 1, 0, 'i' }, 2098c2ecf20Sopenharmony_ci { "output", 1, 0, 'o' }, 2108c2ecf20Sopenharmony_ci { "loop", 0, 0, 'l' }, 2118c2ecf20Sopenharmony_ci { "cpha", 0, 0, 'H' }, 2128c2ecf20Sopenharmony_ci { "cpol", 0, 0, 'O' }, 2138c2ecf20Sopenharmony_ci { "lsb", 0, 0, 'L' }, 2148c2ecf20Sopenharmony_ci { "cs-high", 0, 0, 'C' }, 2158c2ecf20Sopenharmony_ci { "3wire", 0, 0, '3' }, 2168c2ecf20Sopenharmony_ci { "no-cs", 0, 0, 'N' }, 2178c2ecf20Sopenharmony_ci { "ready", 0, 0, 'R' }, 2188c2ecf20Sopenharmony_ci { "dual", 0, 0, '2' }, 2198c2ecf20Sopenharmony_ci { "verbose", 0, 0, 'v' }, 2208c2ecf20Sopenharmony_ci { "quad", 0, 0, '4' }, 2218c2ecf20Sopenharmony_ci { "octal", 0, 0, '8' }, 2228c2ecf20Sopenharmony_ci { "size", 1, 0, 'S' }, 2238c2ecf20Sopenharmony_ci { "iter", 1, 0, 'I' }, 2248c2ecf20Sopenharmony_ci { NULL, 0, 0, 0 }, 2258c2ecf20Sopenharmony_ci }; 2268c2ecf20Sopenharmony_ci int c; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR248p:vS:I:", 2298c2ecf20Sopenharmony_ci lopts, NULL); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (c == -1) 2328c2ecf20Sopenharmony_ci break; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci switch (c) { 2358c2ecf20Sopenharmony_ci case 'D': 2368c2ecf20Sopenharmony_ci device = optarg; 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci case 's': 2398c2ecf20Sopenharmony_ci speed = atoi(optarg); 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci case 'd': 2428c2ecf20Sopenharmony_ci delay = atoi(optarg); 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci case 'b': 2458c2ecf20Sopenharmony_ci bits = atoi(optarg); 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci case 'i': 2488c2ecf20Sopenharmony_ci input_file = optarg; 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci case 'o': 2518c2ecf20Sopenharmony_ci output_file = optarg; 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci case 'l': 2548c2ecf20Sopenharmony_ci mode |= SPI_LOOP; 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci case 'H': 2578c2ecf20Sopenharmony_ci mode |= SPI_CPHA; 2588c2ecf20Sopenharmony_ci break; 2598c2ecf20Sopenharmony_ci case 'O': 2608c2ecf20Sopenharmony_ci mode |= SPI_CPOL; 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci case 'L': 2638c2ecf20Sopenharmony_ci mode |= SPI_LSB_FIRST; 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci case 'C': 2668c2ecf20Sopenharmony_ci mode |= SPI_CS_HIGH; 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci case '3': 2698c2ecf20Sopenharmony_ci mode |= SPI_3WIRE; 2708c2ecf20Sopenharmony_ci break; 2718c2ecf20Sopenharmony_ci case 'N': 2728c2ecf20Sopenharmony_ci mode |= SPI_NO_CS; 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci case 'v': 2758c2ecf20Sopenharmony_ci verbose = 1; 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci case 'R': 2788c2ecf20Sopenharmony_ci mode |= SPI_READY; 2798c2ecf20Sopenharmony_ci break; 2808c2ecf20Sopenharmony_ci case 'p': 2818c2ecf20Sopenharmony_ci input_tx = optarg; 2828c2ecf20Sopenharmony_ci break; 2838c2ecf20Sopenharmony_ci case '2': 2848c2ecf20Sopenharmony_ci mode |= SPI_TX_DUAL; 2858c2ecf20Sopenharmony_ci break; 2868c2ecf20Sopenharmony_ci case '4': 2878c2ecf20Sopenharmony_ci mode |= SPI_TX_QUAD; 2888c2ecf20Sopenharmony_ci break; 2898c2ecf20Sopenharmony_ci case '8': 2908c2ecf20Sopenharmony_ci mode |= SPI_TX_OCTAL; 2918c2ecf20Sopenharmony_ci break; 2928c2ecf20Sopenharmony_ci case 'S': 2938c2ecf20Sopenharmony_ci transfer_size = atoi(optarg); 2948c2ecf20Sopenharmony_ci break; 2958c2ecf20Sopenharmony_ci case 'I': 2968c2ecf20Sopenharmony_ci iterations = atoi(optarg); 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci default: 2998c2ecf20Sopenharmony_ci print_usage(argv[0]); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci if (mode & SPI_LOOP) { 3038c2ecf20Sopenharmony_ci if (mode & SPI_TX_DUAL) 3048c2ecf20Sopenharmony_ci mode |= SPI_RX_DUAL; 3058c2ecf20Sopenharmony_ci if (mode & SPI_TX_QUAD) 3068c2ecf20Sopenharmony_ci mode |= SPI_RX_QUAD; 3078c2ecf20Sopenharmony_ci if (mode & SPI_TX_OCTAL) 3088c2ecf20Sopenharmony_ci mode |= SPI_RX_OCTAL; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic void transfer_escaped_string(int fd, char *str) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci size_t size = strlen(str); 3158c2ecf20Sopenharmony_ci uint8_t *tx; 3168c2ecf20Sopenharmony_ci uint8_t *rx; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci tx = malloc(size); 3198c2ecf20Sopenharmony_ci if (!tx) 3208c2ecf20Sopenharmony_ci pabort("can't allocate tx buffer"); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci rx = malloc(size); 3238c2ecf20Sopenharmony_ci if (!rx) 3248c2ecf20Sopenharmony_ci pabort("can't allocate rx buffer"); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci size = unescape((char *)tx, str, size); 3278c2ecf20Sopenharmony_ci transfer(fd, tx, rx, size); 3288c2ecf20Sopenharmony_ci free(rx); 3298c2ecf20Sopenharmony_ci free(tx); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic void transfer_file(int fd, char *filename) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci ssize_t bytes; 3358c2ecf20Sopenharmony_ci struct stat sb; 3368c2ecf20Sopenharmony_ci int tx_fd; 3378c2ecf20Sopenharmony_ci uint8_t *tx; 3388c2ecf20Sopenharmony_ci uint8_t *rx; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (stat(filename, &sb) == -1) 3418c2ecf20Sopenharmony_ci pabort("can't stat input file"); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci tx_fd = open(filename, O_RDONLY); 3448c2ecf20Sopenharmony_ci if (tx_fd < 0) 3458c2ecf20Sopenharmony_ci pabort("can't open input file"); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci tx = malloc(sb.st_size); 3488c2ecf20Sopenharmony_ci if (!tx) 3498c2ecf20Sopenharmony_ci pabort("can't allocate tx buffer"); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci rx = malloc(sb.st_size); 3528c2ecf20Sopenharmony_ci if (!rx) 3538c2ecf20Sopenharmony_ci pabort("can't allocate rx buffer"); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci bytes = read(tx_fd, tx, sb.st_size); 3568c2ecf20Sopenharmony_ci if (bytes != sb.st_size) 3578c2ecf20Sopenharmony_ci pabort("failed to read input file"); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci transfer(fd, tx, rx, sb.st_size); 3608c2ecf20Sopenharmony_ci free(rx); 3618c2ecf20Sopenharmony_ci free(tx); 3628c2ecf20Sopenharmony_ci close(tx_fd); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic uint64_t _read_count; 3668c2ecf20Sopenharmony_cistatic uint64_t _write_count; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic void show_transfer_rate(void) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci static uint64_t prev_read_count, prev_write_count; 3718c2ecf20Sopenharmony_ci double rx_rate, tx_rate; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci rx_rate = ((_read_count - prev_read_count) * 8) / (interval*1000.0); 3748c2ecf20Sopenharmony_ci tx_rate = ((_write_count - prev_write_count) * 8) / (interval*1000.0); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci printf("rate: tx %.1fkbps, rx %.1fkbps\n", rx_rate, tx_rate); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci prev_read_count = _read_count; 3798c2ecf20Sopenharmony_ci prev_write_count = _write_count; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic void transfer_buf(int fd, int len) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci uint8_t *tx; 3858c2ecf20Sopenharmony_ci uint8_t *rx; 3868c2ecf20Sopenharmony_ci int i; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci tx = malloc(len); 3898c2ecf20Sopenharmony_ci if (!tx) 3908c2ecf20Sopenharmony_ci pabort("can't allocate tx buffer"); 3918c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 3928c2ecf20Sopenharmony_ci tx[i] = random(); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci rx = malloc(len); 3958c2ecf20Sopenharmony_ci if (!rx) 3968c2ecf20Sopenharmony_ci pabort("can't allocate rx buffer"); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci transfer(fd, tx, rx, len); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci _write_count += len; 4018c2ecf20Sopenharmony_ci _read_count += len; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (mode & SPI_LOOP) { 4048c2ecf20Sopenharmony_ci if (memcmp(tx, rx, len)) { 4058c2ecf20Sopenharmony_ci fprintf(stderr, "transfer error !\n"); 4068c2ecf20Sopenharmony_ci hex_dump(tx, len, 32, "TX"); 4078c2ecf20Sopenharmony_ci hex_dump(rx, len, 32, "RX"); 4088c2ecf20Sopenharmony_ci exit(1); 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci free(rx); 4138c2ecf20Sopenharmony_ci free(tx); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ciint main(int argc, char *argv[]) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci int ret = 0; 4198c2ecf20Sopenharmony_ci int fd; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci parse_opts(argc, argv); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (input_tx && input_file) 4248c2ecf20Sopenharmony_ci pabort("only one of -p and --input may be selected"); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci fd = open(device, O_RDWR); 4278c2ecf20Sopenharmony_ci if (fd < 0) 4288c2ecf20Sopenharmony_ci pabort("can't open device"); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci /* 4318c2ecf20Sopenharmony_ci * spi mode 4328c2ecf20Sopenharmony_ci */ 4338c2ecf20Sopenharmony_ci ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode); 4348c2ecf20Sopenharmony_ci if (ret == -1) 4358c2ecf20Sopenharmony_ci pabort("can't set spi mode"); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode); 4388c2ecf20Sopenharmony_ci if (ret == -1) 4398c2ecf20Sopenharmony_ci pabort("can't get spi mode"); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* 4428c2ecf20Sopenharmony_ci * bits per word 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_ci ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); 4458c2ecf20Sopenharmony_ci if (ret == -1) 4468c2ecf20Sopenharmony_ci pabort("can't set bits per word"); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); 4498c2ecf20Sopenharmony_ci if (ret == -1) 4508c2ecf20Sopenharmony_ci pabort("can't get bits per word"); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* 4538c2ecf20Sopenharmony_ci * max speed hz 4548c2ecf20Sopenharmony_ci */ 4558c2ecf20Sopenharmony_ci ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); 4568c2ecf20Sopenharmony_ci if (ret == -1) 4578c2ecf20Sopenharmony_ci pabort("can't set max speed hz"); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); 4608c2ecf20Sopenharmony_ci if (ret == -1) 4618c2ecf20Sopenharmony_ci pabort("can't get max speed hz"); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci printf("spi mode: 0x%x\n", mode); 4648c2ecf20Sopenharmony_ci printf("bits per word: %u\n", bits); 4658c2ecf20Sopenharmony_ci printf("max speed: %u Hz (%u kHz)\n", speed, speed/1000); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (input_tx) 4688c2ecf20Sopenharmony_ci transfer_escaped_string(fd, input_tx); 4698c2ecf20Sopenharmony_ci else if (input_file) 4708c2ecf20Sopenharmony_ci transfer_file(fd, input_file); 4718c2ecf20Sopenharmony_ci else if (transfer_size) { 4728c2ecf20Sopenharmony_ci struct timespec last_stat; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &last_stat); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci while (iterations-- > 0) { 4778c2ecf20Sopenharmony_ci struct timespec current; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci transfer_buf(fd, transfer_size); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, ¤t); 4828c2ecf20Sopenharmony_ci if (current.tv_sec - last_stat.tv_sec > interval) { 4838c2ecf20Sopenharmony_ci show_transfer_rate(); 4848c2ecf20Sopenharmony_ci last_stat = current; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci printf("total: tx %.1fKB, rx %.1fKB\n", 4888c2ecf20Sopenharmony_ci _write_count/1024.0, _read_count/1024.0); 4898c2ecf20Sopenharmony_ci } else 4908c2ecf20Sopenharmony_ci transfer(fd, default_tx, default_rx, sizeof(default_tx)); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci close(fd); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return ret; 4958c2ecf20Sopenharmony_ci} 496