1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * GPIO tools - helpers library for the GPIO tools 4 * 5 * Copyright (C) 2015 Linus Walleij 6 * Copyright (C) 2016 Bamvor Jian Zhang 7 */ 8 9 #include <unistd.h> 10 #include <stdlib.h> 11 #include <stdio.h> 12 #include <errno.h> 13 #include <string.h> 14 #include <fcntl.h> 15 #include <getopt.h> 16 #include <sys/ioctl.h> 17 #include <linux/gpio.h> 18 #include "gpio-utils.h" 19 20 #define CONSUMER "gpio-utils" 21 22 /** 23 * doc: Operation of gpio 24 * 25 * Provide the api of gpiochip for chardev interface. There are two 26 * types of api. The first one provide as same function as each 27 * ioctl, including request and release for lines of gpio, read/write 28 * the value of gpio. If the user want to do lots of read and write of 29 * lines of gpio, user should use this type of api. 30 * 31 * The second one provide the easy to use api for user. Each of the 32 * following api will request gpio lines, do the operation and then 33 * release these lines. 34 */ 35 36 /** 37 * gpiotools_request_line() - request gpio lines in a gpiochip 38 * @device_name: The name of gpiochip without prefix "/dev/", 39 * such as "gpiochip0" 40 * @lines: An array desired lines, specified by offset 41 * index for the associated GPIO device. 42 * @num_lines: The number of lines to request. 43 * @config: The new config for requested gpio. Reference 44 * "linux/gpio.h" for config details. 45 * @consumer: The name of consumer, such as "sysfs", 46 * "powerkey". This is useful for other users to 47 * know who is using. 48 * 49 * Request gpio lines through the ioctl provided by chardev. User 50 * could call gpiotools_set_values() and gpiotools_get_values() to 51 * read and write respectively through the returned fd. Call 52 * gpiotools_release_line() to release these lines after that. 53 * 54 * Return: On success return the fd; 55 * On failure return the errno. 56 */ 57 int gpiotools_request_line(const char *device_name, unsigned int *lines, 58 unsigned int num_lines, 59 struct gpio_v2_line_config *config, 60 const char *consumer) 61 { 62 struct gpio_v2_line_request req; 63 char *chrdev_name; 64 int fd; 65 int i; 66 int ret; 67 68 ret = asprintf(&chrdev_name, "/dev/%s", device_name); 69 if (ret < 0) 70 return -ENOMEM; 71 72 fd = open(chrdev_name, 0); 73 if (fd == -1) { 74 ret = -errno; 75 fprintf(stderr, "Failed to open %s, %s\n", 76 chrdev_name, strerror(errno)); 77 goto exit_free_name; 78 } 79 80 memset(&req, 0, sizeof(req)); 81 for (i = 0; i < num_lines; i++) 82 req.offsets[i] = lines[i]; 83 84 req.config = *config; 85 strcpy(req.consumer, consumer); 86 req.num_lines = num_lines; 87 88 ret = ioctl(fd, GPIO_V2_GET_LINE_IOCTL, &req); 89 if (ret == -1) { 90 ret = -errno; 91 fprintf(stderr, "Failed to issue %s (%d), %s\n", 92 "GPIO_GET_LINE_IOCTL", ret, strerror(errno)); 93 } 94 95 if (close(fd) == -1) 96 perror("Failed to close GPIO character device file"); 97 exit_free_name: 98 free(chrdev_name); 99 return ret < 0 ? ret : req.fd; 100 } 101 102 /** 103 * gpiotools_set_values(): Set the value of gpio(s) 104 * @fd: The fd returned by 105 * gpiotools_request_line(). 106 * @values: The array of values want to set. 107 * 108 * Return: On success return 0; 109 * On failure return the errno. 110 */ 111 int gpiotools_set_values(const int fd, struct gpio_v2_line_values *values) 112 { 113 int ret; 114 115 ret = ioctl(fd, GPIO_V2_LINE_SET_VALUES_IOCTL, values); 116 if (ret == -1) { 117 ret = -errno; 118 fprintf(stderr, "Failed to issue %s (%d), %s\n", 119 "GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret, 120 strerror(errno)); 121 } 122 123 return ret; 124 } 125 126 /** 127 * gpiotools_get_values(): Get the value of gpio(s) 128 * @fd: The fd returned by 129 * gpiotools_request_line(). 130 * @values: The array of values get from hardware. 131 * 132 * Return: On success return 0; 133 * On failure return the errno. 134 */ 135 int gpiotools_get_values(const int fd, struct gpio_v2_line_values *values) 136 { 137 int ret; 138 139 ret = ioctl(fd, GPIO_V2_LINE_GET_VALUES_IOCTL, values); 140 if (ret == -1) { 141 ret = -errno; 142 fprintf(stderr, "Failed to issue %s (%d), %s\n", 143 "GPIOHANDLE_GET_LINE_VALUES_IOCTL", ret, 144 strerror(errno)); 145 } 146 147 return ret; 148 } 149 150 /** 151 * gpiotools_release_line(): Release the line(s) of gpiochip 152 * @fd: The fd returned by 153 * gpiotools_request_line(). 154 * 155 * Return: On success return 0; 156 * On failure return the errno. 157 */ 158 int gpiotools_release_line(const int fd) 159 { 160 int ret; 161 162 ret = close(fd); 163 if (ret == -1) { 164 perror("Failed to close GPIO LINE device file"); 165 ret = -errno; 166 } 167 168 return ret; 169 } 170 171 /** 172 * gpiotools_get(): Get value from specific line 173 * @device_name: The name of gpiochip without prefix "/dev/", 174 * such as "gpiochip0" 175 * @line: number of line, such as 2. 176 * 177 * Return: On success return 0; 178 * On failure return the errno. 179 */ 180 int gpiotools_get(const char *device_name, unsigned int line) 181 { 182 int ret; 183 unsigned int value; 184 unsigned int lines[] = {line}; 185 186 ret = gpiotools_gets(device_name, lines, 1, &value); 187 if (ret) 188 return ret; 189 return value; 190 } 191 192 193 /** 194 * gpiotools_gets(): Get values from specific lines. 195 * @device_name: The name of gpiochip without prefix "/dev/", 196 * such as "gpiochip0". 197 * @lines: An array desired lines, specified by offset 198 * index for the associated GPIO device. 199 * @num_lines: The number of lines to request. 200 * @values: The array of values get from gpiochip. 201 * 202 * Return: On success return 0; 203 * On failure return the errno. 204 */ 205 int gpiotools_gets(const char *device_name, unsigned int *lines, 206 unsigned int num_lines, unsigned int *values) 207 { 208 int fd, i; 209 int ret; 210 int ret_close; 211 struct gpio_v2_line_config config; 212 struct gpio_v2_line_values lv; 213 214 memset(&config, 0, sizeof(config)); 215 config.flags = GPIO_V2_LINE_FLAG_INPUT; 216 ret = gpiotools_request_line(device_name, lines, num_lines, 217 &config, CONSUMER); 218 if (ret < 0) 219 return ret; 220 221 fd = ret; 222 for (i = 0; i < num_lines; i++) 223 gpiotools_set_bit(&lv.mask, i); 224 ret = gpiotools_get_values(fd, &lv); 225 if (!ret) 226 for (i = 0; i < num_lines; i++) 227 values[i] = gpiotools_test_bit(lv.bits, i); 228 ret_close = gpiotools_release_line(fd); 229 return ret < 0 ? ret : ret_close; 230 } 231 232 /** 233 * gpiotools_set(): Set value to specific line 234 * @device_name: The name of gpiochip without prefix "/dev/", 235 * such as "gpiochip0" 236 * @line: number of line, such as 2. 237 * @value: The value of gpio, must be 0(low) or 1(high). 238 * 239 * Return: On success return 0; 240 * On failure return the errno. 241 */ 242 int gpiotools_set(const char *device_name, unsigned int line, 243 unsigned int value) 244 { 245 unsigned int lines[] = {line}; 246 247 return gpiotools_sets(device_name, lines, 1, &value); 248 } 249 250 /** 251 * gpiotools_sets(): Set values to specific lines. 252 * @device_name: The name of gpiochip without prefix "/dev/", 253 * such as "gpiochip0". 254 * @lines: An array desired lines, specified by offset 255 * index for the associated GPIO device. 256 * @num_lines: The number of lines to request. 257 * @value: The array of values set to gpiochip, must be 258 * 0(low) or 1(high). 259 * 260 * Return: On success return 0; 261 * On failure return the errno. 262 */ 263 int gpiotools_sets(const char *device_name, unsigned int *lines, 264 unsigned int num_lines, unsigned int *values) 265 { 266 int ret, i; 267 struct gpio_v2_line_config config; 268 269 memset(&config, 0, sizeof(config)); 270 config.flags = GPIO_V2_LINE_FLAG_OUTPUT; 271 config.num_attrs = 1; 272 config.attrs[0].attr.id = GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES; 273 for (i = 0; i < num_lines; i++) { 274 gpiotools_set_bit(&config.attrs[0].mask, i); 275 gpiotools_assign_bit(&config.attrs[0].attr.values, 276 i, values[i]); 277 } 278 ret = gpiotools_request_line(device_name, lines, num_lines, 279 &config, CONSUMER); 280 if (ret < 0) 281 return ret; 282 283 return gpiotools_release_line(ret); 284 } 285