xref: /openbmc/linux/tools/gpio/lsgpio.c (revision eb4b8eca)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26d591c46SLinus Walleij /*
36d591c46SLinus Walleij  * lsgpio - example on how to list the GPIO lines on a system
46d591c46SLinus Walleij  *
56d591c46SLinus Walleij  * Copyright (C) 2015 Linus Walleij
66d591c46SLinus Walleij  *
76d591c46SLinus Walleij  * Usage:
86d591c46SLinus Walleij  *	lsgpio <-n device-name>
96d591c46SLinus Walleij  */
106d591c46SLinus Walleij 
116d591c46SLinus Walleij #include <unistd.h>
126d591c46SLinus Walleij #include <stdlib.h>
136d591c46SLinus Walleij #include <stdbool.h>
146d591c46SLinus Walleij #include <stdio.h>
156d591c46SLinus Walleij #include <dirent.h>
166d591c46SLinus Walleij #include <errno.h>
176d591c46SLinus Walleij #include <string.h>
186d591c46SLinus Walleij #include <poll.h>
196d591c46SLinus Walleij #include <fcntl.h>
206d591c46SLinus Walleij #include <getopt.h>
216d591c46SLinus Walleij #include <sys/ioctl.h>
226d591c46SLinus Walleij #include <linux/gpio.h>
236d591c46SLinus Walleij 
246d591c46SLinus Walleij #include "gpio-utils.h"
256d591c46SLinus Walleij 
26521a2ad6SLinus Walleij struct gpio_flag {
27521a2ad6SLinus Walleij 	char *name;
283c333c47SKent Gibson 	unsigned long long mask;
29521a2ad6SLinus Walleij };
30521a2ad6SLinus Walleij 
31521a2ad6SLinus Walleij struct gpio_flag flagnames[] = {
32521a2ad6SLinus Walleij 	{
333c333c47SKent Gibson 		.name = "used",
343c333c47SKent Gibson 		.mask = GPIO_V2_LINE_FLAG_USED,
353c333c47SKent Gibson 	},
363c333c47SKent Gibson 	{
373c333c47SKent Gibson 		.name = "input",
383c333c47SKent Gibson 		.mask = GPIO_V2_LINE_FLAG_INPUT,
39521a2ad6SLinus Walleij 	},
40521a2ad6SLinus Walleij 	{
41521a2ad6SLinus Walleij 		.name = "output",
423c333c47SKent Gibson 		.mask = GPIO_V2_LINE_FLAG_OUTPUT,
43521a2ad6SLinus Walleij 	},
44521a2ad6SLinus Walleij 	{
45521a2ad6SLinus Walleij 		.name = "active-low",
463c333c47SKent Gibson 		.mask = GPIO_V2_LINE_FLAG_ACTIVE_LOW,
47521a2ad6SLinus Walleij 	},
48521a2ad6SLinus Walleij 	{
49521a2ad6SLinus Walleij 		.name = "open-drain",
503c333c47SKent Gibson 		.mask = GPIO_V2_LINE_FLAG_OPEN_DRAIN,
51521a2ad6SLinus Walleij 	},
52521a2ad6SLinus Walleij 	{
53521a2ad6SLinus Walleij 		.name = "open-source",
543c333c47SKent Gibson 		.mask = GPIO_V2_LINE_FLAG_OPEN_SOURCE,
55521a2ad6SLinus Walleij 	},
563831c051SKent Gibson 	{
573831c051SKent Gibson 		.name = "pull-up",
583c333c47SKent Gibson 		.mask = GPIO_V2_LINE_FLAG_BIAS_PULL_UP,
593831c051SKent Gibson 	},
603831c051SKent Gibson 	{
613831c051SKent Gibson 		.name = "pull-down",
623c333c47SKent Gibson 		.mask = GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN,
633831c051SKent Gibson 	},
643831c051SKent Gibson 	{
653831c051SKent Gibson 		.name = "bias-disabled",
663c333c47SKent Gibson 		.mask = GPIO_V2_LINE_FLAG_BIAS_DISABLED,
673831c051SKent Gibson 	},
68da777be6SKent Gibson 	{
69da777be6SKent Gibson 		.name = "clock-realtime",
70da777be6SKent Gibson 		.mask = GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME,
71da777be6SKent Gibson 	},
72521a2ad6SLinus Walleij };
73521a2ad6SLinus Walleij 
print_attributes(struct gpio_v2_line_info * info)743c333c47SKent Gibson static void print_attributes(struct gpio_v2_line_info *info)
75521a2ad6SLinus Walleij {
76521a2ad6SLinus Walleij 	int i;
773c333c47SKent Gibson 	const char *field_format = "%s";
78521a2ad6SLinus Walleij 
79521a2ad6SLinus Walleij 	for (i = 0; i < ARRAY_SIZE(flagnames); i++) {
803c333c47SKent Gibson 		if (info->flags & flagnames[i].mask) {
813c333c47SKent Gibson 			fprintf(stdout, field_format, flagnames[i].name);
823c333c47SKent Gibson 			field_format = ", %s";
83521a2ad6SLinus Walleij 		}
84521a2ad6SLinus Walleij 	}
853c333c47SKent Gibson 
863c333c47SKent Gibson 	if ((info->flags & GPIO_V2_LINE_FLAG_EDGE_RISING) &&
873c333c47SKent Gibson 	    (info->flags & GPIO_V2_LINE_FLAG_EDGE_FALLING))
883c333c47SKent Gibson 		fprintf(stdout, field_format, "both-edges");
893c333c47SKent Gibson 	else if (info->flags & GPIO_V2_LINE_FLAG_EDGE_RISING)
903c333c47SKent Gibson 		fprintf(stdout, field_format, "rising-edge");
913c333c47SKent Gibson 	else if (info->flags & GPIO_V2_LINE_FLAG_EDGE_FALLING)
923c333c47SKent Gibson 		fprintf(stdout, field_format, "falling-edge");
933c333c47SKent Gibson 
943c333c47SKent Gibson 	for (i = 0; i < info->num_attrs; i++) {
953c333c47SKent Gibson 		if (info->attrs[i].id == GPIO_V2_LINE_ATTR_ID_DEBOUNCE)
963c333c47SKent Gibson 			fprintf(stdout, ", debounce_period=%dusec",
97*eb4b8ecaSMilo Spadacini 				info->attrs[i].debounce_period_us);
983c333c47SKent Gibson 	}
99521a2ad6SLinus Walleij }
100521a2ad6SLinus Walleij 
list_device(const char * device_name)1016d591c46SLinus Walleij int list_device(const char *device_name)
1026d591c46SLinus Walleij {
1036d591c46SLinus Walleij 	struct gpiochip_info cinfo;
1046d591c46SLinus Walleij 	char *chrdev_name;
1056d591c46SLinus Walleij 	int fd;
1066d591c46SLinus Walleij 	int ret;
107521a2ad6SLinus Walleij 	int i;
1086d591c46SLinus Walleij 
1096d591c46SLinus Walleij 	ret = asprintf(&chrdev_name, "/dev/%s", device_name);
1106d591c46SLinus Walleij 	if (ret < 0)
1116d591c46SLinus Walleij 		return -ENOMEM;
1126d591c46SLinus Walleij 
1136d591c46SLinus Walleij 	fd = open(chrdev_name, 0);
1146d591c46SLinus Walleij 	if (fd == -1) {
1156d591c46SLinus Walleij 		ret = -errno;
1166d591c46SLinus Walleij 		fprintf(stderr, "Failed to open %s\n", chrdev_name);
117ef3c61a0SKent Gibson 		goto exit_free_name;
1186d591c46SLinus Walleij 	}
1196d591c46SLinus Walleij 
1206d591c46SLinus Walleij 	/* Inspect this GPIO chip */
1216d591c46SLinus Walleij 	ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &cinfo);
1226d591c46SLinus Walleij 	if (ret == -1) {
1236d591c46SLinus Walleij 		ret = -errno;
124521a2ad6SLinus Walleij 		perror("Failed to issue CHIPINFO IOCTL\n");
125521a2ad6SLinus Walleij 		goto exit_close_error;
1266d591c46SLinus Walleij 	}
127df4878e9SLinus Walleij 	fprintf(stdout, "GPIO chip: %s, \"%s\", %u GPIO lines\n",
128df4878e9SLinus Walleij 		cinfo.name, cinfo.label, cinfo.lines);
1296d591c46SLinus Walleij 
130521a2ad6SLinus Walleij 	/* Loop over the lines and print info */
131521a2ad6SLinus Walleij 	for (i = 0; i < cinfo.lines; i++) {
1323c333c47SKent Gibson 		struct gpio_v2_line_info linfo;
133521a2ad6SLinus Walleij 
134521a2ad6SLinus Walleij 		memset(&linfo, 0, sizeof(linfo));
1353c333c47SKent Gibson 		linfo.offset = i;
136521a2ad6SLinus Walleij 
1373c333c47SKent Gibson 		ret = ioctl(fd, GPIO_V2_GET_LINEINFO_IOCTL, &linfo);
138521a2ad6SLinus Walleij 		if (ret == -1) {
1396d591c46SLinus Walleij 			ret = -errno;
140521a2ad6SLinus Walleij 			perror("Failed to issue LINEINFO IOCTL\n");
141521a2ad6SLinus Walleij 			goto exit_close_error;
142521a2ad6SLinus Walleij 		}
1433c333c47SKent Gibson 		fprintf(stdout, "\tline %2d:", linfo.offset);
144521a2ad6SLinus Walleij 		if (linfo.name[0])
145bb91d345SMarkus Pargmann 			fprintf(stdout, " \"%s\"", linfo.name);
146521a2ad6SLinus Walleij 		else
147521a2ad6SLinus Walleij 			fprintf(stdout, " unnamed");
148214338e3SLinus Walleij 		if (linfo.consumer[0])
149214338e3SLinus Walleij 			fprintf(stdout, " \"%s\"", linfo.consumer);
150521a2ad6SLinus Walleij 		else
151214338e3SLinus Walleij 			fprintf(stdout, " unused");
152521a2ad6SLinus Walleij 		if (linfo.flags) {
153521a2ad6SLinus Walleij 			fprintf(stdout, " [");
1543c333c47SKent Gibson 			print_attributes(&linfo);
155521a2ad6SLinus Walleij 			fprintf(stdout, "]");
156521a2ad6SLinus Walleij 		}
157521a2ad6SLinus Walleij 		fprintf(stdout, "\n");
158521a2ad6SLinus Walleij 
1596d591c46SLinus Walleij 	}
1606d591c46SLinus Walleij 
161521a2ad6SLinus Walleij exit_close_error:
162521a2ad6SLinus Walleij 	if (close(fd) == -1)
163521a2ad6SLinus Walleij 		perror("Failed to close GPIO character device file");
164ef3c61a0SKent Gibson exit_free_name:
1656d591c46SLinus Walleij 	free(chrdev_name);
1666d591c46SLinus Walleij 	return ret;
1676d591c46SLinus Walleij }
1686d591c46SLinus Walleij 
print_usage(void)1696d591c46SLinus Walleij void print_usage(void)
1706d591c46SLinus Walleij {
1716d591c46SLinus Walleij 	fprintf(stderr, "Usage: lsgpio [options]...\n"
1726d591c46SLinus Walleij 		"List GPIO chips, lines and states\n"
1736d591c46SLinus Walleij 		"  -n <name>  List GPIOs on a named device\n"
1746d591c46SLinus Walleij 		"  -?         This helptext\n"
1756d591c46SLinus Walleij 	);
1766d591c46SLinus Walleij }
1776d591c46SLinus Walleij 
main(int argc,char ** argv)1786d591c46SLinus Walleij int main(int argc, char **argv)
1796d591c46SLinus Walleij {
180691998faSGeert Uytterhoeven 	const char *device_name = NULL;
1816d591c46SLinus Walleij 	int ret;
1826d591c46SLinus Walleij 	int c;
1836d591c46SLinus Walleij 
1846d591c46SLinus Walleij 	while ((c = getopt(argc, argv, "n:")) != -1) {
1856d591c46SLinus Walleij 		switch (c) {
1866d591c46SLinus Walleij 		case 'n':
1876d591c46SLinus Walleij 			device_name = optarg;
1886d591c46SLinus Walleij 			break;
1896d591c46SLinus Walleij 		case '?':
1906d591c46SLinus Walleij 			print_usage();
1916d591c46SLinus Walleij 			return -1;
1926d591c46SLinus Walleij 		}
1936d591c46SLinus Walleij 	}
1946d591c46SLinus Walleij 
1956d591c46SLinus Walleij 	if (device_name)
1966d591c46SLinus Walleij 		ret = list_device(device_name);
1976d591c46SLinus Walleij 	else {
1986d591c46SLinus Walleij 		const struct dirent *ent;
1996d591c46SLinus Walleij 		DIR *dp;
2006d591c46SLinus Walleij 
2016d591c46SLinus Walleij 		/* List all GPIO devices one at a time */
2026d591c46SLinus Walleij 		dp = opendir("/dev");
2036d591c46SLinus Walleij 		if (!dp) {
2046d591c46SLinus Walleij 			ret = -errno;
2056d591c46SLinus Walleij 			goto error_out;
2066d591c46SLinus Walleij 		}
2076d591c46SLinus Walleij 
2086d591c46SLinus Walleij 		ret = -ENOENT;
2096d591c46SLinus Walleij 		while (ent = readdir(dp), ent) {
2106d591c46SLinus Walleij 			if (check_prefix(ent->d_name, "gpiochip")) {
2116d591c46SLinus Walleij 				ret = list_device(ent->d_name);
2126d591c46SLinus Walleij 				if (ret)
2136d591c46SLinus Walleij 					break;
2146d591c46SLinus Walleij 			}
2156d591c46SLinus Walleij 		}
2166d591c46SLinus Walleij 
2176d591c46SLinus Walleij 		ret = 0;
2186d591c46SLinus Walleij 		if (closedir(dp) == -1) {
2196d591c46SLinus Walleij 			perror("scanning devices: Failed to close directory");
2206d591c46SLinus Walleij 			ret = -errno;
2216d591c46SLinus Walleij 		}
2226d591c46SLinus Walleij 	}
2236d591c46SLinus Walleij error_out:
2246d591c46SLinus Walleij 	return ret;
2256d591c46SLinus Walleij }
226