@ -11,9 +11,25 @@
*/
*/
# include <common.h>
# include <common.h>
# include <dm.h>
# include <errno.h>
# include <fdtdec.h>
# include <malloc.h>
# include <asm/io.h>
# include <asm/io.h>
# include <asm/gpio.h>
# include <asm/gpio.h>
# include <dm/device-internal.h>
DECLARE_GLOBAL_DATA_PTR ;
# define SUNXI_GPIOS_PER_BANK SUNXI_GPIO_A_NR
struct sunxi_gpio_platdata {
struct sunxi_gpio * regs ;
const char * bank_name ; /* Name of bank, e.g. "B" */
int gpio_count ;
} ;
# ifndef CONFIG_DM_GPIO
static int sunxi_gpio_output ( u32 pin , u32 val )
static int sunxi_gpio_output ( u32 pin , u32 val )
{
{
u32 dat ;
u32 dat ;
@ -100,3 +116,157 @@ int sunxi_name_to_gpio(const char *name)
return - 1 ;
return - 1 ;
return group * 32 + pin ;
return group * 32 + pin ;
}
}
# endif
# ifdef CONFIG_DM_GPIO
static int sunxi_gpio_direction_input ( struct udevice * dev , unsigned offset )
{
struct sunxi_gpio_platdata * plat = dev_get_platdata ( dev ) ;
sunxi_gpio_set_cfgbank ( plat - > regs , offset , SUNXI_GPIO_INPUT ) ;
return 0 ;
}
static int sunxi_gpio_direction_output ( struct udevice * dev , unsigned offset ,
int value )
{
struct sunxi_gpio_platdata * plat = dev_get_platdata ( dev ) ;
u32 num = GPIO_NUM ( offset ) ;
sunxi_gpio_set_cfgbank ( plat - > regs , offset , SUNXI_GPIO_OUTPUT ) ;
clrsetbits_le32 ( & plat - > regs - > dat , 1 < < num , value ? ( 1 < < num ) : 0 ) ;
return 0 ;
}
static int sunxi_gpio_get_value ( struct udevice * dev , unsigned offset )
{
struct sunxi_gpio_platdata * plat = dev_get_platdata ( dev ) ;
u32 num = GPIO_NUM ( offset ) ;
unsigned dat ;
dat = readl ( & plat - > regs - > dat ) ;
dat > > = num ;
return dat & 0x1 ;
}
static int sunxi_gpio_set_value ( struct udevice * dev , unsigned offset ,
int value )
{
struct sunxi_gpio_platdata * plat = dev_get_platdata ( dev ) ;
u32 num = GPIO_NUM ( offset ) ;
clrsetbits_le32 ( & plat - > regs - > dat , 1 < < num , value ? ( 1 < < num ) : 0 ) ;
return 0 ;
}
static int sunxi_gpio_get_function ( struct udevice * dev , unsigned offset )
{
struct sunxi_gpio_platdata * plat = dev_get_platdata ( dev ) ;
int func ;
func = sunxi_gpio_get_cfgbank ( plat - > regs , offset ) ;
if ( func = = SUNXI_GPIO_OUTPUT )
return GPIOF_OUTPUT ;
else if ( func = = SUNXI_GPIO_INPUT )
return GPIOF_INPUT ;
else
return GPIOF_FUNC ;
}
static const struct dm_gpio_ops gpio_sunxi_ops = {
. direction_input = sunxi_gpio_direction_input ,
. direction_output = sunxi_gpio_direction_output ,
. get_value = sunxi_gpio_get_value ,
. set_value = sunxi_gpio_set_value ,
. get_function = sunxi_gpio_get_function ,
} ;
/**
* Returns the name of a GPIO bank
*
* GPIO banks are named A , B , C , . . .
*
* @ bank : Bank number ( 0 , 1. . n - 1 )
* @ return allocated string containing the name
*/
static char * gpio_bank_name ( int bank )
{
char * name ;
name = malloc ( 2 ) ;
if ( name ) {
name [ 0 ] = ' A ' + bank ;
name [ 1 ] = ' \0 ' ;
}
return name ;
}
static int gpio_sunxi_probe ( struct udevice * dev )
{
struct sunxi_gpio_platdata * plat = dev_get_platdata ( dev ) ;
struct gpio_dev_priv * uc_priv = dev - > uclass_priv ;
/* Tell the uclass how many GPIOs we have */
if ( plat ) {
uc_priv - > gpio_count = plat - > gpio_count ;
uc_priv - > bank_name = plat - > bank_name ;
}
return 0 ;
}
/**
* We have a top - level GPIO device with no actual GPIOs . It has a child
* device for each Sunxi bank .
*/
static int gpio_sunxi_bind ( struct udevice * parent )
{
struct sunxi_gpio_platdata * plat = parent - > platdata ;
struct sunxi_gpio_reg * ctlr ;
int bank ;
int ret ;
/* If this is a child device, there is nothing to do here */
if ( plat )
return 0 ;
ctlr = ( struct sunxi_gpio_reg * ) fdtdec_get_addr ( gd - > fdt_blob ,
parent - > of_offset , " reg " ) ;
for ( bank = 0 ; bank < SUNXI_GPIO_BANKS ; bank + + ) {
struct sunxi_gpio_platdata * plat ;
struct udevice * dev ;
plat = calloc ( 1 , sizeof ( * plat ) ) ;
if ( ! plat )
return - ENOMEM ;
plat - > regs = & ctlr - > gpio_bank [ bank ] ;
plat - > bank_name = gpio_bank_name ( bank ) ;
plat - > gpio_count = SUNXI_GPIOS_PER_BANK ;
ret = device_bind ( parent , parent - > driver ,
plat - > bank_name , plat , - 1 , & dev ) ;
if ( ret )
return ret ;
dev - > of_offset = parent - > of_offset ;
}
return 0 ;
}
static const struct udevice_id sunxi_gpio_ids [ ] = {
{ . compatible = " allwinner,sun7i-a20-pinctrl " } ,
{ }
} ;
U_BOOT_DRIVER ( gpio_sunxi ) = {
. name = " gpio_sunxi " ,
. id = UCLASS_GPIO ,
. ops = & gpio_sunxi_ops ,
. of_match = sunxi_gpio_ids ,
. bind = gpio_sunxi_bind ,
. probe = gpio_sunxi_probe ,
} ;
# endif