Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  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}