1 /* 2 * SPI testing utility (using spidev driver) 3 * 4 * Copyright (c) 2007 MontaVista Software, Inc. 5 * Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License. 10 * 11 * Cross-compile with cross-gcc -I/path/to/cross-kernel/include 12 */ 13 14 #include <stdint.h> 15 #include <unistd.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <getopt.h> 20 #include <fcntl.h> 21 #include <sys/ioctl.h> 22 #include <linux/ioctl.h> 23 #include <sys/stat.h> 24 #include <linux/types.h> 25 #include <linux/spi/spidev.h> 26 27 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 28 29 static void pabort(const char *s) 30 { 31 perror(s); 32 abort(); 33 } 34 35 static const char *device = "/dev/spidev1.1"; 36 static uint32_t mode; 37 static uint8_t bits = 8; 38 static char *input_file; 39 static char *output_file; 40 static uint32_t speed = 500000; 41 static uint16_t delay; 42 static int verbose; 43 44 uint8_t default_tx[] = { 45 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 46 0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 47 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 48 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 49 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 50 0xF0, 0x0D, 51 }; 52 53 uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, }; 54 char *input_tx; 55 56 static void hex_dump(const void *src, size_t length, size_t line_size, 57 char *prefix) 58 { 59 int i = 0; 60 const unsigned char *address = src; 61 const unsigned char *line = address; 62 unsigned char c; 63 64 printf("%s | ", prefix); 65 while (length-- > 0) { 66 printf("%02X ", *address++); 67 if (!(++i % line_size) || (length == 0 && i % line_size)) { 68 if (length == 0) { 69 while (i++ % line_size) 70 printf("__ "); 71 } 72 printf(" | "); /* right close */ 73 while (line < address) { 74 c = *line++; 75 printf("%c", (c < 33 || c == 255) ? 0x2E : c); 76 } 77 printf("\n"); 78 if (length > 0) 79 printf("%s | ", prefix); 80 } 81 } 82 } 83 84 /* 85 * Unescape - process hexadecimal escape character 86 * converts shell input "\x23" -> 0x23 87 */ 88 static int unescape(char *_dst, char *_src, size_t len) 89 { 90 int ret = 0; 91 int match; 92 char *src = _src; 93 char *dst = _dst; 94 unsigned int ch; 95 96 while (*src) { 97 if (*src == '\\' && *(src+1) == 'x') { 98 match = sscanf(src + 2, "%2x", &ch); 99 if (!match) 100 pabort("malformed input string"); 101 102 src += 4; 103 *dst++ = (unsigned char)ch; 104 } else { 105 *dst++ = *src++; 106 } 107 ret++; 108 } 109 return ret; 110 } 111 112 static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) 113 { 114 int ret; 115 int out_fd; 116 struct spi_ioc_transfer tr = { 117 .tx_buf = (unsigned long)tx, 118 .rx_buf = (unsigned long)rx, 119 .len = len, 120 .delay_usecs = delay, 121 .speed_hz = speed, 122 .bits_per_word = bits, 123 }; 124 125 if (mode & SPI_TX_QUAD) 126 tr.tx_nbits = 4; 127 else if (mode & SPI_TX_DUAL) 128 tr.tx_nbits = 2; 129 if (mode & SPI_RX_QUAD) 130 tr.rx_nbits = 4; 131 else if (mode & SPI_RX_DUAL) 132 tr.rx_nbits = 2; 133 if (!(mode & SPI_LOOP)) { 134 if (mode & (SPI_TX_QUAD | SPI_TX_DUAL)) 135 tr.rx_buf = 0; 136 else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL)) 137 tr.tx_buf = 0; 138 } 139 140 ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); 141 if (ret < 1) 142 pabort("can't send spi message"); 143 144 if (verbose) 145 hex_dump(tx, len, 32, "TX"); 146 147 if (output_file) { 148 out_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666); 149 if (out_fd < 0) 150 pabort("could not open output file"); 151 152 ret = write(out_fd, rx, len); 153 if (ret != len) 154 pabort("not all bytes written to output file"); 155 156 close(out_fd); 157 } 158 159 if (verbose || !output_file) 160 hex_dump(rx, len, 32, "RX"); 161 } 162 163 static void print_usage(const char *prog) 164 { 165 printf("Usage: %s [-DsbdlHOLC3]\n", prog); 166 puts(" -D --device device to use (default /dev/spidev1.1)\n" 167 " -s --speed max speed (Hz)\n" 168 " -d --delay delay (usec)\n" 169 " -b --bpw bits per word\n" 170 " -i --input input data from a file (e.g. \"test.bin\")\n" 171 " -o --output output data to a file (e.g. \"results.bin\")\n" 172 " -l --loop loopback\n" 173 " -H --cpha clock phase\n" 174 " -O --cpol clock polarity\n" 175 " -L --lsb least significant bit first\n" 176 " -C --cs-high chip select active high\n" 177 " -3 --3wire SI/SO signals shared\n" 178 " -v --verbose Verbose (show tx buffer)\n" 179 " -p Send data (e.g. \"1234\\xde\\xad\")\n" 180 " -N --no-cs no chip select\n" 181 " -R --ready slave pulls low to pause\n" 182 " -2 --dual dual transfer\n" 183 " -4 --quad quad transfer\n"); 184 exit(1); 185 } 186 187 static void parse_opts(int argc, char *argv[]) 188 { 189 while (1) { 190 static const struct option lopts[] = { 191 { "device", 1, 0, 'D' }, 192 { "speed", 1, 0, 's' }, 193 { "delay", 1, 0, 'd' }, 194 { "bpw", 1, 0, 'b' }, 195 { "input", 1, 0, 'i' }, 196 { "output", 1, 0, 'o' }, 197 { "loop", 0, 0, 'l' }, 198 { "cpha", 0, 0, 'H' }, 199 { "cpol", 0, 0, 'O' }, 200 { "lsb", 0, 0, 'L' }, 201 { "cs-high", 0, 0, 'C' }, 202 { "3wire", 0, 0, '3' }, 203 { "no-cs", 0, 0, 'N' }, 204 { "ready", 0, 0, 'R' }, 205 { "dual", 0, 0, '2' }, 206 { "verbose", 0, 0, 'v' }, 207 { "quad", 0, 0, '4' }, 208 { NULL, 0, 0, 0 }, 209 }; 210 int c; 211 212 c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:v", 213 lopts, NULL); 214 215 if (c == -1) 216 break; 217 218 switch (c) { 219 case 'D': 220 device = optarg; 221 break; 222 case 's': 223 speed = atoi(optarg); 224 break; 225 case 'd': 226 delay = atoi(optarg); 227 break; 228 case 'b': 229 bits = atoi(optarg); 230 break; 231 case 'i': 232 input_file = optarg; 233 break; 234 case 'o': 235 output_file = optarg; 236 break; 237 case 'l': 238 mode |= SPI_LOOP; 239 break; 240 case 'H': 241 mode |= SPI_CPHA; 242 break; 243 case 'O': 244 mode |= SPI_CPOL; 245 break; 246 case 'L': 247 mode |= SPI_LSB_FIRST; 248 break; 249 case 'C': 250 mode |= SPI_CS_HIGH; 251 break; 252 case '3': 253 mode |= SPI_3WIRE; 254 break; 255 case 'N': 256 mode |= SPI_NO_CS; 257 break; 258 case 'v': 259 verbose = 1; 260 break; 261 case 'R': 262 mode |= SPI_READY; 263 break; 264 case 'p': 265 input_tx = optarg; 266 break; 267 case '2': 268 mode |= SPI_TX_DUAL; 269 break; 270 case '4': 271 mode |= SPI_TX_QUAD; 272 break; 273 default: 274 print_usage(argv[0]); 275 break; 276 } 277 } 278 if (mode & SPI_LOOP) { 279 if (mode & SPI_TX_DUAL) 280 mode |= SPI_RX_DUAL; 281 if (mode & SPI_TX_QUAD) 282 mode |= SPI_RX_QUAD; 283 } 284 } 285 286 static void transfer_escaped_string(int fd, char *str) 287 { 288 size_t size = strlen(str); 289 uint8_t *tx; 290 uint8_t *rx; 291 292 tx = malloc(size); 293 if (!tx) 294 pabort("can't allocate tx buffer"); 295 296 rx = malloc(size); 297 if (!rx) 298 pabort("can't allocate rx buffer"); 299 300 size = unescape((char *)tx, str, size); 301 transfer(fd, tx, rx, size); 302 free(rx); 303 free(tx); 304 } 305 306 static void transfer_file(int fd, char *filename) 307 { 308 ssize_t bytes; 309 struct stat sb; 310 int tx_fd; 311 uint8_t *tx; 312 uint8_t *rx; 313 314 if (stat(filename, &sb) == -1) 315 pabort("can't stat input file"); 316 317 tx_fd = open(filename, O_RDONLY); 318 if (tx_fd < 0) 319 pabort("can't open input file"); 320 321 tx = malloc(sb.st_size); 322 if (!tx) 323 pabort("can't allocate tx buffer"); 324 325 rx = malloc(sb.st_size); 326 if (!rx) 327 pabort("can't allocate rx buffer"); 328 329 bytes = read(tx_fd, tx, sb.st_size); 330 if (bytes != sb.st_size) 331 pabort("failed to read input file"); 332 333 transfer(fd, tx, rx, sb.st_size); 334 free(rx); 335 free(tx); 336 close(tx_fd); 337 } 338 339 int main(int argc, char *argv[]) 340 { 341 int ret = 0; 342 int fd; 343 344 parse_opts(argc, argv); 345 346 fd = open(device, O_RDWR); 347 if (fd < 0) 348 pabort("can't open device"); 349 350 /* 351 * spi mode 352 */ 353 ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode); 354 if (ret == -1) 355 pabort("can't set spi mode"); 356 357 ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode); 358 if (ret == -1) 359 pabort("can't get spi mode"); 360 361 /* 362 * bits per word 363 */ 364 ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); 365 if (ret == -1) 366 pabort("can't set bits per word"); 367 368 ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); 369 if (ret == -1) 370 pabort("can't get bits per word"); 371 372 /* 373 * max speed hz 374 */ 375 ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); 376 if (ret == -1) 377 pabort("can't set max speed hz"); 378 379 ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); 380 if (ret == -1) 381 pabort("can't get max speed hz"); 382 383 printf("spi mode: 0x%x\n", mode); 384 printf("bits per word: %d\n", bits); 385 printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); 386 387 if (input_tx && input_file) 388 pabort("only one of -p and --input may be selected"); 389 390 if (input_tx) 391 transfer_escaped_string(fd, input_tx); 392 else if (input_file) 393 transfer_file(fd, input_file); 394 else 395 transfer(fd, default_tx, default_rx, sizeof(default_tx)); 396 397 close(fd); 398 399 return ret; 400 } 401