2014-07-01 09:45:15 +04:00
# include <linux/idr.h>
# include <linux/mutex.h>
# include <linux/device.h>
# include <linux/sysfs.h>
# include <linux/gpio/consumer.h>
# include <linux/gpio/driver.h>
# include <linux/interrupt.h>
# include <linux/kdev_t.h>
2015-05-04 18:10:37 +03:00
# include <linux/slab.h>
2014-07-01 09:45:15 +04:00
# include "gpiolib.h"
2015-05-04 18:10:48 +03:00
# define GPIO_IRQF_TRIGGER_FALLING BIT(0)
# define GPIO_IRQF_TRIGGER_RISING BIT(1)
# define GPIO_IRQF_TRIGGER_BOTH (GPIO_IRQF_TRIGGER_FALLING | \
GPIO_IRQF_TRIGGER_RISING )
2015-05-04 18:10:37 +03:00
struct gpiod_data {
struct gpio_desc * desc ;
2015-05-04 18:10:44 +03:00
struct mutex mutex ;
2015-05-04 18:10:39 +03:00
struct kernfs_node * value_kn ;
2015-05-04 18:10:41 +03:00
int irq ;
2015-05-04 18:10:48 +03:00
unsigned char irq_flags ;
2015-05-04 18:10:47 +03:00
bool direction_can_change ;
2015-05-04 18:10:37 +03:00
} ;
2015-05-04 18:10:44 +03:00
/*
* Lock to serialise gpiod export and unexport , and prevent re - export of
* gpiod whose chip is being unregistered .
2014-07-01 09:45:15 +04:00
*/
static DEFINE_MUTEX ( sysfs_lock ) ;
/*
* / sys / class / gpio / gpioN . . . only for GPIOs that are exported
* / direction
* * MAY BE OMITTED if kernel won ' t allow direction changes
* * is read / write as " in " or " out "
* * may also be written as " high " or " low " , initializing
* output value as specified ( " out " implies " low " )
* / value
* * always readable , subject to hardware behavior
* * may be writable , as zero / nonzero
* / edge
* * configures behavior of poll ( 2 ) on / value
* * available only if pin can generate IRQs on input
* * is read / write as " none " , " falling " , " rising " , or " both "
* / active_low
* * configures polarity of / value
* * is read / write as zero / nonzero
* * also affects existing and subsequent " falling " and " rising "
* / edge configuration
*/
2015-05-04 18:10:34 +03:00
static ssize_t direction_show ( struct device * dev ,
2014-07-01 09:45:15 +04:00
struct device_attribute * attr , char * buf )
{
2015-05-04 18:10:37 +03:00
struct gpiod_data * data = dev_get_drvdata ( dev ) ;
struct gpio_desc * desc = data - > desc ;
2014-07-01 09:45:15 +04:00
ssize_t status ;
2015-05-04 18:10:44 +03:00
mutex_lock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:36 +03:00
gpiod_get_direction ( desc ) ;
status = sprintf ( buf , " %s \n " ,
2014-07-01 09:45:15 +04:00
test_bit ( FLAG_IS_OUT , & desc - > flags )
? " out " : " in " ) ;
2015-05-04 18:10:44 +03:00
mutex_unlock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
return status ;
}
2015-05-04 18:10:34 +03:00
static ssize_t direction_store ( struct device * dev ,
2014-07-01 09:45:15 +04:00
struct device_attribute * attr , const char * buf , size_t size )
{
2015-05-04 18:10:37 +03:00
struct gpiod_data * data = dev_get_drvdata ( dev ) ;
struct gpio_desc * desc = data - > desc ;
2014-07-01 09:45:15 +04:00
ssize_t status ;
2015-05-04 18:10:44 +03:00
mutex_lock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:36 +03:00
if ( sysfs_streq ( buf , " high " ) )
2014-07-01 09:45:15 +04:00
status = gpiod_direction_output_raw ( desc , 1 ) ;
else if ( sysfs_streq ( buf , " out " ) | | sysfs_streq ( buf , " low " ) )
status = gpiod_direction_output_raw ( desc , 0 ) ;
else if ( sysfs_streq ( buf , " in " ) )
status = gpiod_direction_input ( desc ) ;
else
status = - EINVAL ;
2015-05-04 18:10:44 +03:00
mutex_unlock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
return status ? : size ;
}
2015-05-04 18:10:34 +03:00
static DEVICE_ATTR_RW ( direction ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:34 +03:00
static ssize_t value_show ( struct device * dev ,
2014-07-01 09:45:15 +04:00
struct device_attribute * attr , char * buf )
{
2015-05-04 18:10:37 +03:00
struct gpiod_data * data = dev_get_drvdata ( dev ) ;
struct gpio_desc * desc = data - > desc ;
2014-07-01 09:45:15 +04:00
ssize_t status ;
2015-05-04 18:10:44 +03:00
mutex_lock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:36 +03:00
status = sprintf ( buf , " %d \n " , gpiod_get_value_cansleep ( desc ) ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:44 +03:00
mutex_unlock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
return status ;
}
2015-05-04 18:10:34 +03:00
static ssize_t value_store ( struct device * dev ,
2014-07-01 09:45:15 +04:00
struct device_attribute * attr , const char * buf , size_t size )
{
2015-05-04 18:10:37 +03:00
struct gpiod_data * data = dev_get_drvdata ( dev ) ;
struct gpio_desc * desc = data - > desc ;
2014-07-01 09:45:15 +04:00
ssize_t status ;
2015-05-04 18:10:44 +03:00
mutex_lock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:36 +03:00
if ( ! test_bit ( FLAG_IS_OUT , & desc - > flags ) ) {
2014-07-01 09:45:15 +04:00
status = - EPERM ;
2015-05-04 18:10:36 +03:00
} else {
2014-07-01 09:45:15 +04:00
long value ;
status = kstrtol ( buf , 0 , & value ) ;
if ( status = = 0 ) {
gpiod_set_value_cansleep ( desc , value ) ;
status = size ;
}
}
2015-05-04 18:10:44 +03:00
mutex_unlock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
return status ;
}
2015-05-04 18:10:34 +03:00
static DEVICE_ATTR_RW ( value ) ;
2014-07-01 09:45:15 +04:00
static irqreturn_t gpio_sysfs_irq ( int irq , void * priv )
{
2015-05-04 18:10:39 +03:00
struct gpiod_data * data = priv ;
sysfs_notify_dirent ( data - > value_kn ) ;
2014-07-01 09:45:15 +04:00
return IRQ_HANDLED ;
}
2015-05-04 18:10:44 +03:00
/* Caller holds gpiod-data mutex. */
2015-05-04 18:10:48 +03:00
static int gpio_sysfs_request_irq ( struct device * dev , unsigned char flags )
2014-07-01 09:45:15 +04:00
{
2015-05-04 18:10:38 +03:00
struct gpiod_data * data = dev_get_drvdata ( dev ) ;
struct gpio_desc * desc = data - > desc ;
2014-07-01 09:45:15 +04:00
unsigned long irq_flags ;
2015-05-04 18:10:41 +03:00
int ret ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:41 +03:00
data - > irq = gpiod_to_irq ( desc ) ;
if ( data - > irq < 0 )
2014-07-01 09:45:15 +04:00
return - EIO ;
2015-05-04 18:10:41 +03:00
data - > value_kn = sysfs_get_dirent ( dev - > kobj . sd , " value " ) ;
if ( ! data - > value_kn )
return - ENODEV ;
2014-07-01 09:45:15 +04:00
irq_flags = IRQF_SHARED ;
2015-05-04 18:10:48 +03:00
if ( flags & GPIO_IRQF_TRIGGER_FALLING )
2014-07-01 09:45:15 +04:00
irq_flags | = test_bit ( FLAG_ACTIVE_LOW , & desc - > flags ) ?
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING ;
2015-05-04 18:10:48 +03:00
if ( flags & GPIO_IRQF_TRIGGER_RISING )
2014-07-01 09:45:15 +04:00
irq_flags | = test_bit ( FLAG_ACTIVE_LOW , & desc - > flags ) ?
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING ;
2015-05-04 18:10:28 +03:00
/*
* FIXME : This should be done in the irq_request_resources callback
* when the irq is requested , but a few drivers currently fail
* to do so .
*
* Remove this redundant call ( along with the corresponding
* unlock ) when those drivers have been fixed .
*/
ret = gpiochip_lock_as_irq ( desc - > chip , gpio_chip_hwgpio ( desc ) ) ;
2014-07-01 09:45:15 +04:00
if ( ret < 0 )
2015-05-04 18:10:41 +03:00
goto err_put_kn ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:41 +03:00
ret = request_any_context_irq ( data - > irq , gpio_sysfs_irq , irq_flags ,
2015-05-04 18:10:39 +03:00
" gpiolib " , data ) ;
2015-05-04 18:10:28 +03:00
if ( ret < 0 )
goto err_unlock ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:48 +03:00
data - > irq_flags = flags ;
2015-05-04 18:10:41 +03:00
2014-07-01 09:45:15 +04:00
return 0 ;
2015-05-04 18:10:28 +03:00
err_unlock :
gpiochip_unlock_as_irq ( desc - > chip , gpio_chip_hwgpio ( desc ) ) ;
2015-05-04 18:10:41 +03:00
err_put_kn :
sysfs_put ( data - > value_kn ) ;
2014-07-01 09:45:15 +04:00
return ret ;
}
2015-05-04 18:10:44 +03:00
/*
* Caller holds gpiod - data mutex ( unless called after class - device
* deregistration ) .
*/
2015-05-04 18:10:41 +03:00
static void gpio_sysfs_free_irq ( struct device * dev )
{
struct gpiod_data * data = dev_get_drvdata ( dev ) ;
struct gpio_desc * desc = data - > desc ;
2015-05-04 18:10:48 +03:00
data - > irq_flags = 0 ;
2015-05-04 18:10:41 +03:00
free_irq ( data - > irq , data ) ;
gpiochip_unlock_as_irq ( desc - > chip , gpio_chip_hwgpio ( desc ) ) ;
sysfs_put ( data - > value_kn ) ;
}
2014-07-01 09:45:15 +04:00
static const struct {
const char * name ;
2015-05-04 18:10:48 +03:00
unsigned char flags ;
2014-07-01 09:45:15 +04:00
} trigger_types [ ] = {
{ " none " , 0 } ,
2015-05-04 18:10:48 +03:00
{ " falling " , GPIO_IRQF_TRIGGER_FALLING } ,
{ " rising " , GPIO_IRQF_TRIGGER_RISING } ,
{ " both " , GPIO_IRQF_TRIGGER_BOTH } ,
2014-07-01 09:45:15 +04:00
} ;
2015-05-04 18:10:34 +03:00
static ssize_t edge_show ( struct device * dev ,
2014-07-01 09:45:15 +04:00
struct device_attribute * attr , char * buf )
{
2015-05-04 18:10:37 +03:00
struct gpiod_data * data = dev_get_drvdata ( dev ) ;
2015-05-04 18:10:36 +03:00
ssize_t status = 0 ;
int i ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:44 +03:00
mutex_lock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:36 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( trigger_types ) ; i + + ) {
2015-05-04 18:10:48 +03:00
if ( data - > irq_flags = = trigger_types [ i ] . flags ) {
2015-05-04 18:10:36 +03:00
status = sprintf ( buf , " %s \n " , trigger_types [ i ] . name ) ;
break ;
}
2014-07-01 09:45:15 +04:00
}
2015-05-04 18:10:44 +03:00
mutex_unlock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
return status ;
}
2015-05-04 18:10:34 +03:00
static ssize_t edge_store ( struct device * dev ,
2014-07-01 09:45:15 +04:00
struct device_attribute * attr , const char * buf , size_t size )
{
2015-05-04 18:10:40 +03:00
struct gpiod_data * data = dev_get_drvdata ( dev ) ;
2015-05-04 18:10:48 +03:00
unsigned char flags ;
2015-05-04 18:10:41 +03:00
ssize_t status = size ;
2015-05-04 18:10:42 +03:00
int i ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:42 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( trigger_types ) ; i + + ) {
2014-07-01 09:45:15 +04:00
if ( sysfs_streq ( trigger_types [ i ] . name , buf ) )
2015-05-04 18:10:42 +03:00
break ;
}
if ( i = = ARRAY_SIZE ( trigger_types ) )
return - EINVAL ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:40 +03:00
flags = trigger_types [ i ] . flags ;
2015-05-04 18:10:44 +03:00
mutex_lock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:48 +03:00
if ( flags = = data - > irq_flags ) {
2015-05-04 18:10:40 +03:00
status = size ;
goto out_unlock ;
}
2015-05-04 18:10:48 +03:00
if ( data - > irq_flags )
2015-05-04 18:10:41 +03:00
gpio_sysfs_free_irq ( dev ) ;
if ( flags ) {
status = gpio_sysfs_request_irq ( dev , flags ) ;
if ( ! status )
status = size ;
}
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:40 +03:00
out_unlock :
2015-05-04 18:10:44 +03:00
mutex_unlock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
return status ;
}
2015-05-04 18:10:34 +03:00
static DEVICE_ATTR_RW ( edge ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:44 +03:00
/* Caller holds gpiod-data mutex. */
2015-05-04 18:10:46 +03:00
static int gpio_sysfs_set_active_low ( struct device * dev , int value )
2014-07-01 09:45:15 +04:00
{
2015-05-04 18:10:38 +03:00
struct gpiod_data * data = dev_get_drvdata ( dev ) ;
struct gpio_desc * desc = data - > desc ;
2014-07-01 09:45:15 +04:00
int status = 0 ;
2015-05-04 18:10:48 +03:00
unsigned int flags = data - > irq_flags ;
2014-07-01 09:45:15 +04:00
if ( ! ! test_bit ( FLAG_ACTIVE_LOW , & desc - > flags ) = = ! ! value )
return 0 ;
if ( value )
set_bit ( FLAG_ACTIVE_LOW , & desc - > flags ) ;
else
clear_bit ( FLAG_ACTIVE_LOW , & desc - > flags ) ;
/* reconfigure poll(2) support if enabled on one edge only */
2015-05-04 18:10:48 +03:00
if ( flags = = GPIO_IRQF_TRIGGER_FALLING | |
flags = = GPIO_IRQF_TRIGGER_RISING ) {
2015-05-04 18:10:41 +03:00
gpio_sysfs_free_irq ( dev ) ;
2015-05-04 18:10:48 +03:00
status = gpio_sysfs_request_irq ( dev , flags ) ;
2014-07-01 09:45:15 +04:00
}
return status ;
}
2015-05-04 18:10:34 +03:00
static ssize_t active_low_show ( struct device * dev ,
2014-07-01 09:45:15 +04:00
struct device_attribute * attr , char * buf )
{
2015-05-04 18:10:37 +03:00
struct gpiod_data * data = dev_get_drvdata ( dev ) ;
struct gpio_desc * desc = data - > desc ;
2014-07-01 09:45:15 +04:00
ssize_t status ;
2015-05-04 18:10:44 +03:00
mutex_lock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:36 +03:00
status = sprintf ( buf , " %d \n " ,
2014-07-01 09:45:15 +04:00
! ! test_bit ( FLAG_ACTIVE_LOW , & desc - > flags ) ) ;
2015-05-04 18:10:44 +03:00
mutex_unlock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
return status ;
}
2015-05-04 18:10:34 +03:00
static ssize_t active_low_store ( struct device * dev ,
2014-07-01 09:45:15 +04:00
struct device_attribute * attr , const char * buf , size_t size )
{
2015-05-04 18:10:44 +03:00
struct gpiod_data * data = dev_get_drvdata ( dev ) ;
2014-07-01 09:45:15 +04:00
ssize_t status ;
2015-05-04 18:10:36 +03:00
long value ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:44 +03:00
mutex_lock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:36 +03:00
status = kstrtol ( buf , 0 , & value ) ;
if ( status = = 0 )
2015-05-04 18:10:46 +03:00
status = gpio_sysfs_set_active_low ( dev , value ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:44 +03:00
mutex_unlock ( & data - > mutex ) ;
2014-07-01 09:45:15 +04:00
return status ? : size ;
}
2015-05-04 18:10:34 +03:00
static DEVICE_ATTR_RW ( active_low ) ;
2014-07-01 09:45:15 +04:00
2015-01-13 15:00:06 +03:00
static umode_t gpio_is_visible ( struct kobject * kobj , struct attribute * attr ,
int n )
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
2015-05-04 18:10:37 +03:00
struct gpiod_data * data = dev_get_drvdata ( dev ) ;
struct gpio_desc * desc = data - > desc ;
2015-01-13 15:00:06 +03:00
umode_t mode = attr - > mode ;
2015-05-04 18:10:47 +03:00
bool show_direction = data - > direction_can_change ;
2015-01-13 15:00:06 +03:00
if ( attr = = & dev_attr_direction . attr ) {
if ( ! show_direction )
mode = 0 ;
} else if ( attr = = & dev_attr_edge . attr ) {
if ( gpiod_to_irq ( desc ) < 0 )
mode = 0 ;
if ( ! show_direction & & test_bit ( FLAG_IS_OUT , & desc - > flags ) )
mode = 0 ;
}
return mode ;
}
2015-01-13 15:00:05 +03:00
static struct attribute * gpio_attrs [ ] = {
2015-01-13 15:00:06 +03:00
& dev_attr_direction . attr ,
& dev_attr_edge . attr ,
2014-07-01 09:45:15 +04:00
& dev_attr_value . attr ,
& dev_attr_active_low . attr ,
NULL ,
} ;
2015-01-13 15:00:06 +03:00
static const struct attribute_group gpio_group = {
. attrs = gpio_attrs ,
. is_visible = gpio_is_visible ,
} ;
static const struct attribute_group * gpio_groups [ ] = {
& gpio_group ,
NULL
} ;
2014-07-01 09:45:15 +04:00
/*
* / sys / class / gpio / gpiochipN /
* / base . . . matching gpio_chip . base ( N )
* / label . . . matching gpio_chip . label
* / ngpio . . . matching gpio_chip . ngpio
*/
2015-05-04 18:10:34 +03:00
static ssize_t base_show ( struct device * dev ,
2014-07-01 09:45:15 +04:00
struct device_attribute * attr , char * buf )
{
const struct gpio_chip * chip = dev_get_drvdata ( dev ) ;
return sprintf ( buf , " %d \n " , chip - > base ) ;
}
2015-05-04 18:10:34 +03:00
static DEVICE_ATTR_RO ( base ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:34 +03:00
static ssize_t label_show ( struct device * dev ,
2014-07-01 09:45:15 +04:00
struct device_attribute * attr , char * buf )
{
const struct gpio_chip * chip = dev_get_drvdata ( dev ) ;
return sprintf ( buf , " %s \n " , chip - > label ? : " " ) ;
}
2015-05-04 18:10:34 +03:00
static DEVICE_ATTR_RO ( label ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:34 +03:00
static ssize_t ngpio_show ( struct device * dev ,
2014-07-01 09:45:15 +04:00
struct device_attribute * attr , char * buf )
{
const struct gpio_chip * chip = dev_get_drvdata ( dev ) ;
return sprintf ( buf , " %u \n " , chip - > ngpio ) ;
}
2015-05-04 18:10:34 +03:00
static DEVICE_ATTR_RO ( ngpio ) ;
2014-07-01 09:45:15 +04:00
2015-01-13 15:00:04 +03:00
static struct attribute * gpiochip_attrs [ ] = {
2014-07-01 09:45:15 +04:00
& dev_attr_base . attr ,
& dev_attr_label . attr ,
& dev_attr_ngpio . attr ,
NULL ,
} ;
2015-01-13 15:00:04 +03:00
ATTRIBUTE_GROUPS ( gpiochip ) ;
2014-07-01 09:45:15 +04:00
/*
* / sys / class / gpio / export . . . write - only
* integer N . . . number of GPIO to export ( full access )
* / sys / class / gpio / unexport . . . write - only
* integer N . . . number of GPIO to unexport
*/
static ssize_t export_store ( struct class * class ,
struct class_attribute * attr ,
const char * buf , size_t len )
{
long gpio ;
struct gpio_desc * desc ;
int status ;
status = kstrtol ( buf , 0 , & gpio ) ;
if ( status < 0 )
goto done ;
desc = gpio_to_desc ( gpio ) ;
/* reject invalid GPIOs */
if ( ! desc ) {
pr_warn ( " %s: invalid GPIO %ld \n " , __func__ , gpio ) ;
return - EINVAL ;
}
/* No extra locking here; FLAG_SYSFS just signifies that the
* request and export were done by on behalf of userspace , so
* they may be undone on its behalf too .
*/
status = gpiod_request ( desc , " sysfs " ) ;
if ( status < 0 ) {
if ( status = = - EPROBE_DEFER )
status = - ENODEV ;
goto done ;
}
status = gpiod_export ( desc , true ) ;
if ( status < 0 )
gpiod_free ( desc ) ;
else
set_bit ( FLAG_SYSFS , & desc - > flags ) ;
done :
if ( status )
pr_debug ( " %s: status %d \n " , __func__ , status ) ;
return status ? : len ;
}
static ssize_t unexport_store ( struct class * class ,
struct class_attribute * attr ,
const char * buf , size_t len )
{
long gpio ;
struct gpio_desc * desc ;
int status ;
status = kstrtol ( buf , 0 , & gpio ) ;
if ( status < 0 )
goto done ;
desc = gpio_to_desc ( gpio ) ;
/* reject bogus commands (gpio_unexport ignores them) */
if ( ! desc ) {
pr_warn ( " %s: invalid GPIO %ld \n " , __func__ , gpio ) ;
return - EINVAL ;
}
status = - EINVAL ;
/* No extra locking here; FLAG_SYSFS just signifies that the
* request and export were done by on behalf of userspace , so
* they may be undone on its behalf too .
*/
if ( test_and_clear_bit ( FLAG_SYSFS , & desc - > flags ) ) {
status = 0 ;
gpiod_free ( desc ) ;
}
done :
if ( status )
pr_debug ( " %s: status %d \n " , __func__ , status ) ;
return status ? : len ;
}
static struct class_attribute gpio_class_attrs [ ] = {
__ATTR ( export , 0200 , NULL , export_store ) ,
__ATTR ( unexport , 0200 , NULL , unexport_store ) ,
__ATTR_NULL ,
} ;
static struct class gpio_class = {
. name = " gpio " ,
. owner = THIS_MODULE ,
. class_attrs = gpio_class_attrs ,
} ;
/**
* gpiod_export - export a GPIO through sysfs
* @ gpio : gpio to make available , already requested
* @ direction_may_change : true if userspace may change gpio direction
* Context : arch_initcall or later
*
* When drivers want to make a GPIO accessible to userspace after they
* have requested it - - perhaps while debugging , or as part of their
* public interface - - they may use this routine . If the GPIO can
* change direction ( some can ' t ) and the caller allows it , userspace
* will see " direction " sysfs attribute which may be used to change
* the gpio ' s direction . A " value " attribute will always be provided .
*
* Returns zero on success , else an error .
*/
int gpiod_export ( struct gpio_desc * desc , bool direction_may_change )
{
2015-04-21 18:42:09 +03:00
struct gpio_chip * chip ;
2015-05-04 18:10:37 +03:00
struct gpiod_data * data ;
2014-07-01 09:45:15 +04:00
unsigned long flags ;
int status ;
const char * ioname = NULL ;
struct device * dev ;
int offset ;
/* can't export until sysfs is available ... */
if ( ! gpio_class . p ) {
pr_debug ( " %s: called too early! \n " , __func__ ) ;
return - ENOENT ;
}
if ( ! desc ) {
pr_debug ( " %s: invalid gpio descriptor \n " , __func__ ) ;
return - EINVAL ;
}
2015-04-21 18:42:09 +03:00
chip = desc - > chip ;
2014-07-01 09:45:15 +04:00
mutex_lock ( & sysfs_lock ) ;
2015-04-21 18:42:09 +03:00
/* check if chip is being removed */
2015-05-04 18:10:31 +03:00
if ( ! chip | | ! chip - > cdev ) {
2015-04-21 18:42:09 +03:00
status = - ENODEV ;
2015-05-04 18:10:37 +03:00
goto err_unlock ;
2015-04-21 18:42:09 +03:00
}
2014-07-01 09:45:15 +04:00
spin_lock_irqsave ( & gpio_lock , flags ) ;
if ( ! test_bit ( FLAG_REQUESTED , & desc - > flags ) | |
test_bit ( FLAG_EXPORT , & desc - > flags ) ) {
spin_unlock_irqrestore ( & gpio_lock , flags ) ;
gpiod_dbg ( desc , " %s: unavailable (requested=%d, exported=%d) \n " ,
__func__ ,
test_bit ( FLAG_REQUESTED , & desc - > flags ) ,
test_bit ( FLAG_EXPORT , & desc - > flags ) ) ;
status = - EPERM ;
2015-05-04 18:10:37 +03:00
goto err_unlock ;
2014-07-01 09:45:15 +04:00
}
spin_unlock_irqrestore ( & gpio_lock , flags ) ;
2015-05-04 18:10:37 +03:00
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data ) {
status = - ENOMEM ;
goto err_unlock ;
}
data - > desc = desc ;
2015-05-04 18:10:44 +03:00
mutex_init ( & data - > mutex ) ;
2015-05-04 18:10:47 +03:00
if ( chip - > direction_input & & chip - > direction_output )
data - > direction_can_change = direction_may_change ;
else
data - > direction_can_change = false ;
2015-05-04 18:10:37 +03:00
2014-07-01 09:45:15 +04:00
offset = gpio_chip_hwgpio ( desc ) ;
2015-05-04 18:10:29 +03:00
if ( chip - > names & & chip - > names [ offset ] )
ioname = chip - > names [ offset ] ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:29 +03:00
dev = device_create_with_groups ( & gpio_class , chip - > dev ,
2015-05-04 18:10:37 +03:00
MKDEV ( 0 , 0 ) , data , gpio_groups ,
2015-01-13 15:00:05 +03:00
ioname ? ioname : " gpio%u " ,
desc_to_gpio ( desc ) ) ;
2014-07-01 09:45:15 +04:00
if ( IS_ERR ( dev ) ) {
status = PTR_ERR ( dev ) ;
2015-05-04 18:10:37 +03:00
goto err_free_data ;
2014-07-01 09:45:15 +04:00
}
set_bit ( FLAG_EXPORT , & desc - > flags ) ;
mutex_unlock ( & sysfs_lock ) ;
return 0 ;
2015-05-04 18:10:37 +03:00
err_free_data :
kfree ( data ) ;
err_unlock :
2014-07-01 09:45:15 +04:00
mutex_unlock ( & sysfs_lock ) ;
gpiod_dbg ( desc , " %s: status %d \n " , __func__ , status ) ;
return status ;
}
EXPORT_SYMBOL_GPL ( gpiod_export ) ;
2015-05-04 18:10:37 +03:00
static int match_export ( struct device * dev , const void * desc )
2014-07-01 09:45:15 +04:00
{
2015-05-04 18:10:37 +03:00
struct gpiod_data * data = dev_get_drvdata ( dev ) ;
return data - > desc = = desc ;
2014-07-01 09:45:15 +04:00
}
/**
* gpiod_export_link - create a sysfs link to an exported GPIO node
* @ dev : device under which to create symlink
* @ name : name of the symlink
* @ gpio : gpio to create symlink to , already exported
*
* Set up a symlink from / sys / . . . / dev / name to / sys / class / gpio / gpioN
* node . Caller is responsible for unlinking .
*
* Returns zero on success , else an error .
*/
int gpiod_export_link ( struct device * dev , const char * name ,
struct gpio_desc * desc )
{
2015-05-04 18:10:43 +03:00
struct device * cdev ;
int ret ;
2014-07-01 09:45:15 +04:00
if ( ! desc ) {
pr_warn ( " %s: invalid GPIO \n " , __func__ ) ;
return - EINVAL ;
}
2015-05-04 18:10:43 +03:00
cdev = class_find_device ( & gpio_class , NULL , desc , match_export ) ;
if ( ! cdev )
return - ENODEV ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:43 +03:00
ret = sysfs_create_link ( & dev - > kobj , & cdev - > kobj , name ) ;
put_device ( cdev ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:43 +03:00
return ret ;
2014-07-01 09:45:15 +04:00
}
EXPORT_SYMBOL_GPL ( gpiod_export_link ) ;
/**
* gpiod_unexport - reverse effect of gpio_export ( )
* @ gpio : gpio to make unavailable
*
* This is implicit on gpio_free ( ) .
*/
void gpiod_unexport ( struct gpio_desc * desc )
{
2015-05-04 18:10:45 +03:00
struct gpiod_data * data ;
struct device * dev ;
2014-07-01 09:45:15 +04:00
if ( ! desc ) {
pr_warn ( " %s: invalid GPIO \n " , __func__ ) ;
return ;
}
mutex_lock ( & sysfs_lock ) ;
2015-05-04 18:10:45 +03:00
if ( ! test_bit ( FLAG_EXPORT , & desc - > flags ) )
goto err_unlock ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:45 +03:00
dev = class_find_device ( & gpio_class , NULL , desc , match_export ) ;
if ( ! dev )
goto err_unlock ;
data = dev_get_drvdata ( dev ) ;
clear_bit ( FLAG_EXPORT , & desc - > flags ) ;
device_unregister ( dev ) ;
/*
* Release irq after deregistration to prevent race with edge_store .
*/
2015-05-04 18:10:48 +03:00
if ( data - > irq_flags )
2015-05-04 18:10:45 +03:00
gpio_sysfs_free_irq ( dev ) ;
2014-07-01 09:45:15 +04:00
mutex_unlock ( & sysfs_lock ) ;
2015-05-04 18:10:45 +03:00
put_device ( dev ) ;
kfree ( data ) ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:45 +03:00
return ;
err_unlock :
mutex_unlock ( & sysfs_lock ) ;
2014-07-01 09:45:15 +04:00
}
EXPORT_SYMBOL_GPL ( gpiod_unexport ) ;
2015-05-04 18:10:32 +03:00
int gpiochip_sysfs_register ( struct gpio_chip * chip )
2014-07-01 09:45:15 +04:00
{
struct device * dev ;
2015-05-04 18:10:32 +03:00
/*
* Many systems add gpio chips for SOC support very early ,
2014-07-01 09:45:15 +04:00
* before driver model support is available . In those cases we
2015-05-04 18:10:32 +03:00
* register later , in gpiolib_sysfs_init ( ) . . . here we just
2014-07-01 09:45:15 +04:00
* verify that _some_ field of gpio_class got initialized .
*/
if ( ! gpio_class . p )
return 0 ;
/* use chip->base for the ID; it's already known to be unique */
2015-01-13 15:00:04 +03:00
dev = device_create_with_groups ( & gpio_class , chip - > dev , MKDEV ( 0 , 0 ) ,
chip , gpiochip_groups ,
" gpiochip%d " , chip - > base ) ;
if ( IS_ERR ( dev ) )
2015-05-04 18:10:31 +03:00
return PTR_ERR ( dev ) ;
2015-05-04 18:10:30 +03:00
mutex_lock ( & sysfs_lock ) ;
2015-05-04 18:10:31 +03:00
chip - > cdev = dev ;
2014-07-01 09:45:15 +04:00
mutex_unlock ( & sysfs_lock ) ;
2015-05-04 18:10:31 +03:00
return 0 ;
2014-07-01 09:45:15 +04:00
}
2015-05-04 18:10:32 +03:00
void gpiochip_sysfs_unregister ( struct gpio_chip * chip )
2014-07-01 09:45:15 +04:00
{
2015-04-21 18:42:09 +03:00
struct gpio_desc * desc ;
unsigned int i ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:31 +03:00
if ( ! chip - > cdev )
return ;
2014-07-01 09:45:15 +04:00
2015-05-04 18:10:31 +03:00
device_unregister ( chip - > cdev ) ;
/* prevent further gpiod exports */
mutex_lock ( & sysfs_lock ) ;
chip - > cdev = NULL ;
mutex_unlock ( & sysfs_lock ) ;
2015-04-21 18:42:09 +03:00
/* unregister gpiod class devices owned by sysfs */
for ( i = 0 ; i < chip - > ngpio ; i + + ) {
desc = & chip - > desc [ i ] ;
if ( test_and_clear_bit ( FLAG_SYSFS , & desc - > flags ) )
gpiod_free ( desc ) ;
}
2014-07-01 09:45:15 +04:00
}
static int __init gpiolib_sysfs_init ( void )
{
int status ;
unsigned long flags ;
struct gpio_chip * chip ;
status = class_register ( & gpio_class ) ;
if ( status < 0 )
return status ;
/* Scan and register the gpio_chips which registered very
* early ( e . g . before the class_register above was called ) .
*
* We run before arch_initcall ( ) so chip - > dev nodes can have
* registered , and so arch_initcall ( ) can always gpio_export ( ) .
*/
spin_lock_irqsave ( & gpio_lock , flags ) ;
list_for_each_entry ( chip , & gpio_chips , list ) {
2015-05-04 18:10:31 +03:00
if ( chip - > cdev )
2014-07-01 09:45:15 +04:00
continue ;
2014-07-22 11:17:40 +04:00
/*
2015-05-04 18:10:32 +03:00
* TODO we yield gpio_lock here because
* gpiochip_sysfs_register ( ) acquires a mutex . This is unsafe
* and needs to be fixed .
2014-07-22 11:17:40 +04:00
*
* Also it would be nice to use gpiochip_find ( ) here so we
* can keep gpio_chips local to gpiolib . c , but the yield of
* gpio_lock prevents us from doing this .
*/
2014-07-01 09:45:15 +04:00
spin_unlock_irqrestore ( & gpio_lock , flags ) ;
2015-05-04 18:10:32 +03:00
status = gpiochip_sysfs_register ( chip ) ;
2014-07-01 09:45:15 +04:00
spin_lock_irqsave ( & gpio_lock , flags ) ;
}
spin_unlock_irqrestore ( & gpio_lock , flags ) ;
return status ;
}
postcore_initcall ( gpiolib_sysfs_init ) ;