xref: /linux/tools/gpio/gpio-hammer.c (revision 9b08f8327f71bf3b091567f0a9ddb72ca60f4fb2)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22a144dd0SLinus Walleij /*
32a144dd0SLinus Walleij  * gpio-hammer - example swiss army knife to shake GPIO lines on a system
42a144dd0SLinus Walleij  *
52a144dd0SLinus Walleij  * Copyright (C) 2016 Linus Walleij
62a144dd0SLinus Walleij  *
72a144dd0SLinus Walleij  * Usage:
82a144dd0SLinus Walleij  *	gpio-hammer -n <device-name> -o <offset1> -o <offset2>
92a144dd0SLinus Walleij  */
102a144dd0SLinus Walleij 
112a144dd0SLinus Walleij #include <unistd.h>
122a144dd0SLinus Walleij #include <stdlib.h>
132a144dd0SLinus Walleij #include <stdbool.h>
142a144dd0SLinus Walleij #include <stdio.h>
152a144dd0SLinus Walleij #include <dirent.h>
162a144dd0SLinus Walleij #include <errno.h>
172a144dd0SLinus Walleij #include <string.h>
182a144dd0SLinus Walleij #include <poll.h>
192a144dd0SLinus Walleij #include <fcntl.h>
202a144dd0SLinus Walleij #include <getopt.h>
212a144dd0SLinus Walleij #include <sys/ioctl.h>
222a144dd0SLinus Walleij #include <linux/gpio.h>
2374100bb9SBamvor Jian Zhang #include "gpio-utils.h"
242a144dd0SLinus Walleij 
25ed60aee0SKent Gibson int hammer_device(const char *device_name, unsigned int *lines, int num_lines,
262a144dd0SLinus Walleij 		  unsigned int loops)
272a144dd0SLinus Walleij {
287ff6d1d2SKent Gibson 	struct gpio_v2_line_values values;
297ff6d1d2SKent Gibson 	struct gpio_v2_line_config config;
302a144dd0SLinus Walleij 	char swirr[] = "-\\|/";
312a144dd0SLinus Walleij 	int fd;
322a144dd0SLinus Walleij 	int ret;
332a144dd0SLinus Walleij 	int i, j;
342a144dd0SLinus Walleij 	unsigned int iteration = 0;
352a144dd0SLinus Walleij 
367ff6d1d2SKent Gibson 	memset(&config, 0, sizeof(config));
377ff6d1d2SKent Gibson 	config.flags = GPIO_V2_LINE_FLAG_OUTPUT;
387ff6d1d2SKent Gibson 
397ff6d1d2SKent Gibson 	ret = gpiotools_request_line(device_name, lines, num_lines,
407ff6d1d2SKent Gibson 				     &config, "gpio-hammer");
412a144dd0SLinus Walleij 	if (ret < 0)
4274100bb9SBamvor Jian Zhang 		goto exit_error;
4374100bb9SBamvor Jian Zhang 	else
4474100bb9SBamvor Jian Zhang 		fd = ret;
452a144dd0SLinus Walleij 
467ff6d1d2SKent Gibson 	values.mask = 0;
477ff6d1d2SKent Gibson 	values.bits = 0;
487ff6d1d2SKent Gibson 	for (i = 0; i < num_lines; i++)
497ff6d1d2SKent Gibson 		gpiotools_set_bit(&values.mask, i);
507ff6d1d2SKent Gibson 
517ff6d1d2SKent Gibson 	ret = gpiotools_get_values(fd, &values);
5274100bb9SBamvor Jian Zhang 	if (ret < 0)
532a144dd0SLinus Walleij 		goto exit_close_error;
542a144dd0SLinus Walleij 
552a144dd0SLinus Walleij 	fprintf(stdout, "Hammer lines [");
56ed60aee0SKent Gibson 	for (i = 0; i < num_lines; i++) {
57*ac93ca12SZhu Jun 		fprintf(stdout, "%u", lines[i]);
58ed60aee0SKent Gibson 		if (i != (num_lines - 1))
592a144dd0SLinus Walleij 			fprintf(stdout, ", ");
602a144dd0SLinus Walleij 	}
612a144dd0SLinus Walleij 	fprintf(stdout, "] on %s, initial states: [", device_name);
62ed60aee0SKent Gibson 	for (i = 0; i < num_lines; i++) {
637ff6d1d2SKent Gibson 		fprintf(stdout, "%d", gpiotools_test_bit(values.bits, i));
64ed60aee0SKent Gibson 		if (i != (num_lines - 1))
652a144dd0SLinus Walleij 			fprintf(stdout, ", ");
662a144dd0SLinus Walleij 	}
672a144dd0SLinus Walleij 	fprintf(stdout, "]\n");
682a144dd0SLinus Walleij 
692a144dd0SLinus Walleij 	/* Hammertime! */
702a144dd0SLinus Walleij 	j = 0;
712a144dd0SLinus Walleij 	while (1) {
722a144dd0SLinus Walleij 		/* Invert all lines so we blink */
73ed60aee0SKent Gibson 		for (i = 0; i < num_lines; i++)
747ff6d1d2SKent Gibson 			gpiotools_change_bit(&values.bits, i);
752a144dd0SLinus Walleij 
767ff6d1d2SKent Gibson 		ret = gpiotools_set_values(fd, &values);
7774100bb9SBamvor Jian Zhang 		if (ret < 0)
782a144dd0SLinus Walleij 			goto exit_close_error;
7974100bb9SBamvor Jian Zhang 
802a144dd0SLinus Walleij 		/* Re-read values to get status */
817ff6d1d2SKent Gibson 		ret = gpiotools_get_values(fd, &values);
8274100bb9SBamvor Jian Zhang 		if (ret < 0)
832a144dd0SLinus Walleij 			goto exit_close_error;
842a144dd0SLinus Walleij 
852a144dd0SLinus Walleij 		fprintf(stdout, "[%c] ", swirr[j]);
862a144dd0SLinus Walleij 		j++;
872a144dd0SLinus Walleij 		if (j == sizeof(swirr) - 1)
882a144dd0SLinus Walleij 			j = 0;
892a144dd0SLinus Walleij 
902a144dd0SLinus Walleij 		fprintf(stdout, "[");
91ed60aee0SKent Gibson 		for (i = 0; i < num_lines; i++) {
92*ac93ca12SZhu Jun 			fprintf(stdout, "%u: %d", lines[i],
937ff6d1d2SKent Gibson 				gpiotools_test_bit(values.bits, i));
94ed60aee0SKent Gibson 			if (i != (num_lines - 1))
952a144dd0SLinus Walleij 				fprintf(stdout, ", ");
962a144dd0SLinus Walleij 		}
972a144dd0SLinus Walleij 		fprintf(stdout, "]\r");
982a144dd0SLinus Walleij 		fflush(stdout);
992a144dd0SLinus Walleij 		sleep(1);
1002a144dd0SLinus Walleij 		iteration++;
1012a144dd0SLinus Walleij 		if (loops && iteration == loops)
1022a144dd0SLinus Walleij 			break;
1032a144dd0SLinus Walleij 	}
1042a144dd0SLinus Walleij 	fprintf(stdout, "\n");
1052a144dd0SLinus Walleij 	ret = 0;
1062a144dd0SLinus Walleij 
1072a144dd0SLinus Walleij exit_close_error:
1087ff6d1d2SKent Gibson 	gpiotools_release_line(fd);
10974100bb9SBamvor Jian Zhang exit_error:
1102a144dd0SLinus Walleij 	return ret;
1112a144dd0SLinus Walleij }
1122a144dd0SLinus Walleij 
1132a144dd0SLinus Walleij void print_usage(void)
1142a144dd0SLinus Walleij {
1152a144dd0SLinus Walleij 	fprintf(stderr, "Usage: gpio-hammer [options]...\n"
1162a144dd0SLinus Walleij 		"Hammer GPIO lines, 0->1->0->1...\n"
1172a144dd0SLinus Walleij 		"  -n <name>  Hammer GPIOs on a named device (must be stated)\n"
1182a144dd0SLinus Walleij 		"  -o <n>     Offset[s] to hammer, at least one, several can be stated\n"
1192a144dd0SLinus Walleij 		" [-c <n>]    Do <n> loops (optional, infinite loop if not stated)\n"
1202a144dd0SLinus Walleij 		"  -?         This helptext\n"
1212a144dd0SLinus Walleij 		"\n"
1222a144dd0SLinus Walleij 		"Example:\n"
1232a144dd0SLinus Walleij 		"gpio-hammer -n gpiochip0 -o 4\n"
1242a144dd0SLinus Walleij 	);
1252a144dd0SLinus Walleij }
1262a144dd0SLinus Walleij 
1272a144dd0SLinus Walleij int main(int argc, char **argv)
1282a144dd0SLinus Walleij {
1292a144dd0SLinus Walleij 	const char *device_name = NULL;
1302a144dd0SLinus Walleij 	unsigned int lines[GPIOHANDLES_MAX];
1312a144dd0SLinus Walleij 	unsigned int loops = 0;
132ed60aee0SKent Gibson 	int num_lines;
1332a144dd0SLinus Walleij 	int c;
1342a144dd0SLinus Walleij 	int i;
1352a144dd0SLinus Walleij 
1362a144dd0SLinus Walleij 	i = 0;
1372a144dd0SLinus Walleij 	while ((c = getopt(argc, argv, "c:n:o:?")) != -1) {
1382a144dd0SLinus Walleij 		switch (c) {
1392a144dd0SLinus Walleij 		case 'c':
1402a144dd0SLinus Walleij 			loops = strtoul(optarg, NULL, 10);
1412a144dd0SLinus Walleij 			break;
1422a144dd0SLinus Walleij 		case 'n':
1432a144dd0SLinus Walleij 			device_name = optarg;
1442a144dd0SLinus Walleij 			break;
1452a144dd0SLinus Walleij 		case 'o':
146d1ee7e1fSGabriel Ravier 			/*
147d1ee7e1fSGabriel Ravier 			 * Avoid overflow. Do not immediately error, we want to
148d1ee7e1fSGabriel Ravier 			 * be able to accurately report on the amount of times
149d1ee7e1fSGabriel Ravier 			 * '-o' was given to give an accurate error message
150d1ee7e1fSGabriel Ravier 			 */
151d1ee7e1fSGabriel Ravier 			if (i < GPIOHANDLES_MAX)
1522a144dd0SLinus Walleij 				lines[i] = strtoul(optarg, NULL, 10);
153d1ee7e1fSGabriel Ravier 
1542a144dd0SLinus Walleij 			i++;
1552a144dd0SLinus Walleij 			break;
1562a144dd0SLinus Walleij 		case '?':
1572a144dd0SLinus Walleij 			print_usage();
1582a144dd0SLinus Walleij 			return -1;
1592a144dd0SLinus Walleij 		}
1602a144dd0SLinus Walleij 	}
161d1ee7e1fSGabriel Ravier 
162d1ee7e1fSGabriel Ravier 	if (i >= GPIOHANDLES_MAX) {
163d1ee7e1fSGabriel Ravier 		fprintf(stderr,
16455f17e2aSColin Ian King 			"Only %d occurrences of '-o' are allowed, %d were found\n",
165d1ee7e1fSGabriel Ravier 			GPIOHANDLES_MAX, i + 1);
166d1ee7e1fSGabriel Ravier 		return -1;
167d1ee7e1fSGabriel Ravier 	}
168d1ee7e1fSGabriel Ravier 
169ed60aee0SKent Gibson 	num_lines = i;
1702a144dd0SLinus Walleij 
171ed60aee0SKent Gibson 	if (!device_name || !num_lines) {
1722a144dd0SLinus Walleij 		print_usage();
1732a144dd0SLinus Walleij 		return -1;
1742a144dd0SLinus Walleij 	}
175ed60aee0SKent Gibson 	return hammer_device(device_name, lines, num_lines, loops);
1762a144dd0SLinus Walleij }
177