@ -19,6 +19,7 @@
* Written by Juha Yrjölä < juha . yrjola @ nokia . com >
*/
# include <common.h>
# include <dm.h>
# include <asm/gpio.h>
# include <asm/io.h>
# include <asm/errno.h>
@ -26,6 +27,20 @@
# define OMAP_GPIO_DIR_OUT 0
# define OMAP_GPIO_DIR_IN 1
# ifdef CONFIG_DM_GPIO
# define GPIO_NAME_SIZE 20
# define GPIO_PER_BANK 32
struct gpio_bank {
char label [ GPIO_PER_BANK ] [ GPIO_NAME_SIZE ] ;
/* TODO(sjg@chromium.org): Can we use a struct here? */
void * base ; /* address of registers in physical memory */
enum gpio_method method ;
} ;
# endif
static inline int get_gpio_index ( int gpio )
{
return gpio & 0x1f ;
@ -130,6 +145,8 @@ static int _get_gpio_value(const struct gpio_bank *bank, int gpio)
return ( __raw_readl ( reg ) & ( 1 < < gpio ) ) ! = 0 ;
}
# ifndef CONFIG_DM_GPIO
static inline const struct gpio_bank * get_gpio_bank ( int gpio )
{
return & omap_gpio_bank [ gpio > > 5 ] ;
@ -226,3 +243,207 @@ int gpio_free(unsigned gpio)
{
return 0 ;
}
# else /* new driver model interface CONFIG_DM_GPIO */
/**
* gpio_is_requested ( ) - check if a GPIO has been requested
*
* @ bank : Bank to check
* @ offset : GPIO offset within bank to check
* @ return true if marked as requested , false if not
*/
static inline bool gpio_is_requested ( struct gpio_bank * bank , int offset )
{
return * bank - > label [ offset ] ! = ' \0 ' ;
}
static int omap_gpio_is_output ( struct gpio_bank * bank , int offset )
{
return _get_gpio_direction ( bank , offset ) = = OMAP_GPIO_DIR_OUT ;
}
static int check_requested ( struct udevice * dev , unsigned offset ,
const char * func )
{
struct gpio_bank * bank = dev_get_priv ( dev ) ;
struct gpio_dev_priv * uc_priv = dev - > uclass_priv ;
if ( ! gpio_is_requested ( bank , offset ) ) {
printf ( " omap_gpio: %s: error: gpio %s%d not requested \n " ,
func , uc_priv - > bank_name , offset ) ;
return - EPERM ;
}
return 0 ;
}
/* set GPIO pin 'gpio' as an input */
static int omap_gpio_direction_input ( struct udevice * dev , unsigned offset )
{
struct gpio_bank * bank = dev_get_priv ( dev ) ;
int ret ;
ret = check_requested ( dev , offset , __func__ ) ;
if ( ret )
return ret ;
/* Configure GPIO direction as input. */
_set_gpio_direction ( bank , offset , 1 ) ;
return 0 ;
}
/* set GPIO pin 'gpio' as an output, with polarity 'value' */
static int omap_gpio_direction_output ( struct udevice * dev , unsigned offset ,
int value )
{
struct gpio_bank * bank = dev_get_priv ( dev ) ;
int ret ;
ret = check_requested ( dev , offset , __func__ ) ;
if ( ret )
return ret ;
_set_gpio_dataout ( bank , offset , value ) ;
_set_gpio_direction ( bank , offset , 0 ) ;
return 0 ;
}
/* read GPIO IN value of pin 'gpio' */
static int omap_gpio_get_value ( struct udevice * dev , unsigned offset )
{
struct gpio_bank * bank = dev_get_priv ( dev ) ;
int ret ;
ret = check_requested ( dev , offset , __func__ ) ;
if ( ret )
return ret ;
return _get_gpio_value ( bank , offset ) ;
}
/* write GPIO OUT value to pin 'gpio' */
static int omap_gpio_set_value ( struct udevice * dev , unsigned offset ,
int value )
{
struct gpio_bank * bank = dev_get_priv ( dev ) ;
int ret ;
ret = check_requested ( dev , offset , __func__ ) ;
if ( ret )
return ret ;
_set_gpio_dataout ( bank , offset , value ) ;
return 0 ;
}
static int omap_gpio_get_state ( struct udevice * dev , unsigned int offset ,
char * buf , int bufsize )
{
struct gpio_dev_priv * uc_priv = dev - > uclass_priv ;
struct gpio_bank * bank = dev_get_priv ( dev ) ;
const char * label ;
bool requested ;
bool is_output ;
int size ;
label = bank - > label [ offset ] ;
is_output = omap_gpio_is_output ( bank - > base , offset ) ;
size = snprintf ( buf , bufsize , " %s%d: " ,
uc_priv - > bank_name ? uc_priv - > bank_name : " " , offset ) ;
buf + = size ;
bufsize - = size ;
requested = gpio_is_requested ( bank , offset ) ;
snprintf ( buf , bufsize , " %s: %d [%c]%s%s " ,
is_output ? " out " : " in " ,
_get_gpio_value ( bank , offset ) ,
requested ? ' x ' : ' ' ,
requested ? " " : " " ,
label ) ;
return 0 ;
}
static int omap_gpio_request ( struct udevice * dev , unsigned offset ,
const char * label )
{
struct gpio_bank * bank = dev_get_priv ( dev ) ;
if ( gpio_is_requested ( bank , offset ) )
return - EBUSY ;
strncpy ( bank - > label [ offset ] , label , GPIO_NAME_SIZE ) ;
bank - > label [ offset ] [ GPIO_NAME_SIZE - 1 ] = ' \0 ' ;
return 0 ;
}
static int omap_gpio_free ( struct udevice * dev , unsigned offset )
{
struct gpio_bank * bank = dev_get_priv ( dev ) ;
int ret ;
ret = check_requested ( dev , offset , __func__ ) ;
if ( ret )
return ret ;
bank - > label [ offset ] [ 0 ] = ' \0 ' ;
return 0 ;
}
static int omap_gpio_get_function ( struct udevice * dev , unsigned offset )
{
struct gpio_bank * bank = dev_get_priv ( dev ) ;
if ( ! gpio_is_requested ( bank , offset ) )
return GPIOF_UNUSED ;
/* GPIOF_FUNC is not implemented yet */
if ( _get_gpio_direction ( bank - > base , offset ) )
return GPIOF_OUTPUT ;
else
return GPIOF_INPUT ;
}
static const struct dm_gpio_ops gpio_omap_ops = {
. request = omap_gpio_request ,
. free = omap_gpio_free ,
. direction_input = omap_gpio_direction_input ,
. direction_output = omap_gpio_direction_output ,
. get_value = omap_gpio_get_value ,
. set_value = omap_gpio_set_value ,
. get_function = omap_gpio_get_function ,
. get_state = omap_gpio_get_state ,
} ;
static int omap_gpio_probe ( struct udevice * dev )
{
struct gpio_bank * bank = dev_get_priv ( dev ) ;
struct omap_gpio_platdata * plat = dev_get_platdata ( dev ) ;
struct gpio_dev_priv * uc_priv = dev - > uclass_priv ;
char name [ 18 ] , * str ;
sprintf ( name , " GPIO%d_ " , plat - > bank_index ) ;
str = strdup ( name ) ;
if ( ! str )
return - ENOMEM ;
uc_priv - > bank_name = str ;
uc_priv - > gpio_count = GPIO_PER_BANK ;
bank - > base = ( void * ) plat - > base ;
bank - > method = plat - > method ;
return 0 ;
}
U_BOOT_DRIVER ( gpio_omap ) = {
. name = " gpio_omap " ,
. id = UCLASS_GPIO ,
. ops = & gpio_omap_ops ,
. probe = omap_gpio_probe ,
. priv_auto_alloc_size = sizeof ( struct gpio_bank ) ,
} ;
# endif /* CONFIG_DM_GPIO */