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