Linux Audio

Check our new training course

Loading...
  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 <getopt.h>
 19#include <fcntl.h>
 20#include <sys/ioctl.h>
 21#include <linux/types.h>
 22#include <linux/spi/spidev.h>
 23
 24#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 25
 26static void pabort(const char *s)
 27{
 28	perror(s);
 29	abort();
 30}
 31
 32static const char *device = "/dev/spidev1.1";
 33static uint32_t mode;
 34static uint8_t bits = 8;
 35static uint32_t speed = 500000;
 36static uint16_t delay;
 37
 38static void transfer(int fd)
 39{
 40	int ret;
 41	uint8_t tx[] = {
 42		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 43		0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
 44		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 45		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 46		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 47		0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
 48		0xF0, 0x0D,
 49	};
 50	uint8_t rx[ARRAY_SIZE(tx)] = {0, };
 51	struct spi_ioc_transfer tr = {
 52		.tx_buf = (unsigned long)tx,
 53		.rx_buf = (unsigned long)rx,
 54		.len = ARRAY_SIZE(tx),
 55		.delay_usecs = delay,
 56		.speed_hz = speed,
 57		.bits_per_word = bits,
 58	};
 59
 60	if (mode & SPI_TX_QUAD)
 61		tr.tx_nbits = 4;
 62	else if (mode & SPI_TX_DUAL)
 63		tr.tx_nbits = 2;
 64	if (mode & SPI_RX_QUAD)
 65		tr.rx_nbits = 4;
 66	else if (mode & SPI_RX_DUAL)
 67		tr.rx_nbits = 2;
 68	if (!(mode & SPI_LOOP)) {
 69		if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
 70			tr.rx_buf = 0;
 71		else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL))
 72			tr.tx_buf = 0;
 73	}
 74
 75	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
 76	if (ret < 1)
 77		pabort("can't send spi message");
 78
 79	for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
 80		if (!(ret % 6))
 81			puts("");
 82		printf("%.2X ", rx[ret]);
 83	}
 84	puts("");
 85}
 86
 87static void print_usage(const char *prog)
 88{
 89	printf("Usage: %s [-DsbdlHOLC3]\n", prog);
 90	puts("  -D --device   device to use (default /dev/spidev1.1)\n"
 91	     "  -s --speed    max speed (Hz)\n"
 92	     "  -d --delay    delay (usec)\n"
 93	     "  -b --bpw      bits per word \n"
 94	     "  -l --loop     loopback\n"
 95	     "  -H --cpha     clock phase\n"
 96	     "  -O --cpol     clock polarity\n"
 97	     "  -L --lsb      least significant bit first\n"
 98	     "  -C --cs-high  chip select active high\n"
 99	     "  -3 --3wire    SI/SO signals shared\n"
100	     "  -N --no-cs    no chip select\n"
101	     "  -R --ready    slave pulls low to pause\n"
102	     "  -2 --dual     dual transfer\n"
103	     "  -4 --quad     quad transfer\n");
104	exit(1);
105}
106
107static void parse_opts(int argc, char *argv[])
108{
109	while (1) {
110		static const struct option lopts[] = {
111			{ "device",  1, 0, 'D' },
112			{ "speed",   1, 0, 's' },
113			{ "delay",   1, 0, 'd' },
114			{ "bpw",     1, 0, 'b' },
115			{ "loop",    0, 0, 'l' },
116			{ "cpha",    0, 0, 'H' },
117			{ "cpol",    0, 0, 'O' },
118			{ "lsb",     0, 0, 'L' },
119			{ "cs-high", 0, 0, 'C' },
120			{ "3wire",   0, 0, '3' },
121			{ "no-cs",   0, 0, 'N' },
122			{ "ready",   0, 0, 'R' },
123			{ "dual",    0, 0, '2' },
124			{ "quad",    0, 0, '4' },
125			{ NULL, 0, 0, 0 },
126		};
127		int c;
128
129		c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24", lopts, NULL);
130
131		if (c == -1)
132			break;
133
134		switch (c) {
135		case 'D':
136			device = optarg;
137			break;
138		case 's':
139			speed = atoi(optarg);
140			break;
141		case 'd':
142			delay = atoi(optarg);
143			break;
144		case 'b':
145			bits = atoi(optarg);
146			break;
147		case 'l':
148			mode |= SPI_LOOP;
149			break;
150		case 'H':
151			mode |= SPI_CPHA;
152			break;
153		case 'O':
154			mode |= SPI_CPOL;
155			break;
156		case 'L':
157			mode |= SPI_LSB_FIRST;
158			break;
159		case 'C':
160			mode |= SPI_CS_HIGH;
161			break;
162		case '3':
163			mode |= SPI_3WIRE;
164			break;
165		case 'N':
166			mode |= SPI_NO_CS;
167			break;
168		case 'R':
169			mode |= SPI_READY;
170			break;
171		case '2':
172			mode |= SPI_TX_DUAL;
173			break;
174		case '4':
175			mode |= SPI_TX_QUAD;
176			break;
177		default:
178			print_usage(argv[0]);
179			break;
180		}
181	}
182	if (mode & SPI_LOOP) {
183		if (mode & SPI_TX_DUAL)
184			mode |= SPI_RX_DUAL;
185		if (mode & SPI_TX_QUAD)
186			mode |= SPI_RX_QUAD;
187	}
188}
189
190int main(int argc, char *argv[])
191{
192	int ret = 0;
193	int fd;
194
195	parse_opts(argc, argv);
196
197	fd = open(device, O_RDWR);
198	if (fd < 0)
199		pabort("can't open device");
200
201	/*
202	 * spi mode
203	 */
204	ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
205	if (ret == -1)
206		pabort("can't set spi mode");
207
208	ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
209	if (ret == -1)
210		pabort("can't get spi mode");
211
212	/*
213	 * bits per word
214	 */
215	ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
216	if (ret == -1)
217		pabort("can't set bits per word");
218
219	ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
220	if (ret == -1)
221		pabort("can't get bits per word");
222
223	/*
224	 * max speed hz
225	 */
226	ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
227	if (ret == -1)
228		pabort("can't set max speed hz");
229
230	ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
231	if (ret == -1)
232		pabort("can't get max speed hz");
233
234	printf("spi mode: 0x%x\n", mode);
235	printf("bits per word: %d\n", bits);
236	printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
237
238	transfer(fd);
239
240	close(fd);
241
242	return ret;
243}
1