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