xref: /aosp_15_r20/external/toybox/toys/other/gpiod.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
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