linux/tools/spi/spidev_test.c
<<
>>
Prefs
   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
  29static void pabort(const char *s)
  30{
  31        perror(s);
  32        abort();
  33}
  34
  35static const char *device = "/dev/spidev1.1";
  36static uint32_t mode;
  37static uint8_t bits = 8;
  38static char *input_file;
  39static char *output_file;
  40static uint32_t speed = 500000;
  41static uint16_t delay;
  42static int verbose;
  43
  44uint8_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
  53uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, };
  54char *input_tx;
  55
  56static 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 */
  88static 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
 112static 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
 163static 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
 187static 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
 286static 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
 306static 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 (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
 339int 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