@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright ( c ) 2013 Xilinx , Michal Simek
* Copyright ( c ) 2013 - 2018 Xilinx , Michal Simek
*/
# include <common.h>
@ -9,6 +9,7 @@
# include <linux/list.h>
# include <asm/io.h>
# include <asm/gpio.h>
# include <dm.h>
static LIST_HEAD ( gpio_list ) ;
@ -23,6 +24,8 @@ struct gpio_regs {
u32 gpiodir ;
} ;
# if !defined(CONFIG_DM_GPIO)
# define GPIO_NAME_SIZE 10
struct gpio_names {
@ -345,3 +348,263 @@ int gpio_alloc_dual(u32 baseaddr, const char *name, u32 gpio_no0, u32 gpio_no1)
/* Return the first gpio allocated for this device */
return ret ;
}
# else
# include <dt-bindings/gpio/gpio.h>
# define XILINX_GPIO_MAX_BANK 2
struct xilinx_gpio_platdata {
struct gpio_regs * regs ;
int bank_max [ XILINX_GPIO_MAX_BANK ] ;
int bank_input [ XILINX_GPIO_MAX_BANK ] ;
int bank_output [ XILINX_GPIO_MAX_BANK ] ;
} ;
static int xilinx_gpio_get_bank_pin ( unsigned offset , u32 * bank_num ,
u32 * bank_pin_num , struct udevice * dev )
{
struct xilinx_gpio_platdata * platdata = dev_get_platdata ( dev ) ;
u32 bank , max_pins ;
/* the first gpio is 0 not 1 */
u32 pin_num = offset ;
for ( bank = 0 ; bank < XILINX_GPIO_MAX_BANK ; bank + + ) {
max_pins = platdata - > bank_max [ bank ] ;
if ( pin_num < max_pins ) {
debug ( " %s: found at bank 0x%x pin 0x%x \n " , __func__ ,
bank , pin_num ) ;
* bank_num = bank ;
* bank_pin_num = pin_num ;
return 0 ;
}
pin_num - = max_pins ;
}
return - EINVAL ;
}
static int xilinx_gpio_set_value ( struct udevice * dev , unsigned offset ,
int value )
{
struct xilinx_gpio_platdata * platdata = dev_get_platdata ( dev ) ;
int val , ret ;
u32 bank , pin ;
ret = xilinx_gpio_get_bank_pin ( offset , & bank , & pin , dev ) ;
if ( ret )
return ret ;
debug ( " %s: regs: %lx, value: %x, gpio: %x, bank %x, pin %x \n " ,
__func__ , ( ulong ) platdata - > regs , value , offset , bank , pin ) ;
if ( value ) {
val = readl ( & platdata - > regs - > gpiodata + bank * 2 ) ;
val = val | ( 1 < < pin ) ;
writel ( val , & platdata - > regs - > gpiodata + bank * 2 ) ;
} else {
val = readl ( & platdata - > regs - > gpiodata + bank * 2 ) ;
val = val & ~ ( 1 < < pin ) ;
writel ( val , & platdata - > regs - > gpiodata + bank * 2 ) ;
}
return val ;
} ;
static int xilinx_gpio_get_value ( struct udevice * dev , unsigned offset )
{
struct xilinx_gpio_platdata * platdata = dev_get_platdata ( dev ) ;
int val , ret ;
u32 bank , pin ;
ret = xilinx_gpio_get_bank_pin ( offset , & bank , & pin , dev ) ;
if ( ret )
return ret ;
debug ( " %s: regs: %lx, gpio: %x, bank %x, pin %x \n " , __func__ ,
( ulong ) platdata - > regs , offset , bank , pin ) ;
val = readl ( & platdata - > regs - > gpiodata + bank * 2 ) ;
val = ! ! ( val & ( 1 < < pin ) ) ;
return val ;
} ;
static int xilinx_gpio_get_function ( struct udevice * dev , unsigned offset )
{
struct xilinx_gpio_platdata * platdata = dev_get_platdata ( dev ) ;
int val , ret ;
u32 bank , pin ;
/* Check if all pins are inputs */
if ( platdata - > bank_input [ bank ] )
return GPIOF_INPUT ;
/* Check if all pins are outputs */
if ( platdata - > bank_output [ bank ] )
return GPIOF_OUTPUT ;
ret = xilinx_gpio_get_bank_pin ( offset , & bank , & pin , dev ) ;
if ( ret )
return ret ;
/* FIXME test on dual */
val = readl ( & platdata - > regs - > gpiodir + bank * 2 ) ;
val = ! ( val & ( 1 < < pin ) ) ;
/* input is 1 in reg but GPIOF_INPUT is 0 */
/* output is 0 in reg but GPIOF_OUTPUT is 1 */
return val ;
}
static int xilinx_gpio_direction_output ( struct udevice * dev , unsigned offset ,
int value )
{
struct xilinx_gpio_platdata * platdata = dev_get_platdata ( dev ) ;
int val , ret ;
u32 bank , pin ;
ret = xilinx_gpio_get_bank_pin ( offset , & bank , & pin , dev ) ;
if ( ret )
return ret ;
/* can't change it if all is input by default */
if ( platdata - > bank_input [ bank ] )
return - EINVAL ;
if ( ! platdata - > bank_output [ bank ] ) {
val = readl ( & platdata - > regs - > gpiodir + bank * 2 ) ;
val = val & ~ ( 1 < < pin ) ;
writel ( val , & platdata - > regs - > gpiodir + bank * 2 ) ;
}
xilinx_gpio_set_value ( dev , offset , value ) ;
return 0 ;
}
static int xilinx_gpio_direction_input ( struct udevice * dev , unsigned offset )
{
struct xilinx_gpio_platdata * platdata = dev_get_platdata ( dev ) ;
int val , ret ;
u32 bank , pin ;
ret = xilinx_gpio_get_bank_pin ( offset , & bank , & pin , dev ) ;
if ( ret )
return ret ;
/* Already input */
if ( platdata - > bank_input [ bank ] )
return 0 ;
/* can't change it if all is output by default */
if ( platdata - > bank_output [ bank ] )
return - EINVAL ;
val = readl ( & platdata - > regs - > gpiodir + bank * 2 ) ;
val = val | ( 1 < < pin ) ;
writel ( val , & platdata - > regs - > gpiodir + bank * 2 ) ;
return 0 ;
}
static int xilinx_gpio_xlate ( struct udevice * dev , struct gpio_desc * desc ,
struct ofnode_phandle_args * args )
{
struct xilinx_gpio_platdata * platdata = dev_get_platdata ( dev ) ;
desc - > offset = args - > args [ 0 ] ;
debug ( " %s: argc: %x, [0]: %x, [1]: %x, [2]: %x \n " , __func__ ,
args - > args_count , args - > args [ 0 ] , args - > args [ 1 ] , args - > args [ 2 ] ) ;
/*
* The second cell is channel offset :
* 0 is first channel , 8 is second channel
*
* U - Boot driver just combine channels together that ' s why simply
* add amount of pins in second channel if present .
*/
if ( args - > args [ 1 ] ) {
if ( ! platdata - > bank_max [ 1 ] ) {
printf ( " %s: %s has no second channel \n " ,
__func__ , dev - > name ) ;
return - EINVAL ;
}
desc - > offset + = platdata - > bank_max [ 0 ] ;
}
/* The third cell is optional */
if ( args - > args_count > 2 )
desc - > flags = ( args - > args [ 2 ] &
GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0 ) ;
debug ( " %s: offset %x, flags %lx \n " ,
__func__ , desc - > offset , desc - > flags ) ;
return 0 ;
}
static const struct dm_gpio_ops xilinx_gpio_ops = {
. direction_input = xilinx_gpio_direction_input ,
. direction_output = xilinx_gpio_direction_output ,
. get_value = xilinx_gpio_get_value ,
. set_value = xilinx_gpio_set_value ,
. get_function = xilinx_gpio_get_function ,
. xlate = xilinx_gpio_xlate ,
} ;
static int xilinx_gpio_probe ( struct udevice * dev )
{
struct xilinx_gpio_platdata * platdata = dev_get_platdata ( dev ) ;
struct gpio_dev_priv * uc_priv = dev_get_uclass_priv ( dev ) ;
uc_priv - > bank_name = dev - > name ;
uc_priv - > gpio_count = platdata - > bank_max [ 0 ] + platdata - > bank_max [ 1 ] ;
return 0 ;
}
static int xilinx_gpio_ofdata_to_platdata ( struct udevice * dev )
{
struct xilinx_gpio_platdata * platdata = dev_get_platdata ( dev ) ;
int is_dual ;
platdata - > regs = ( struct gpio_regs * ) dev_read_addr ( dev ) ;
platdata - > bank_max [ 0 ] = dev_read_u32_default ( dev ,
" xlnx,gpio-width " , 0 ) ;
platdata - > bank_input [ 0 ] = dev_read_u32_default ( dev ,
" xlnx,all-inputs " , 0 ) ;
platdata - > bank_output [ 0 ] = dev_read_u32_default ( dev ,
" xlnx,all-outputs " , 0 ) ;
is_dual = dev_read_u32_default ( dev , " xlnx,is-dual " , 0 ) ;
if ( is_dual ) {
platdata - > bank_max [ 1 ] = dev_read_u32_default ( dev ,
" xlnx,gpio2-width " , 0 ) ;
platdata - > bank_input [ 1 ] = dev_read_u32_default ( dev ,
" xlnx,all-inputs-2 " , 0 ) ;
platdata - > bank_output [ 1 ] = dev_read_u32_default ( dev ,
" xlnx,all-outputs-2 " , 0 ) ;
}
return 0 ;
}
static const struct udevice_id xilinx_gpio_ids [ ] = {
{ . compatible = " xlnx,xps-gpio-1.00.a " , } ,
{ }
} ;
U_BOOT_DRIVER ( xilinx_gpio ) = {
. name = " xlnx_gpio " ,
. id = UCLASS_GPIO ,
. ops = & xilinx_gpio_ops ,
. of_match = xilinx_gpio_ids ,
. ofdata_to_platdata = xilinx_gpio_ofdata_to_platdata ,
. probe = xilinx_gpio_probe ,
. platdata_auto_alloc_size = sizeof ( struct xilinx_gpio_platdata ) ,
} ;
# endif