@ -7,6 +7,7 @@
# include <common.h>
# include <dm.h>
# include <errno.h>
# include <malloc.h>
# include <asm/gpio.h>
# include <linux/ctype.h>
@ -92,24 +93,41 @@ int gpio_lookup_name(const char *name, struct udevice **devp,
* gpio : GPIO number
* label : Name for the requested GPIO
*
* The label is copied and allocated so the caller does not need to keep
* the pointer around .
*
* This function implements the API that ' s compatible with current
* GPIO API used in U - Boot . The request is forwarded to particular
* GPIO driver . Returns 0 on success , negative value on error .
*/
int gpio_request ( unsigned gpio , const char * label )
{
struct gpio_dev_priv * uc_priv ;
unsigned int offset ;
struct udevice * dev ;
char * str ;
int ret ;
ret = gpio_to_device ( gpio , & dev , & offset ) ;
if ( ret )
return ret ;
if ( ! gpio_get_ops ( dev ) - > request )
return 0 ;
uc_priv = dev - > uclass_priv ;
if ( uc_priv - > name [ offset ] )
return - EBUSY ;
str = strdup ( label ) ;
if ( ! str )
return - ENOMEM ;
if ( gpio_get_ops ( dev ) - > request ) {
ret = gpio_get_ops ( dev ) - > request ( dev , offset , label ) ;
if ( ret ) {
free ( str ) ;
return ret ;
}
}
uc_priv - > name [ offset ] = str ;
return gpio_get_ops ( dev ) - > request ( dev , offset , label ) ;
return 0 ;
}
/**
@ -122,6 +140,7 @@ int gpio_request(unsigned gpio, const char *label)
*/
int gpio_free ( unsigned gpio )
{
struct gpio_dev_priv * uc_priv ;
unsigned int offset ;
struct udevice * dev ;
int ret ;
@ -130,9 +149,34 @@ int gpio_free(unsigned gpio)
if ( ret )
return ret ;
if ( ! gpio_get_ops ( dev ) - > free )
return 0 ;
return gpio_get_ops ( dev ) - > free ( dev , offset ) ;
uc_priv = dev - > uclass_priv ;
if ( ! uc_priv - > name [ offset ] )
return - ENXIO ;
if ( gpio_get_ops ( dev ) - > free ) {
ret = gpio_get_ops ( dev ) - > free ( dev , offset ) ;
if ( ret )
return ret ;
}
free ( uc_priv - > name [ offset ] ) ;
uc_priv - > name [ offset ] = NULL ;
return 0 ;
}
static int check_reserved ( struct udevice * dev , unsigned offset ,
const char * func )
{
struct gpio_dev_priv * uc_priv = dev - > uclass_priv ;
if ( ! uc_priv - > name [ offset ] ) {
printf ( " %s: %s: error: gpio %s%d not reserved \n " ,
dev - > name , func ,
uc_priv - > bank_name ? uc_priv - > bank_name : " " , offset ) ;
return - EBUSY ;
}
return 0 ;
}
/**
@ -152,8 +196,9 @@ int gpio_direction_input(unsigned gpio)
ret = gpio_to_device ( gpio , & dev , & offset ) ;
if ( ret )
return ret ;
ret = check_reserved ( dev , offset , " dir_input " ) ;
return gpio_get_ops ( dev ) - > direction_input ( dev , offset ) ;
return ret ? ret : gpio_get_ops ( dev ) - > direction_input ( dev , offset ) ;
}
/**
@ -174,8 +219,10 @@ int gpio_direction_output(unsigned gpio, int value)
ret = gpio_to_device ( gpio , & dev , & offset ) ;
if ( ret )
return ret ;
ret = check_reserved ( dev , offset , " dir_output " ) ;
return gpio_get_ops ( dev ) - > direction_output ( dev , offset , value ) ;
return ret ? ret :
gpio_get_ops ( dev ) - > direction_output ( dev , offset , value ) ;
}
/**
@ -196,8 +243,9 @@ int gpio_get_value(unsigned gpio)
ret = gpio_to_device ( gpio , & dev , & offset ) ;
if ( ret )
return ret ;
ret = check_reserved ( dev , offset , " get_value " ) ;
return gpio_get_ops ( dev ) - > get_value ( dev , offset ) ;
return ret ? ret : gpio_get_ops ( dev ) - > get_value ( dev , offset ) ;
}
/**
@ -218,8 +266,9 @@ int gpio_set_value(unsigned gpio, int value)
ret = gpio_to_device ( gpio , & dev , & offset ) ;
if ( ret )
return ret ;
ret = check_reserved ( dev , offset , " set_value " ) ;
return gpio_get_ops ( dev ) - > set_value ( dev , offset , value ) ;
return ret ? ret : gpio_get_ops ( dev ) - > set_value ( dev , offset , value ) ;
}
const char * gpio_get_bank_info ( struct udevice * dev , int * bit_count )
@ -235,7 +284,7 @@ const char *gpio_get_bank_info(struct udevice *dev, int *bit_count)
}
/* We need to renumber the GPIOs when any driver is probed/removed */
static int gpio_renumber ( void )
static int gpio_renumber ( struct udevice * removed_dev )
{
struct gpio_dev_priv * uc_priv ;
struct udevice * dev ;
@ -250,7 +299,7 @@ static int gpio_renumber(void)
/* Ensure that we have a base for each bank */
base = 0 ;
uclass_foreach_dev ( dev , uc ) {
if ( device_active ( dev ) ) {
if ( device_active ( dev ) & & dev ! = removed_dev ) {
uc_priv = dev - > uclass_priv ;
uc_priv - > gpio_base = base ;
base + = uc_priv - > gpio_count ;
@ -262,12 +311,27 @@ static int gpio_renumber(void)
static int gpio_post_probe ( struct udevice * dev )
{
return gpio_renumber ( ) ;
struct gpio_dev_priv * uc_priv = dev - > uclass_priv ;
uc_priv - > name = calloc ( uc_priv - > gpio_count , sizeof ( char * ) ) ;
if ( ! uc_priv - > name )
return - ENOMEM ;
return gpio_renumber ( NULL ) ;
}
static int gpio_pre_remove ( struct udevice * dev )
{
return gpio_renumber ( ) ;
struct gpio_dev_priv * uc_priv = dev - > uclass_priv ;
int i ;
for ( i = 0 ; i < uc_priv - > gpio_count ; i + + ) {
if ( uc_priv - > name [ i ] )
free ( uc_priv - > name [ i ] ) ;
}
free ( uc_priv - > name ) ;
return gpio_renumber ( dev ) ;
}
UCLASS_DRIVER ( gpio ) = {