--- /dev/null
+/*
+ * gpio-hammer - example swiss army knife to shake GPIO lines on a system
+ *
+ * Copyright (C) 2016 Linus Walleij
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * Usage:
+ *     gpio-hammer -n <device-name> -o <offset1> -o <offset2>
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <linux/gpio.h>
+
+int hammer_device(const char *device_name, unsigned int *lines, int nlines,
+                 unsigned int loops)
+{
+       struct gpiohandle_request req;
+       struct gpiohandle_data data;
+       char *chrdev_name;
+       char swirr[] = "-\\|/";
+       int fd;
+       int ret;
+       int i, j;
+       unsigned int iteration = 0;
+
+       ret = asprintf(&chrdev_name, "/dev/%s", device_name);
+       if (ret < 0)
+               return -ENOMEM;
+
+       fd = open(chrdev_name, 0);
+       if (fd == -1) {
+               ret = -errno;
+               fprintf(stderr, "Failed to open %s\n", chrdev_name);
+               goto exit_close_error;
+       }
+
+       /* Request lines as output */
+       for (i = 0; i < nlines; i++)
+               req.lineoffsets[i] = lines[i];
+       req.flags = GPIOHANDLE_REQUEST_OUTPUT; /* Request as output */
+       strcpy(req.consumer_label, "gpio-hammer");
+       req.lines = nlines;
+       ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
+       if (ret == -1) {
+               ret = -errno;
+               fprintf(stderr, "Failed to issue GET LINEHANDLE "
+                       "IOCTL (%d)\n",
+                       ret);
+               goto exit_close_error;
+       }
+
+       /* Read initial states */
+       ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
+       if (ret == -1) {
+               ret = -errno;
+               fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE "
+                       "VALUES IOCTL (%d)\n",
+                       ret);
+               goto exit_close_error;
+       }
+       fprintf(stdout, "Hammer lines [");
+       for (i = 0; i < nlines; i++) {
+               fprintf(stdout, "%d", lines[i]);
+               if (i != (nlines - 1))
+                       fprintf(stdout, ", ");
+       }
+       fprintf(stdout, "] on %s, initial states: [", device_name);
+       for (i = 0; i < nlines; i++) {
+               fprintf(stdout, "%d", data.values[i]);
+               if (i != (nlines - 1))
+                       fprintf(stdout, ", ");
+       }
+       fprintf(stdout, "]\n");
+
+       /* Hammertime! */
+       j = 0;
+       while (1) {
+               /* Invert all lines so we blink */
+               for (i = 0; i < nlines; i++)
+                       data.values[i] = !data.values[i];
+
+               ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
+               if (ret == -1) {
+                       ret = -errno;
+                       fprintf(stderr, "Failed to issue GPIOHANDLE SET LINE "
+                               "VALUES IOCTL (%d)\n",
+                               ret);
+                       goto exit_close_error;
+               }
+               /* Re-read values to get status */
+               ret = ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
+               if (ret == -1) {
+                       ret = -errno;
+                       fprintf(stderr, "Failed to issue GPIOHANDLE GET LINE "
+                               "VALUES IOCTL (%d)\n",
+                               ret);
+                       goto exit_close_error;
+               }
+
+               fprintf(stdout, "[%c] ", swirr[j]);
+               j++;
+               if (j == sizeof(swirr)-1)
+                       j = 0;
+
+               fprintf(stdout, "[");
+               for (i = 0; i < nlines; i++) {
+                       fprintf(stdout, "%d: %d", lines[i], data.values[i]);
+                       if (i != (nlines - 1))
+                               fprintf(stdout, ", ");
+               }
+               fprintf(stdout, "]\r");
+               fflush(stdout);
+               sleep(1);
+               iteration++;
+               if (loops && iteration == loops)
+                       break;
+       }
+       fprintf(stdout, "\n");
+       ret = 0;
+
+exit_close_error:
+       if (close(fd) == -1)
+               perror("Failed to close GPIO character device file");
+       free(chrdev_name);
+       return ret;
+}
+
+void print_usage(void)
+{
+       fprintf(stderr, "Usage: gpio-hammer [options]...\n"
+               "Hammer GPIO lines, 0->1->0->1...\n"
+               "  -n <name>  Hammer GPIOs on a named device (must be stated)\n"
+               "  -o <n>     Offset[s] to hammer, at least one, several can be stated\n"
+               " [-c <n>]    Do <n> loops (optional, infinite loop if not stated)\n"
+               "  -?         This helptext\n"
+               "\n"
+               "Example:\n"
+               "gpio-hammer -n gpiochip0 -o 4\n"
+       );
+}
+
+int main(int argc, char **argv)
+{
+       const char *device_name = NULL;
+       unsigned int lines[GPIOHANDLES_MAX];
+       unsigned int loops = 0;
+       int nlines;
+       int c;
+       int i;
+
+       i = 0;
+       while ((c = getopt(argc, argv, "c:n:o:?")) != -1) {
+               switch (c) {
+               case 'c':
+                       loops = strtoul(optarg, NULL, 10);
+                       break;
+               case 'n':
+                       device_name = optarg;
+                       break;
+               case 'o':
+                       lines[i] = strtoul(optarg, NULL, 10);
+                       i++;
+                       break;
+               case '?':
+                       print_usage();
+                       return -1;
+               }
+       }
+       nlines = i;
+
+       if (!device_name || !nlines) {
+               print_usage();
+               return -1;
+       }
+       return hammer_device(device_name, lines, nlines, loops);
+}