@ -6,11 +6,14 @@
# include <common.h>
# include <dm.h>
# include <dm/device-internal.h>
# include <dm/lists.h>
# include <dm/pinctrl.h>
# include <fdt_support.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/sizes.h>
# include <asm/gpio.h>
# include "pinctrl-meson.h"
@ -117,6 +120,143 @@ const struct pinctrl_ops meson_pinctrl_ops = {
. set_state = pinctrl_generic_set_state ,
} ;
static int meson_gpio_calc_reg_and_bit ( struct udevice * dev , unsigned int offset ,
enum meson_reg_type reg_type ,
unsigned int * reg , unsigned int * bit )
{
struct meson_pinctrl * priv = dev_get_priv ( dev - > parent ) ;
struct meson_bank * bank = NULL ;
struct meson_reg_desc * desc ;
unsigned int pin ;
int i ;
pin = priv - > data - > pin_base + offset ;
for ( i = 0 ; i < priv - > data - > num_banks ; i + + ) {
if ( pin > = priv - > data - > banks [ i ] . first & &
pin < = priv - > data - > banks [ i ] . last ) {
bank = & priv - > data - > banks [ i ] ;
break ;
}
}
if ( ! bank )
return - EINVAL ;
desc = & bank - > regs [ reg_type ] ;
* reg = desc - > reg * 4 ;
* bit = desc - > bit + pin - bank - > first ;
return 0 ;
}
static int meson_gpio_get ( struct udevice * dev , unsigned int offset )
{
struct meson_pinctrl * priv = dev_get_priv ( dev - > parent ) ;
unsigned int reg , bit ;
int ret ;
ret = meson_gpio_calc_reg_and_bit ( dev , offset , REG_IN , & reg , & bit ) ;
if ( ret )
return ret ;
return ! ! ( readl ( priv - > reg_gpio + reg ) & BIT ( bit ) ) ;
}
static int meson_gpio_set ( struct udevice * dev , unsigned int offset , int value )
{
struct meson_pinctrl * priv = dev_get_priv ( dev - > parent ) ;
unsigned int reg , bit ;
int ret ;
ret = meson_gpio_calc_reg_and_bit ( dev , offset , REG_OUT , & reg , & bit ) ;
if ( ret )
return ret ;
clrsetbits_le32 ( priv - > reg_gpio + reg , BIT ( bit ) , value ? BIT ( bit ) : 0 ) ;
return 0 ;
}
static int meson_gpio_get_direction ( struct udevice * dev , unsigned int offset )
{
struct meson_pinctrl * priv = dev_get_priv ( dev - > parent ) ;
unsigned int reg , bit , val ;
int ret ;
ret = meson_gpio_calc_reg_and_bit ( dev , offset , REG_DIR , & reg , & bit ) ;
if ( ret )
return ret ;
val = readl ( priv - > reg_gpio + reg ) ;
return ( val & BIT ( bit ) ) ? GPIOF_INPUT : GPIOF_OUTPUT ;
}
static int meson_gpio_direction_input ( struct udevice * dev , unsigned int offset )
{
struct meson_pinctrl * priv = dev_get_priv ( dev - > parent ) ;
unsigned int reg , bit ;
int ret ;
ret = meson_gpio_calc_reg_and_bit ( dev , offset , REG_DIR , & reg , & bit ) ;
if ( ret )
return ret ;
clrsetbits_le32 ( priv - > reg_gpio + reg , BIT ( bit ) , 1 ) ;
return 0 ;
}
static int meson_gpio_direction_output ( struct udevice * dev ,
unsigned int offset , int value )
{
struct meson_pinctrl * priv = dev_get_priv ( dev - > parent ) ;
unsigned int reg , bit ;
int ret ;
ret = meson_gpio_calc_reg_and_bit ( dev , offset , REG_DIR , & reg , & bit ) ;
if ( ret )
return ret ;
clrsetbits_le32 ( priv - > reg_gpio + reg , BIT ( bit ) , 0 ) ;
ret = meson_gpio_calc_reg_and_bit ( dev , offset , REG_OUT , & reg , & bit ) ;
if ( ret )
return ret ;
clrsetbits_le32 ( priv - > reg_gpio + reg , BIT ( bit ) , value ? BIT ( bit ) : 0 ) ;
return 0 ;
}
static int meson_gpio_probe ( struct udevice * dev )
{
struct meson_pinctrl * priv = dev_get_priv ( dev - > parent ) ;
struct gpio_dev_priv * uc_priv ;
uc_priv = dev_get_uclass_priv ( dev ) ;
uc_priv - > bank_name = priv - > data - > name ;
uc_priv - > gpio_count = priv - > data - > num_pins ;
return 0 ;
}
static const struct dm_gpio_ops meson_gpio_ops = {
. set_value = meson_gpio_set ,
. get_value = meson_gpio_get ,
. get_function = meson_gpio_get_direction ,
. direction_input = meson_gpio_direction_input ,
. direction_output = meson_gpio_direction_output ,
} ;
static struct driver meson_gpio_driver = {
. name = " meson-gpio " ,
. id = UCLASS_GPIO ,
. probe = meson_gpio_probe ,
. ops = & meson_gpio_ops ,
} ;
static fdt_addr_t parse_address ( int offset , const char * name , int na , int ns )
{
int index , len = 0 ;
@ -138,9 +278,12 @@ static fdt_addr_t parse_address(int offset, const char *name, int na, int ns)
int meson_pinctrl_probe ( struct udevice * dev )
{
struct meson_pinctrl * priv = dev_get_priv ( dev ) ;
struct uclass_driver * drv ;
struct udevice * gpio_dev ;
fdt_addr_t addr ;
int node , gpio = - 1 , len ;
int na , ns ;
char * name ;
na = fdt_address_cells ( gd - > fdt_blob , dev_of_offset ( dev - > parent ) ) ;
if ( na < 1 ) {
@ -168,12 +311,32 @@ int meson_pinctrl_probe(struct udevice *dev)
addr = parse_address ( gpio , " mux " , na , ns ) ;
if ( addr = = FDT_ADDR_T_NONE ) {
debug ( " mux not found \n " ) ;
debug ( " mux address not found \n " ) ;
return - EINVAL ;
}
priv - > reg_mux = ( void __iomem * ) addr ;
addr = parse_address ( gpio , " gpio " , na , ns ) ;
if ( addr = = FDT_ADDR_T_NONE ) {
debug ( " gpio address not found \n " ) ;
return - EINVAL ;
}
priv - > reg_gpio = ( void __iomem * ) addr ;
priv - > data = ( struct meson_pinctrl_data * ) dev_get_driver_data ( dev ) ;
/* Lookup GPIO driver */
drv = lists_uclass_lookup ( UCLASS_GPIO ) ;
if ( ! drv ) {
puts ( " Cannot find GPIO driver \n " ) ;
return - ENOENT ;
}
name = calloc ( 1 , 32 ) ;
sprintf ( name , " meson-gpio " ) ;
/* Create child device UCLASS_GPIO and bind it */
device_bind ( dev , & meson_gpio_driver , name , NULL , gpio , & gpio_dev ) ;
dev_set_of_offset ( gpio_dev , gpio ) ;
return 0 ;
}