2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2015-10-21 16:45:54 +03:00
/*
* GPIO tools - helpers library for the GPIO tools
*
* Copyright ( C ) 2015 Linus Walleij
2016-10-14 05:48:25 +03:00
* Copyright ( C ) 2016 Bamvor Jian Zhang
2015-10-21 16:45:54 +03:00
*/
2016-10-14 05:48:25 +03:00
# include <unistd.h>
# include <stdlib.h>
# include <stdio.h>
# include <errno.h>
# include <string.h>
# include <fcntl.h>
# include <getopt.h>
# include <sys/ioctl.h>
# include <linux/gpio.h>
2015-10-21 16:45:54 +03:00
# include "gpio-utils.h"
2016-10-14 05:48:25 +03:00
2020-03-22 13:10:17 +03:00
# define CONSUMER "gpio-utils"
2016-10-14 05:48:25 +03:00
/**
2021-03-25 20:55:36 +03:00
* DOC : Operation of gpio
2016-10-14 05:48:25 +03:00
*
* Provide the api of gpiochip for chardev interface . There are two
* types of api . The first one provide as same function as each
* ioctl , including request and release for lines of gpio , read / write
* the value of gpio . If the user want to do lots of read and write of
* lines of gpio , user should use this type of api .
*
* The second one provide the easy to use api for user . Each of the
* following api will request gpio lines , do the operation and then
* release these lines .
*/
2020-09-28 03:28:04 +03:00
/**
* gpiotools_request_line ( ) - request gpio lines in a gpiochip
* @ device_name : The name of gpiochip without prefix " /dev/ " ,
* such as " gpiochip0 "
* @ lines : An array desired lines , specified by offset
* index for the associated GPIO device .
* @ num_lines : The number of lines to request .
* @ config : The new config for requested gpio . Reference
* " linux/gpio.h " for config details .
* @ consumer : The name of consumer , such as " sysfs " ,
* " powerkey " . This is useful for other users to
* know who is using .
*
* Request gpio lines through the ioctl provided by chardev . User
* could call gpiotools_set_values ( ) and gpiotools_get_values ( ) to
* read and write respectively through the returned fd . Call
* gpiotools_release_line ( ) to release these lines after that .
*
* Return : On success return the fd ;
* On failure return the errno .
*/
int gpiotools_request_line ( const char * device_name , unsigned int * lines ,
unsigned int num_lines ,
struct gpio_v2_line_config * config ,
const char * consumer )
{
struct gpio_v2_line_request req ;
char * chrdev_name ;
int fd ;
int i ;
int ret ;
ret = asprintf ( & chrdev_name , " /dev/%s " , device_name ) ;
if ( ret < 0 )
return - ENOMEM ;
fd = open ( chrdev_name , 0 ) ;
if ( fd = = - 1 ) {
ret = - errno ;
fprintf ( stderr , " Failed to open %s, %s \n " ,
chrdev_name , strerror ( errno ) ) ;
goto exit_free_name ;
}
memset ( & req , 0 , sizeof ( req ) ) ;
for ( i = 0 ; i < num_lines ; i + + )
req . offsets [ i ] = lines [ i ] ;
req . config = * config ;
strcpy ( req . consumer , consumer ) ;
req . num_lines = num_lines ;
ret = ioctl ( fd , GPIO_V2_GET_LINE_IOCTL , & req ) ;
if ( ret = = - 1 ) {
ret = - errno ;
fprintf ( stderr , " Failed to issue %s (%d), %s \n " ,
" GPIO_GET_LINE_IOCTL " , ret , strerror ( errno ) ) ;
}
if ( close ( fd ) = = - 1 )
perror ( " Failed to close GPIO character device file " ) ;
exit_free_name :
free ( chrdev_name ) ;
return ret < 0 ? ret : req . fd ;
}
2016-10-14 05:48:25 +03:00
/**
2021-03-25 20:55:36 +03:00
* gpiotools_set_values ( ) - Set the value of gpio ( s )
2016-10-14 05:48:25 +03:00
* @ fd : The fd returned by
2020-09-28 03:28:04 +03:00
* gpiotools_request_line ( ) .
* @ values : The array of values want to set .
2016-10-14 05:48:25 +03:00
*
* Return : On success return 0 ;
* On failure return the errno .
*/
2020-09-28 03:28:04 +03:00
int gpiotools_set_values ( const int fd , struct gpio_v2_line_values * values )
2016-10-14 05:48:25 +03:00
{
int ret ;
2020-09-28 03:28:04 +03:00
ret = ioctl ( fd , GPIO_V2_LINE_SET_VALUES_IOCTL , values ) ;
2016-10-14 05:48:25 +03:00
if ( ret = = - 1 ) {
ret = - errno ;
2017-09-28 16:01:44 +03:00
fprintf ( stderr , " Failed to issue %s (%d), %s \n " ,
" GPIOHANDLE_SET_LINE_VALUES_IOCTL " , ret ,
strerror ( errno ) ) ;
2016-10-14 05:48:25 +03:00
}
return ret ;
}
/**
2021-03-25 20:55:36 +03:00
* gpiotools_get_values ( ) - Get the value of gpio ( s )
2016-10-14 05:48:25 +03:00
* @ fd : The fd returned by
2020-09-28 03:28:04 +03:00
* gpiotools_request_line ( ) .
* @ values : The array of values get from hardware .
2016-10-14 05:48:25 +03:00
*
* Return : On success return 0 ;
* On failure return the errno .
*/
2020-09-28 03:28:04 +03:00
int gpiotools_get_values ( const int fd , struct gpio_v2_line_values * values )
2016-10-14 05:48:25 +03:00
{
int ret ;
2020-09-28 03:28:04 +03:00
ret = ioctl ( fd , GPIO_V2_LINE_GET_VALUES_IOCTL , values ) ;
2016-10-14 05:48:25 +03:00
if ( ret = = - 1 ) {
ret = - errno ;
2017-09-28 16:01:44 +03:00
fprintf ( stderr , " Failed to issue %s (%d), %s \n " ,
" GPIOHANDLE_GET_LINE_VALUES_IOCTL " , ret ,
strerror ( errno ) ) ;
2016-10-14 05:48:25 +03:00
}
return ret ;
}
2020-09-28 03:28:04 +03:00
/**
2021-03-25 20:55:36 +03:00
* gpiotools_release_line ( ) - Release the line ( s ) of gpiochip
2020-09-28 03:28:04 +03:00
* @ fd : The fd returned by
* gpiotools_request_line ( ) .
*
* Return : On success return 0 ;
* On failure return the errno .
*/
int gpiotools_release_line ( const int fd )
{
int ret ;
ret = close ( fd ) ;
if ( ret = = - 1 ) {
perror ( " Failed to close GPIO LINE device file " ) ;
ret = - errno ;
}
return ret ;
}
2016-10-14 05:48:25 +03:00
/**
2021-03-25 20:55:36 +03:00
* gpiotools_get ( ) - Get value from specific line
2016-10-14 05:48:25 +03:00
* @ device_name : The name of gpiochip without prefix " /dev/ " ,
* such as " gpiochip0 "
* @ line : number of line , such as 2.
*
* Return : On success return 0 ;
* On failure return the errno .
*/
int gpiotools_get ( const char * device_name , unsigned int line )
{
2020-09-28 03:28:04 +03:00
int ret ;
unsigned int value ;
2016-10-14 05:48:25 +03:00
unsigned int lines [ ] = { line } ;
2020-09-28 03:28:04 +03:00
ret = gpiotools_gets ( device_name , lines , 1 , & value ) ;
if ( ret )
return ret ;
return value ;
2016-10-14 05:48:25 +03:00
}
/**
2021-03-25 20:55:36 +03:00
* gpiotools_gets ( ) - Get values from specific lines .
2016-10-14 05:48:25 +03:00
* @ device_name : The name of gpiochip without prefix " /dev/ " ,
* such as " gpiochip0 " .
* @ lines : An array desired lines , specified by offset
* index for the associated GPIO device .
2020-09-28 03:28:03 +03:00
* @ num_lines : The number of lines to request .
2020-09-28 03:28:04 +03:00
* @ values : The array of values get from gpiochip .
2016-10-14 05:48:25 +03:00
*
* Return : On success return 0 ;
* On failure return the errno .
*/
int gpiotools_gets ( const char * device_name , unsigned int * lines ,
2020-09-28 03:28:04 +03:00
unsigned int num_lines , unsigned int * values )
2016-10-14 05:48:25 +03:00
{
2020-09-28 03:28:04 +03:00
int fd , i ;
2016-10-14 05:48:25 +03:00
int ret ;
int ret_close ;
2020-09-28 03:28:04 +03:00
struct gpio_v2_line_config config ;
struct gpio_v2_line_values lv ;
2016-10-14 05:48:25 +03:00
2020-09-28 03:28:04 +03:00
memset ( & config , 0 , sizeof ( config ) ) ;
config . flags = GPIO_V2_LINE_FLAG_INPUT ;
ret = gpiotools_request_line ( device_name , lines , num_lines ,
& config , CONSUMER ) ;
2016-10-14 05:48:25 +03:00
if ( ret < 0 )
return ret ;
fd = ret ;
2020-09-28 03:28:04 +03:00
for ( i = 0 ; i < num_lines ; i + + )
gpiotools_set_bit ( & lv . mask , i ) ;
ret = gpiotools_get_values ( fd , & lv ) ;
if ( ! ret )
for ( i = 0 ; i < num_lines ; i + + )
values [ i ] = gpiotools_test_bit ( lv . bits , i ) ;
ret_close = gpiotools_release_line ( fd ) ;
2016-10-14 05:48:25 +03:00
return ret < 0 ? ret : ret_close ;
}
/**
2021-03-25 20:55:36 +03:00
* gpiotools_set ( ) - Set value to specific line
2016-10-14 05:48:25 +03:00
* @ device_name : The name of gpiochip without prefix " /dev/ " ,
* such as " gpiochip0 "
* @ line : number of line , such as 2.
* @ value : The value of gpio , must be 0 ( low ) or 1 ( high ) .
*
* Return : On success return 0 ;
* On failure return the errno .
*/
int gpiotools_set ( const char * device_name , unsigned int line ,
unsigned int value )
{
unsigned int lines [ ] = { line } ;
2020-09-28 03:28:04 +03:00
return gpiotools_sets ( device_name , lines , 1 , & value ) ;
2016-10-14 05:48:25 +03:00
}
/**
2021-03-25 20:55:36 +03:00
* gpiotools_sets ( ) - Set values to specific lines .
2016-10-14 05:48:25 +03:00
* @ device_name : The name of gpiochip without prefix " /dev/ " ,
* such as " gpiochip0 " .
* @ lines : An array desired lines , specified by offset
* index for the associated GPIO device .
2020-09-28 03:28:03 +03:00
* @ num_lines : The number of lines to request .
2021-03-25 20:55:36 +03:00
* @ values : The array of values set to gpiochip , must be
2016-10-14 05:48:25 +03:00
* 0 ( low ) or 1 ( high ) .
*
* Return : On success return 0 ;
* On failure return the errno .
*/
int gpiotools_sets ( const char * device_name , unsigned int * lines ,
2020-09-28 03:28:04 +03:00
unsigned int num_lines , unsigned int * values )
2016-10-14 05:48:25 +03:00
{
2020-09-28 03:28:04 +03:00
int ret , i ;
struct gpio_v2_line_config config ;
2016-10-14 05:48:25 +03:00
2020-09-28 03:28:04 +03:00
memset ( & config , 0 , sizeof ( config ) ) ;
config . flags = GPIO_V2_LINE_FLAG_OUTPUT ;
config . num_attrs = 1 ;
config . attrs [ 0 ] . attr . id = GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES ;
for ( i = 0 ; i < num_lines ; i + + ) {
gpiotools_set_bit ( & config . attrs [ 0 ] . mask , i ) ;
gpiotools_assign_bit ( & config . attrs [ 0 ] . attr . values ,
i , values [ i ] ) ;
}
ret = gpiotools_request_line ( device_name , lines , num_lines ,
& config , CONSUMER ) ;
2016-10-14 05:48:25 +03:00
if ( ret < 0 )
return ret ;
2020-09-28 03:28:04 +03:00
return gpiotools_release_line ( ret ) ;
2016-10-14 05:48:25 +03:00
}