18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * GPIO tools - helpers library for the GPIO tools 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2015 Linus Walleij 68c2ecf20Sopenharmony_ci * Copyright (C) 2016 Bamvor Jian Zhang 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <unistd.h> 108c2ecf20Sopenharmony_ci#include <stdlib.h> 118c2ecf20Sopenharmony_ci#include <stdio.h> 128c2ecf20Sopenharmony_ci#include <errno.h> 138c2ecf20Sopenharmony_ci#include <string.h> 148c2ecf20Sopenharmony_ci#include <fcntl.h> 158c2ecf20Sopenharmony_ci#include <getopt.h> 168c2ecf20Sopenharmony_ci#include <sys/ioctl.h> 178c2ecf20Sopenharmony_ci#include <linux/gpio.h> 188c2ecf20Sopenharmony_ci#include "gpio-utils.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define CONSUMER "gpio-utils" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/** 238c2ecf20Sopenharmony_ci * doc: Operation of gpio 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Provide the api of gpiochip for chardev interface. There are two 268c2ecf20Sopenharmony_ci * types of api. The first one provide as same function as each 278c2ecf20Sopenharmony_ci * ioctl, including request and release for lines of gpio, read/write 288c2ecf20Sopenharmony_ci * the value of gpio. If the user want to do lots of read and write of 298c2ecf20Sopenharmony_ci * lines of gpio, user should use this type of api. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * The second one provide the easy to use api for user. Each of the 328c2ecf20Sopenharmony_ci * following api will request gpio lines, do the operation and then 338c2ecf20Sopenharmony_ci * release these lines. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci/** 368c2ecf20Sopenharmony_ci * gpiotools_request_linehandle() - request gpio lines in a gpiochip 378c2ecf20Sopenharmony_ci * @device_name: The name of gpiochip without prefix "/dev/", 388c2ecf20Sopenharmony_ci * such as "gpiochip0" 398c2ecf20Sopenharmony_ci * @lines: An array desired lines, specified by offset 408c2ecf20Sopenharmony_ci * index for the associated GPIO device. 418c2ecf20Sopenharmony_ci * @num_lines: The number of lines to request. 428c2ecf20Sopenharmony_ci * @flag: The new flag for requsted gpio. Reference 438c2ecf20Sopenharmony_ci * "linux/gpio.h" for the meaning of flag. 448c2ecf20Sopenharmony_ci * @data: Default value will be set to gpio when flag is 458c2ecf20Sopenharmony_ci * GPIOHANDLE_REQUEST_OUTPUT. 468c2ecf20Sopenharmony_ci * @consumer_label: The name of consumer, such as "sysfs", 478c2ecf20Sopenharmony_ci * "powerkey". This is useful for other users to 488c2ecf20Sopenharmony_ci * know who is using. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * Request gpio lines through the ioctl provided by chardev. User 518c2ecf20Sopenharmony_ci * could call gpiotools_set_values() and gpiotools_get_values() to 528c2ecf20Sopenharmony_ci * read and write respectively through the returned fd. Call 538c2ecf20Sopenharmony_ci * gpiotools_release_linehandle() to release these lines after that. 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci * Return: On success return the fd; 568c2ecf20Sopenharmony_ci * On failure return the errno. 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_ciint gpiotools_request_linehandle(const char *device_name, unsigned int *lines, 598c2ecf20Sopenharmony_ci unsigned int num_lines, unsigned int flag, 608c2ecf20Sopenharmony_ci struct gpiohandle_data *data, 618c2ecf20Sopenharmony_ci const char *consumer_label) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct gpiohandle_request req; 648c2ecf20Sopenharmony_ci char *chrdev_name; 658c2ecf20Sopenharmony_ci int fd; 668c2ecf20Sopenharmony_ci int i; 678c2ecf20Sopenharmony_ci int ret; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci ret = asprintf(&chrdev_name, "/dev/%s", device_name); 708c2ecf20Sopenharmony_ci if (ret < 0) 718c2ecf20Sopenharmony_ci return -ENOMEM; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci fd = open(chrdev_name, 0); 748c2ecf20Sopenharmony_ci if (fd == -1) { 758c2ecf20Sopenharmony_ci ret = -errno; 768c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to open %s, %s\n", 778c2ecf20Sopenharmony_ci chrdev_name, strerror(errno)); 788c2ecf20Sopenharmony_ci goto exit_free_name; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci for (i = 0; i < num_lines; i++) 828c2ecf20Sopenharmony_ci req.lineoffsets[i] = lines[i]; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci req.flags = flag; 858c2ecf20Sopenharmony_ci strcpy(req.consumer_label, consumer_label); 868c2ecf20Sopenharmony_ci req.lines = num_lines; 878c2ecf20Sopenharmony_ci if (flag & GPIOHANDLE_REQUEST_OUTPUT) 888c2ecf20Sopenharmony_ci memcpy(req.default_values, data, sizeof(req.default_values)); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); 918c2ecf20Sopenharmony_ci if (ret == -1) { 928c2ecf20Sopenharmony_ci ret = -errno; 938c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to issue %s (%d), %s\n", 948c2ecf20Sopenharmony_ci "GPIO_GET_LINEHANDLE_IOCTL", ret, strerror(errno)); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (close(fd) == -1) 988c2ecf20Sopenharmony_ci perror("Failed to close GPIO character device file"); 998c2ecf20Sopenharmony_ciexit_free_name: 1008c2ecf20Sopenharmony_ci free(chrdev_name); 1018c2ecf20Sopenharmony_ci return ret < 0 ? ret : req.fd; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/** 1058c2ecf20Sopenharmony_ci * gpiotools_request_line() - request gpio lines in a gpiochip 1068c2ecf20Sopenharmony_ci * @device_name: The name of gpiochip without prefix "/dev/", 1078c2ecf20Sopenharmony_ci * such as "gpiochip0" 1088c2ecf20Sopenharmony_ci * @lines: An array desired lines, specified by offset 1098c2ecf20Sopenharmony_ci * index for the associated GPIO device. 1108c2ecf20Sopenharmony_ci * @num_lines: The number of lines to request. 1118c2ecf20Sopenharmony_ci * @config: The new config for requested gpio. Reference 1128c2ecf20Sopenharmony_ci * "linux/gpio.h" for config details. 1138c2ecf20Sopenharmony_ci * @consumer: The name of consumer, such as "sysfs", 1148c2ecf20Sopenharmony_ci * "powerkey". This is useful for other users to 1158c2ecf20Sopenharmony_ci * know who is using. 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci * Request gpio lines through the ioctl provided by chardev. User 1188c2ecf20Sopenharmony_ci * could call gpiotools_set_values() and gpiotools_get_values() to 1198c2ecf20Sopenharmony_ci * read and write respectively through the returned fd. Call 1208c2ecf20Sopenharmony_ci * gpiotools_release_line() to release these lines after that. 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * Return: On success return the fd; 1238c2ecf20Sopenharmony_ci * On failure return the errno. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ciint gpiotools_request_line(const char *device_name, unsigned int *lines, 1268c2ecf20Sopenharmony_ci unsigned int num_lines, 1278c2ecf20Sopenharmony_ci struct gpio_v2_line_config *config, 1288c2ecf20Sopenharmony_ci const char *consumer) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct gpio_v2_line_request req; 1318c2ecf20Sopenharmony_ci char *chrdev_name; 1328c2ecf20Sopenharmony_ci int fd; 1338c2ecf20Sopenharmony_ci int i; 1348c2ecf20Sopenharmony_ci int ret; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci ret = asprintf(&chrdev_name, "/dev/%s", device_name); 1378c2ecf20Sopenharmony_ci if (ret < 0) 1388c2ecf20Sopenharmony_ci return -ENOMEM; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci fd = open(chrdev_name, 0); 1418c2ecf20Sopenharmony_ci if (fd == -1) { 1428c2ecf20Sopenharmony_ci ret = -errno; 1438c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to open %s, %s\n", 1448c2ecf20Sopenharmony_ci chrdev_name, strerror(errno)); 1458c2ecf20Sopenharmony_ci goto exit_free_name; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci memset(&req, 0, sizeof(req)); 1498c2ecf20Sopenharmony_ci for (i = 0; i < num_lines; i++) 1508c2ecf20Sopenharmony_ci req.offsets[i] = lines[i]; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci req.config = *config; 1538c2ecf20Sopenharmony_ci strcpy(req.consumer, consumer); 1548c2ecf20Sopenharmony_ci req.num_lines = num_lines; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci ret = ioctl(fd, GPIO_V2_GET_LINE_IOCTL, &req); 1578c2ecf20Sopenharmony_ci if (ret == -1) { 1588c2ecf20Sopenharmony_ci ret = -errno; 1598c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to issue %s (%d), %s\n", 1608c2ecf20Sopenharmony_ci "GPIO_GET_LINE_IOCTL", ret, strerror(errno)); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (close(fd) == -1) 1648c2ecf20Sopenharmony_ci perror("Failed to close GPIO character device file"); 1658c2ecf20Sopenharmony_ciexit_free_name: 1668c2ecf20Sopenharmony_ci free(chrdev_name); 1678c2ecf20Sopenharmony_ci return ret < 0 ? ret : req.fd; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/** 1718c2ecf20Sopenharmony_ci * gpiotools_set_values(): Set the value of gpio(s) 1728c2ecf20Sopenharmony_ci * @fd: The fd returned by 1738c2ecf20Sopenharmony_ci * gpiotools_request_line(). 1748c2ecf20Sopenharmony_ci * @values: The array of values want to set. 1758c2ecf20Sopenharmony_ci * 1768c2ecf20Sopenharmony_ci * Return: On success return 0; 1778c2ecf20Sopenharmony_ci * On failure return the errno. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ciint gpiotools_set_values(const int fd, struct gpio_v2_line_values *values) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci int ret; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci ret = ioctl(fd, GPIO_V2_LINE_SET_VALUES_IOCTL, values); 1848c2ecf20Sopenharmony_ci if (ret == -1) { 1858c2ecf20Sopenharmony_ci ret = -errno; 1868c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to issue %s (%d), %s\n", 1878c2ecf20Sopenharmony_ci "GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret, 1888c2ecf20Sopenharmony_ci strerror(errno)); 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return ret; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/** 1958c2ecf20Sopenharmony_ci * gpiotools_get_values(): Get the value of gpio(s) 1968c2ecf20Sopenharmony_ci * @fd: The fd returned by 1978c2ecf20Sopenharmony_ci * gpiotools_request_line(). 1988c2ecf20Sopenharmony_ci * @values: The array of values get from hardware. 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * Return: On success return 0; 2018c2ecf20Sopenharmony_ci * On failure return the errno. 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_ciint gpiotools_get_values(const int fd, struct gpio_v2_line_values *values) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci int ret; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ret = ioctl(fd, GPIO_V2_LINE_GET_VALUES_IOCTL, values); 2088c2ecf20Sopenharmony_ci if (ret == -1) { 2098c2ecf20Sopenharmony_ci ret = -errno; 2108c2ecf20Sopenharmony_ci fprintf(stderr, "Failed to issue %s (%d), %s\n", 2118c2ecf20Sopenharmony_ci "GPIOHANDLE_GET_LINE_VALUES_IOCTL", ret, 2128c2ecf20Sopenharmony_ci strerror(errno)); 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return ret; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/** 2198c2ecf20Sopenharmony_ci * gpiotools_release_linehandle(): Release the line(s) of gpiochip 2208c2ecf20Sopenharmony_ci * @fd: The fd returned by 2218c2ecf20Sopenharmony_ci * gpiotools_request_linehandle(). 2228c2ecf20Sopenharmony_ci * 2238c2ecf20Sopenharmony_ci * Return: On success return 0; 2248c2ecf20Sopenharmony_ci * On failure return the errno. 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_ciint gpiotools_release_linehandle(const int fd) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci int ret; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci ret = close(fd); 2318c2ecf20Sopenharmony_ci if (ret == -1) { 2328c2ecf20Sopenharmony_ci perror("Failed to close GPIO LINEHANDLE device file"); 2338c2ecf20Sopenharmony_ci ret = -errno; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci return ret; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/** 2408c2ecf20Sopenharmony_ci * gpiotools_release_line(): Release the line(s) of gpiochip 2418c2ecf20Sopenharmony_ci * @fd: The fd returned by 2428c2ecf20Sopenharmony_ci * gpiotools_request_line(). 2438c2ecf20Sopenharmony_ci * 2448c2ecf20Sopenharmony_ci * Return: On success return 0; 2458c2ecf20Sopenharmony_ci * On failure return the errno. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ciint gpiotools_release_line(const int fd) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci int ret; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci ret = close(fd); 2528c2ecf20Sopenharmony_ci if (ret == -1) { 2538c2ecf20Sopenharmony_ci perror("Failed to close GPIO LINE device file"); 2548c2ecf20Sopenharmony_ci ret = -errno; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return ret; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci/** 2618c2ecf20Sopenharmony_ci * gpiotools_get(): Get value from specific line 2628c2ecf20Sopenharmony_ci * @device_name: The name of gpiochip without prefix "/dev/", 2638c2ecf20Sopenharmony_ci * such as "gpiochip0" 2648c2ecf20Sopenharmony_ci * @line: number of line, such as 2. 2658c2ecf20Sopenharmony_ci * 2668c2ecf20Sopenharmony_ci * Return: On success return 0; 2678c2ecf20Sopenharmony_ci * On failure return the errno. 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_ciint gpiotools_get(const char *device_name, unsigned int line) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci int ret; 2728c2ecf20Sopenharmony_ci unsigned int value; 2738c2ecf20Sopenharmony_ci unsigned int lines[] = {line}; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci ret = gpiotools_gets(device_name, lines, 1, &value); 2768c2ecf20Sopenharmony_ci if (ret) 2778c2ecf20Sopenharmony_ci return ret; 2788c2ecf20Sopenharmony_ci return value; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/** 2838c2ecf20Sopenharmony_ci * gpiotools_gets(): Get values from specific lines. 2848c2ecf20Sopenharmony_ci * @device_name: The name of gpiochip without prefix "/dev/", 2858c2ecf20Sopenharmony_ci * such as "gpiochip0". 2868c2ecf20Sopenharmony_ci * @lines: An array desired lines, specified by offset 2878c2ecf20Sopenharmony_ci * index for the associated GPIO device. 2888c2ecf20Sopenharmony_ci * @num_lines: The number of lines to request. 2898c2ecf20Sopenharmony_ci * @values: The array of values get from gpiochip. 2908c2ecf20Sopenharmony_ci * 2918c2ecf20Sopenharmony_ci * Return: On success return 0; 2928c2ecf20Sopenharmony_ci * On failure return the errno. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ciint gpiotools_gets(const char *device_name, unsigned int *lines, 2958c2ecf20Sopenharmony_ci unsigned int num_lines, unsigned int *values) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci int fd, i; 2988c2ecf20Sopenharmony_ci int ret; 2998c2ecf20Sopenharmony_ci int ret_close; 3008c2ecf20Sopenharmony_ci struct gpio_v2_line_config config; 3018c2ecf20Sopenharmony_ci struct gpio_v2_line_values lv; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci memset(&config, 0, sizeof(config)); 3048c2ecf20Sopenharmony_ci config.flags = GPIO_V2_LINE_FLAG_INPUT; 3058c2ecf20Sopenharmony_ci ret = gpiotools_request_line(device_name, lines, num_lines, 3068c2ecf20Sopenharmony_ci &config, CONSUMER); 3078c2ecf20Sopenharmony_ci if (ret < 0) 3088c2ecf20Sopenharmony_ci return ret; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci fd = ret; 3118c2ecf20Sopenharmony_ci for (i = 0; i < num_lines; i++) 3128c2ecf20Sopenharmony_ci gpiotools_set_bit(&lv.mask, i); 3138c2ecf20Sopenharmony_ci ret = gpiotools_get_values(fd, &lv); 3148c2ecf20Sopenharmony_ci if (!ret) 3158c2ecf20Sopenharmony_ci for (i = 0; i < num_lines; i++) 3168c2ecf20Sopenharmony_ci values[i] = gpiotools_test_bit(lv.bits, i); 3178c2ecf20Sopenharmony_ci ret_close = gpiotools_release_line(fd); 3188c2ecf20Sopenharmony_ci return ret < 0 ? ret : ret_close; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/** 3228c2ecf20Sopenharmony_ci * gpiotools_set(): Set value to specific line 3238c2ecf20Sopenharmony_ci * @device_name: The name of gpiochip without prefix "/dev/", 3248c2ecf20Sopenharmony_ci * such as "gpiochip0" 3258c2ecf20Sopenharmony_ci * @line: number of line, such as 2. 3268c2ecf20Sopenharmony_ci * @value: The value of gpio, must be 0(low) or 1(high). 3278c2ecf20Sopenharmony_ci * 3288c2ecf20Sopenharmony_ci * Return: On success return 0; 3298c2ecf20Sopenharmony_ci * On failure return the errno. 3308c2ecf20Sopenharmony_ci */ 3318c2ecf20Sopenharmony_ciint gpiotools_set(const char *device_name, unsigned int line, 3328c2ecf20Sopenharmony_ci unsigned int value) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci unsigned int lines[] = {line}; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci return gpiotools_sets(device_name, lines, 1, &value); 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/** 3408c2ecf20Sopenharmony_ci * gpiotools_sets(): Set values to specific lines. 3418c2ecf20Sopenharmony_ci * @device_name: The name of gpiochip without prefix "/dev/", 3428c2ecf20Sopenharmony_ci * such as "gpiochip0". 3438c2ecf20Sopenharmony_ci * @lines: An array desired lines, specified by offset 3448c2ecf20Sopenharmony_ci * index for the associated GPIO device. 3458c2ecf20Sopenharmony_ci * @num_lines: The number of lines to request. 3468c2ecf20Sopenharmony_ci * @value: The array of values set to gpiochip, must be 3478c2ecf20Sopenharmony_ci * 0(low) or 1(high). 3488c2ecf20Sopenharmony_ci * 3498c2ecf20Sopenharmony_ci * Return: On success return 0; 3508c2ecf20Sopenharmony_ci * On failure return the errno. 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ciint gpiotools_sets(const char *device_name, unsigned int *lines, 3538c2ecf20Sopenharmony_ci unsigned int num_lines, unsigned int *values) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci int ret, i; 3568c2ecf20Sopenharmony_ci struct gpio_v2_line_config config; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci memset(&config, 0, sizeof(config)); 3598c2ecf20Sopenharmony_ci config.flags = GPIO_V2_LINE_FLAG_OUTPUT; 3608c2ecf20Sopenharmony_ci config.num_attrs = 1; 3618c2ecf20Sopenharmony_ci config.attrs[0].attr.id = GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES; 3628c2ecf20Sopenharmony_ci for (i = 0; i < num_lines; i++) { 3638c2ecf20Sopenharmony_ci gpiotools_set_bit(&config.attrs[0].mask, i); 3648c2ecf20Sopenharmony_ci gpiotools_assign_bit(&config.attrs[0].attr.values, 3658c2ecf20Sopenharmony_ci i, values[i]); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci ret = gpiotools_request_line(device_name, lines, num_lines, 3688c2ecf20Sopenharmony_ci &config, CONSUMER); 3698c2ecf20Sopenharmony_ci if (ret < 0) 3708c2ecf20Sopenharmony_ci return ret; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return gpiotools_release_line(ret); 3738c2ecf20Sopenharmony_ci} 374