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