1*cf5a6c84SAndroid Build Coastguard Worker /* gpiod.c - gpio tools
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2021 The Android Open Source Project
4*cf5a6c84SAndroid Build Coastguard Worker *
5*cf5a6c84SAndroid Build Coastguard Worker * TODO: gpiomon
6*cf5a6c84SAndroid Build Coastguard Worker
7*cf5a6c84SAndroid Build Coastguard Worker USE_GPIODETECT(NEWTOY(gpiodetect, ">0", TOYFLAG_USR|TOYFLAG_BIN))
8*cf5a6c84SAndroid Build Coastguard Worker USE_GPIOINFO(NEWTOY(gpioinfo, 0, TOYFLAG_USR|TOYFLAG_BIN))
9*cf5a6c84SAndroid Build Coastguard Worker USE_GPIOGET(NEWTOY(gpioget, "<2l", TOYFLAG_USR|TOYFLAG_BIN))
10*cf5a6c84SAndroid Build Coastguard Worker USE_GPIOFIND(NEWTOY(gpiofind, "<1>1", TOYFLAG_USR|TOYFLAG_BIN))
11*cf5a6c84SAndroid Build Coastguard Worker USE_GPIOSET(NEWTOY(gpioset, "<2l", TOYFLAG_USR|TOYFLAG_BIN))
12*cf5a6c84SAndroid Build Coastguard Worker
13*cf5a6c84SAndroid Build Coastguard Worker config GPIODETECT
14*cf5a6c84SAndroid Build Coastguard Worker bool "gpiodetect"
15*cf5a6c84SAndroid Build Coastguard Worker default y
16*cf5a6c84SAndroid Build Coastguard Worker help
17*cf5a6c84SAndroid Build Coastguard Worker usage: gpiodetect
18*cf5a6c84SAndroid Build Coastguard Worker
19*cf5a6c84SAndroid Build Coastguard Worker Show all gpio chips' names, labels, and number of lines.
20*cf5a6c84SAndroid Build Coastguard Worker
21*cf5a6c84SAndroid Build Coastguard Worker config GPIOFIND
22*cf5a6c84SAndroid Build Coastguard Worker bool "gpiofind"
23*cf5a6c84SAndroid Build Coastguard Worker default y
24*cf5a6c84SAndroid Build Coastguard Worker help
25*cf5a6c84SAndroid Build Coastguard Worker usage: gpiofind NAME
26*cf5a6c84SAndroid Build Coastguard Worker
27*cf5a6c84SAndroid Build Coastguard Worker Show the chip and line number for the given line name.
28*cf5a6c84SAndroid Build Coastguard Worker
29*cf5a6c84SAndroid Build Coastguard Worker config GPIOINFO
30*cf5a6c84SAndroid Build Coastguard Worker bool "gpioinfo"
31*cf5a6c84SAndroid Build Coastguard Worker default y
32*cf5a6c84SAndroid Build Coastguard Worker help
33*cf5a6c84SAndroid Build Coastguard Worker usage: gpioinfo [CHIP...]
34*cf5a6c84SAndroid Build Coastguard Worker
35*cf5a6c84SAndroid Build Coastguard Worker Show gpio chips' lines.
36*cf5a6c84SAndroid Build Coastguard Worker
37*cf5a6c84SAndroid Build Coastguard Worker config GPIOGET
38*cf5a6c84SAndroid Build Coastguard Worker bool "gpioget"
39*cf5a6c84SAndroid Build Coastguard Worker default y
40*cf5a6c84SAndroid Build Coastguard Worker help
41*cf5a6c84SAndroid Build Coastguard Worker usage: gpioget [-l] CHIP LINE...
42*cf5a6c84SAndroid Build Coastguard Worker
43*cf5a6c84SAndroid Build Coastguard Worker Gets the values of the given lines on CHIP. Use gpiofind to convert line
44*cf5a6c84SAndroid Build Coastguard Worker names to numbers.
45*cf5a6c84SAndroid Build Coastguard Worker
46*cf5a6c84SAndroid Build Coastguard Worker -l Active low
47*cf5a6c84SAndroid Build Coastguard Worker
48*cf5a6c84SAndroid Build Coastguard Worker config GPIOSET
49*cf5a6c84SAndroid Build Coastguard Worker bool "gpioset"
50*cf5a6c84SAndroid Build Coastguard Worker default y
51*cf5a6c84SAndroid Build Coastguard Worker help
52*cf5a6c84SAndroid Build Coastguard Worker usage: gpioset [-l] CHIP LINE=VALUE...
53*cf5a6c84SAndroid Build Coastguard Worker
54*cf5a6c84SAndroid Build Coastguard Worker Set the lines on CHIP to the given values. Use gpiofind to convert line
55*cf5a6c84SAndroid Build Coastguard Worker names to numbers.
56*cf5a6c84SAndroid Build Coastguard Worker
57*cf5a6c84SAndroid Build Coastguard Worker -l Active low
58*cf5a6c84SAndroid Build Coastguard Worker */
59*cf5a6c84SAndroid Build Coastguard Worker
60*cf5a6c84SAndroid Build Coastguard Worker #define FOR_gpiodetect
61*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
62*cf5a6c84SAndroid Build Coastguard Worker
GLOBALS(struct double_list * chips;int chip_count;)63*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
64*cf5a6c84SAndroid Build Coastguard Worker struct double_list *chips;
65*cf5a6c84SAndroid Build Coastguard Worker int chip_count;
66*cf5a6c84SAndroid Build Coastguard Worker )
67*cf5a6c84SAndroid Build Coastguard Worker
68*cf5a6c84SAndroid Build Coastguard Worker #include <linux/gpio.h>
69*cf5a6c84SAndroid Build Coastguard Worker
70*cf5a6c84SAndroid Build Coastguard Worker static int open_chip(char *chip)
71*cf5a6c84SAndroid Build Coastguard Worker {
72*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf, isdigit(*chip) ? "/dev/gpiochip%s" : "/dev/%s", chip);
73*cf5a6c84SAndroid Build Coastguard Worker return xopen(toybuf, O_RDWR);
74*cf5a6c84SAndroid Build Coastguard Worker }
75*cf5a6c84SAndroid Build Coastguard Worker
collect_chips(struct dirtree * node)76*cf5a6c84SAndroid Build Coastguard Worker static int collect_chips(struct dirtree *node)
77*cf5a6c84SAndroid Build Coastguard Worker {
78*cf5a6c84SAndroid Build Coastguard Worker int n;
79*cf5a6c84SAndroid Build Coastguard Worker
80*cf5a6c84SAndroid Build Coastguard Worker if (!node->parent) return DIRTREE_RECURSE; // Skip the directory itself.
81*cf5a6c84SAndroid Build Coastguard Worker
82*cf5a6c84SAndroid Build Coastguard Worker if (sscanf(node->name, "gpiochip%d", &n)!=1) return 0;
83*cf5a6c84SAndroid Build Coastguard Worker
84*cf5a6c84SAndroid Build Coastguard Worker dlist_add(&TT.chips, xstrdup(node->name));
85*cf5a6c84SAndroid Build Coastguard Worker TT.chip_count++;
86*cf5a6c84SAndroid Build Coastguard Worker
87*cf5a6c84SAndroid Build Coastguard Worker return 0;
88*cf5a6c84SAndroid Build Coastguard Worker }
89*cf5a6c84SAndroid Build Coastguard Worker
comparator(const void * a,const void * b)90*cf5a6c84SAndroid Build Coastguard Worker static int comparator(const void *a, const void *b)
91*cf5a6c84SAndroid Build Coastguard Worker {
92*cf5a6c84SAndroid Build Coastguard Worker struct double_list *lhs = *(struct double_list **)a,
93*cf5a6c84SAndroid Build Coastguard Worker *rhs = *(struct double_list **)b;
94*cf5a6c84SAndroid Build Coastguard Worker
95*cf5a6c84SAndroid Build Coastguard Worker return strcmp(lhs->data, rhs->data);
96*cf5a6c84SAndroid Build Coastguard Worker }
97*cf5a6c84SAndroid Build Coastguard Worker
98*cf5a6c84SAndroid Build Coastguard Worker // call cb() in sorted order
foreach_chip(void (* cb)(char * name))99*cf5a6c84SAndroid Build Coastguard Worker static void foreach_chip(void (*cb)(char *name))
100*cf5a6c84SAndroid Build Coastguard Worker {
101*cf5a6c84SAndroid Build Coastguard Worker struct double_list **sorted, *chip;
102*cf5a6c84SAndroid Build Coastguard Worker int i = 0;
103*cf5a6c84SAndroid Build Coastguard Worker
104*cf5a6c84SAndroid Build Coastguard Worker dirtree_flagread("/dev", DIRTREE_SHUTUP, collect_chips);
105*cf5a6c84SAndroid Build Coastguard Worker if (!TT.chips) return;
106*cf5a6c84SAndroid Build Coastguard Worker
107*cf5a6c84SAndroid Build Coastguard Worker sorted = xmalloc(TT.chip_count*sizeof(void *));
108*cf5a6c84SAndroid Build Coastguard Worker for (chip = TT.chips; i<TT.chip_count; chip = chip->next) sorted[i++] = chip;
109*cf5a6c84SAndroid Build Coastguard Worker qsort(sorted, TT.chip_count, sizeof(void *), comparator);
110*cf5a6c84SAndroid Build Coastguard Worker
111*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<TT.chip_count; i++) {
112*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf, "/dev/%s", sorted[i]->data);
113*cf5a6c84SAndroid Build Coastguard Worker cb(toybuf);
114*cf5a6c84SAndroid Build Coastguard Worker }
115*cf5a6c84SAndroid Build Coastguard Worker
116*cf5a6c84SAndroid Build Coastguard Worker free(sorted);
117*cf5a6c84SAndroid Build Coastguard Worker llist_traverse(TT.chips, llist_free_double);
118*cf5a6c84SAndroid Build Coastguard Worker }
119*cf5a6c84SAndroid Build Coastguard Worker
gpiodetect(char * path)120*cf5a6c84SAndroid Build Coastguard Worker static void gpiodetect(char *path)
121*cf5a6c84SAndroid Build Coastguard Worker {
122*cf5a6c84SAndroid Build Coastguard Worker struct gpiochip_info chip;
123*cf5a6c84SAndroid Build Coastguard Worker int fd = xopen(path, O_RDWR);
124*cf5a6c84SAndroid Build Coastguard Worker
125*cf5a6c84SAndroid Build Coastguard Worker xioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip);
126*cf5a6c84SAndroid Build Coastguard Worker close(fd);
127*cf5a6c84SAndroid Build Coastguard Worker
128*cf5a6c84SAndroid Build Coastguard Worker // gpiochip0 [pinctrl-bcm2711] (58 line)
129*cf5a6c84SAndroid Build Coastguard Worker printf("%s [%s] (%u line%s)\n", chip.name, chip.label, chip.lines,
130*cf5a6c84SAndroid Build Coastguard Worker chip.lines==1?"":"s");
131*cf5a6c84SAndroid Build Coastguard Worker }
132*cf5a6c84SAndroid Build Coastguard Worker
gpiodetect_main(void)133*cf5a6c84SAndroid Build Coastguard Worker void gpiodetect_main(void)
134*cf5a6c84SAndroid Build Coastguard Worker {
135*cf5a6c84SAndroid Build Coastguard Worker foreach_chip(gpiodetect);
136*cf5a6c84SAndroid Build Coastguard Worker }
137*cf5a6c84SAndroid Build Coastguard Worker
138*cf5a6c84SAndroid Build Coastguard Worker #define FOR_gpiofind
139*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
140*cf5a6c84SAndroid Build Coastguard Worker
gpiofind(char * path)141*cf5a6c84SAndroid Build Coastguard Worker static void gpiofind(char *path)
142*cf5a6c84SAndroid Build Coastguard Worker {
143*cf5a6c84SAndroid Build Coastguard Worker struct gpiochip_info chip;
144*cf5a6c84SAndroid Build Coastguard Worker struct gpioline_info line;
145*cf5a6c84SAndroid Build Coastguard Worker int fd = xopen(path, O_RDWR);
146*cf5a6c84SAndroid Build Coastguard Worker
147*cf5a6c84SAndroid Build Coastguard Worker xioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip);
148*cf5a6c84SAndroid Build Coastguard Worker
149*cf5a6c84SAndroid Build Coastguard Worker for (line.line_offset=0; line.line_offset<chip.lines; line.line_offset++) {
150*cf5a6c84SAndroid Build Coastguard Worker xioctl(fd, GPIO_GET_LINEINFO_IOCTL, &line);
151*cf5a6c84SAndroid Build Coastguard Worker if (!strcmp(line.name, *toys.optargs)) {
152*cf5a6c84SAndroid Build Coastguard Worker printf("%s %d\n", chip.name, line.line_offset);
153*cf5a6c84SAndroid Build Coastguard Worker break;
154*cf5a6c84SAndroid Build Coastguard Worker }
155*cf5a6c84SAndroid Build Coastguard Worker }
156*cf5a6c84SAndroid Build Coastguard Worker close(fd);
157*cf5a6c84SAndroid Build Coastguard Worker }
158*cf5a6c84SAndroid Build Coastguard Worker
gpiofind_main(void)159*cf5a6c84SAndroid Build Coastguard Worker void gpiofind_main(void)
160*cf5a6c84SAndroid Build Coastguard Worker {
161*cf5a6c84SAndroid Build Coastguard Worker foreach_chip(gpiofind);
162*cf5a6c84SAndroid Build Coastguard Worker }
163*cf5a6c84SAndroid Build Coastguard Worker
164*cf5a6c84SAndroid Build Coastguard Worker #define FOR_gpioinfo
165*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
166*cf5a6c84SAndroid Build Coastguard Worker
gpioinfo_fd(int fd)167*cf5a6c84SAndroid Build Coastguard Worker static void gpioinfo_fd(int fd)
168*cf5a6c84SAndroid Build Coastguard Worker {
169*cf5a6c84SAndroid Build Coastguard Worker struct gpiochip_info chip;
170*cf5a6c84SAndroid Build Coastguard Worker struct gpioline_info line;
171*cf5a6c84SAndroid Build Coastguard Worker
172*cf5a6c84SAndroid Build Coastguard Worker xioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip);
173*cf5a6c84SAndroid Build Coastguard Worker
174*cf5a6c84SAndroid Build Coastguard Worker // gpiochip1 - 8 lines:
175*cf5a6c84SAndroid Build Coastguard Worker printf("%s - %d line%s:\n", chip.name, chip.lines, chip.lines==1?"":"s");
176*cf5a6c84SAndroid Build Coastguard Worker
177*cf5a6c84SAndroid Build Coastguard Worker // line 4: "VDD_SD_IO_SEL" "vdd-sd-io" output active-high [used]
178*cf5a6c84SAndroid Build Coastguard Worker // We use slightly wider columns for the name and consumer; just wide enough
179*cf5a6c84SAndroid Build Coastguard Worker // to show all Raspberry Pi 400 pins without wrapping an 80-column terminal.
180*cf5a6c84SAndroid Build Coastguard Worker for (line.line_offset=0; line.line_offset<chip.lines; line.line_offset++) {
181*cf5a6c84SAndroid Build Coastguard Worker xioctl(fd, GPIO_GET_LINEINFO_IOCTL, &line);
182*cf5a6c84SAndroid Build Coastguard Worker if (*line.name) sprintf(toybuf, "\"%s\"", line.name);
183*cf5a6c84SAndroid Build Coastguard Worker else strcpy(toybuf, "unnamed");
184*cf5a6c84SAndroid Build Coastguard Worker if (*line.consumer) sprintf(toybuf+64, "\"%s\"", line.consumer);
185*cf5a6c84SAndroid Build Coastguard Worker else strcpy(toybuf+64, "unused");
186*cf5a6c84SAndroid Build Coastguard Worker printf("\tline %3d:%18s %18s", line.line_offset, toybuf, toybuf+64);
187*cf5a6c84SAndroid Build Coastguard Worker printf(" %sput", line.flags&GPIOLINE_FLAG_IS_OUT?"out":" in");
188*cf5a6c84SAndroid Build Coastguard Worker printf(" active-%s", line.flags&GPIOLINE_FLAG_ACTIVE_LOW?"low ":"high");
189*cf5a6c84SAndroid Build Coastguard Worker if (line.flags&GPIOLINE_FLAG_KERNEL) printf(" [used]");
190*cf5a6c84SAndroid Build Coastguard Worker printf("\n");
191*cf5a6c84SAndroid Build Coastguard Worker }
192*cf5a6c84SAndroid Build Coastguard Worker
193*cf5a6c84SAndroid Build Coastguard Worker close(fd);
194*cf5a6c84SAndroid Build Coastguard Worker }
195*cf5a6c84SAndroid Build Coastguard Worker
gpioinfo(char * path)196*cf5a6c84SAndroid Build Coastguard Worker static void gpioinfo(char *path)
197*cf5a6c84SAndroid Build Coastguard Worker {
198*cf5a6c84SAndroid Build Coastguard Worker gpioinfo_fd(xopen(path, O_RDWR));
199*cf5a6c84SAndroid Build Coastguard Worker }
200*cf5a6c84SAndroid Build Coastguard Worker
gpioinfo_main(void)201*cf5a6c84SAndroid Build Coastguard Worker void gpioinfo_main(void)
202*cf5a6c84SAndroid Build Coastguard Worker {
203*cf5a6c84SAndroid Build Coastguard Worker int i;
204*cf5a6c84SAndroid Build Coastguard Worker
205*cf5a6c84SAndroid Build Coastguard Worker if (!toys.optc) foreach_chip(gpioinfo);
206*cf5a6c84SAndroid Build Coastguard Worker else for (i = 0; toys.optargs[i];i++) gpioinfo_fd(open_chip(toys.optargs[i]));
207*cf5a6c84SAndroid Build Coastguard Worker }
208*cf5a6c84SAndroid Build Coastguard Worker
209*cf5a6c84SAndroid Build Coastguard Worker #define FOR_gpioget
210*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
211*cf5a6c84SAndroid Build Coastguard Worker
212*cf5a6c84SAndroid Build Coastguard Worker // TODO: half the get/set plumbing same here, maybe collate?
gpioget_main(void)213*cf5a6c84SAndroid Build Coastguard Worker void gpioget_main(void)
214*cf5a6c84SAndroid Build Coastguard Worker {
215*cf5a6c84SAndroid Build Coastguard Worker struct gpiohandle_request req = { .flags = GPIOHANDLE_REQUEST_INPUT };
216*cf5a6c84SAndroid Build Coastguard Worker struct gpiohandle_data data;
217*cf5a6c84SAndroid Build Coastguard Worker struct gpiochip_info chip;
218*cf5a6c84SAndroid Build Coastguard Worker char **args = toys.optargs;
219*cf5a6c84SAndroid Build Coastguard Worker int fd, line;
220*cf5a6c84SAndroid Build Coastguard Worker
221*cf5a6c84SAndroid Build Coastguard Worker fd = open_chip(*args);
222*cf5a6c84SAndroid Build Coastguard Worker xioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip);
223*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(l)) req.flags |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
224*cf5a6c84SAndroid Build Coastguard Worker for (args++; *args; args++, req.lines++) {
225*cf5a6c84SAndroid Build Coastguard Worker if (req.lines >= GPIOHANDLES_MAX) error_exit("too many requests!");
226*cf5a6c84SAndroid Build Coastguard Worker line = atolx_range(*args, 0, chip.lines);
227*cf5a6c84SAndroid Build Coastguard Worker req.lineoffsets[req.lines] = line;
228*cf5a6c84SAndroid Build Coastguard Worker }
229*cf5a6c84SAndroid Build Coastguard Worker xioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
230*cf5a6c84SAndroid Build Coastguard Worker xioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
231*cf5a6c84SAndroid Build Coastguard Worker for (line = 0; line<req.lines; line++)
232*cf5a6c84SAndroid Build Coastguard Worker printf("%s%d", " "+(line<1), data.values[line]);
233*cf5a6c84SAndroid Build Coastguard Worker xputc('\n');
234*cf5a6c84SAndroid Build Coastguard Worker }
235*cf5a6c84SAndroid Build Coastguard Worker
236*cf5a6c84SAndroid Build Coastguard Worker #define FOR_gpioset
237*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
238*cf5a6c84SAndroid Build Coastguard Worker
gpioset_main(void)239*cf5a6c84SAndroid Build Coastguard Worker void gpioset_main(void)
240*cf5a6c84SAndroid Build Coastguard Worker {
241*cf5a6c84SAndroid Build Coastguard Worker struct gpiohandle_request req = { .flags = GPIOHANDLE_REQUEST_OUTPUT };
242*cf5a6c84SAndroid Build Coastguard Worker char **args = toys.optargs;
243*cf5a6c84SAndroid Build Coastguard Worker int fd, value;
244*cf5a6c84SAndroid Build Coastguard Worker
245*cf5a6c84SAndroid Build Coastguard Worker fd = open_chip(*args);
246*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(l)) req.flags |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
247*cf5a6c84SAndroid Build Coastguard Worker for (args++; *args; args++, req.lines++) {
248*cf5a6c84SAndroid Build Coastguard Worker if (req.lines == GPIOHANDLES_MAX) error_exit("too many requests!");
249*cf5a6c84SAndroid Build Coastguard Worker if (sscanf(*args, "%d=%d", req.lineoffsets+req.lines, &value) != 2)
250*cf5a6c84SAndroid Build Coastguard Worker perror_exit("not LINE=VALUE: %s", *args);
251*cf5a6c84SAndroid Build Coastguard Worker req.default_values[req.lines] = value;
252*cf5a6c84SAndroid Build Coastguard Worker }
253*cf5a6c84SAndroid Build Coastguard Worker xioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
254*cf5a6c84SAndroid Build Coastguard Worker }
255