2012-02-02 01:04:47 +04:00
/*
* Driver for the NVIDIA Tegra pinmux
*
2012-04-11 22:53:09 +04:00
* Copyright ( c ) 2011 - 2012 , NVIDIA CORPORATION . All rights reserved .
2012-02-02 01:04:47 +04:00
*
* Derived from code :
* Copyright ( C ) 2010 Google , Inc .
* Copyright ( C ) 2010 NVIDIA Corporation
* Copyright ( C ) 2009 - 2011 ST - Ericsson AB
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*/
# include <linux/err.h>
# include <linux/init.h>
# include <linux/io.h>
# include <linux/module.h>
2012-04-11 22:53:09 +04:00
# include <linux/of.h>
# include <linux/platform_device.h>
2012-04-04 19:27:50 +04:00
# include <linux/pinctrl/machine.h>
2012-02-02 01:04:47 +04:00
# include <linux/pinctrl/pinctrl.h>
# include <linux/pinctrl/pinmux.h>
# include <linux/pinctrl/pinconf.h>
2012-04-04 19:27:50 +04:00
# include <linux/slab.h>
2012-02-02 01:04:47 +04:00
2012-04-11 22:53:09 +04:00
# include "core.h"
2012-02-02 01:04:47 +04:00
# include "pinctrl-tegra.h"
2013-08-21 15:23:38 +04:00
# include "pinctrl-utils.h"
2012-02-02 01:04:47 +04:00
struct tegra_pmx {
struct device * dev ;
struct pinctrl_dev * pctl ;
const struct tegra_pinctrl_soc_data * soc ;
int nbanks ;
void __iomem * * regs ;
} ;
static inline u32 pmx_readl ( struct tegra_pmx * pmx , u32 bank , u32 reg )
{
return readl ( pmx - > regs [ bank ] + reg ) ;
}
static inline void pmx_writel ( struct tegra_pmx * pmx , u32 val , u32 bank , u32 reg )
{
writel ( val , pmx - > regs [ bank ] + reg ) ;
}
2012-03-30 09:55:40 +04:00
static int tegra_pinctrl_get_groups_count ( struct pinctrl_dev * pctldev )
2012-02-02 01:04:47 +04:00
{
struct tegra_pmx * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2012-03-30 09:55:40 +04:00
return pmx - > soc - > ngroups ;
2012-02-02 01:04:47 +04:00
}
static const char * tegra_pinctrl_get_group_name ( struct pinctrl_dev * pctldev ,
unsigned group )
{
struct tegra_pmx * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
return pmx - > soc - > groups [ group ] . name ;
}
static int tegra_pinctrl_get_group_pins ( struct pinctrl_dev * pctldev ,
unsigned group ,
const unsigned * * pins ,
unsigned * num_pins )
{
struct tegra_pmx * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
* pins = pmx - > soc - > groups [ group ] . pins ;
* num_pins = pmx - > soc - > groups [ group ] . npins ;
return 0 ;
}
2012-04-12 01:42:56 +04:00
# ifdef CONFIG_DEBUG_FS
2012-02-02 01:04:47 +04:00
static void tegra_pinctrl_pin_dbg_show ( struct pinctrl_dev * pctldev ,
struct seq_file * s ,
unsigned offset )
{
2012-04-11 22:53:09 +04:00
seq_printf ( s , " %s " , dev_name ( pctldev - > dev ) ) ;
2012-02-02 01:04:47 +04:00
}
2012-04-12 01:42:56 +04:00
# endif
2012-02-02 01:04:47 +04:00
2012-04-04 19:27:50 +04:00
static const struct cfg_param {
const char * property ;
enum tegra_pinconf_param param ;
} cfg_params [ ] = {
{ " nvidia,pull " , TEGRA_PINCONF_PARAM_PULL } ,
{ " nvidia,tristate " , TEGRA_PINCONF_PARAM_TRISTATE } ,
{ " nvidia,enable-input " , TEGRA_PINCONF_PARAM_ENABLE_INPUT } ,
{ " nvidia,open-drain " , TEGRA_PINCONF_PARAM_OPEN_DRAIN } ,
{ " nvidia,lock " , TEGRA_PINCONF_PARAM_LOCK } ,
{ " nvidia,io-reset " , TEGRA_PINCONF_PARAM_IORESET } ,
2013-01-08 11:32:36 +04:00
{ " nvidia,rcv-sel " , TEGRA_PINCONF_PARAM_RCV_SEL } ,
2012-04-04 19:27:50 +04:00
{ " nvidia,high-speed-mode " , TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE } ,
{ " nvidia,schmitt " , TEGRA_PINCONF_PARAM_SCHMITT } ,
{ " nvidia,low-power-mode " , TEGRA_PINCONF_PARAM_LOW_POWER_MODE } ,
{ " nvidia,pull-down-strength " , TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH } ,
{ " nvidia,pull-up-strength " , TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH } ,
{ " nvidia,slew-rate-falling " , TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING } ,
{ " nvidia,slew-rate-rising " , TEGRA_PINCONF_PARAM_SLEW_RATE_RISING } ,
2013-01-08 11:32:36 +04:00
{ " nvidia,drive-type " , TEGRA_PINCONF_PARAM_DRIVE_TYPE } ,
2012-04-04 19:27:50 +04:00
} ;
2013-08-21 15:23:38 +04:00
static int tegra_pinctrl_dt_subnode_to_map ( struct pinctrl_dev * pctldev ,
2012-11-11 06:31:31 +04:00
struct device_node * np ,
struct pinctrl_map * * map ,
unsigned * reserved_maps ,
unsigned * num_maps )
2012-04-04 19:27:50 +04:00
{
2013-08-21 15:23:38 +04:00
struct device * dev = pctldev - > dev ;
2012-04-04 19:27:50 +04:00
int ret , i ;
const char * function ;
u32 val ;
unsigned long config ;
unsigned long * configs = NULL ;
unsigned num_configs = 0 ;
unsigned reserve ;
struct property * prop ;
const char * group ;
ret = of_property_read_string ( np , " nvidia,function " , & function ) ;
2012-04-23 20:05:22 +04:00
if ( ret < 0 ) {
/* EINVAL=missing, which is fine since it's optional */
if ( ret ! = - EINVAL )
dev_err ( dev ,
" could not parse property nvidia,function \n " ) ;
2012-04-04 19:27:50 +04:00
function = NULL ;
2012-04-23 20:05:22 +04:00
}
2012-04-04 19:27:50 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( cfg_params ) ; i + + ) {
ret = of_property_read_u32 ( np , cfg_params [ i ] . property , & val ) ;
if ( ! ret ) {
config = TEGRA_PINCONF_PACK ( cfg_params [ i ] . param , val ) ;
2013-08-21 15:23:38 +04:00
ret = pinctrl_utils_add_config ( pctldev , & configs ,
& num_configs , config ) ;
2012-04-04 19:27:50 +04:00
if ( ret < 0 )
goto exit ;
2012-04-23 20:05:22 +04:00
/* EINVAL=missing, which is fine since it's optional */
} else if ( ret ! = - EINVAL ) {
dev_err ( dev , " could not parse property %s \n " ,
cfg_params [ i ] . property ) ;
2012-04-04 19:27:50 +04:00
}
}
reserve = 0 ;
if ( function ! = NULL )
reserve + + ;
if ( num_configs )
reserve + + ;
ret = of_property_count_strings ( np , " nvidia,pins " ) ;
2012-04-23 20:05:22 +04:00
if ( ret < 0 ) {
dev_err ( dev , " could not parse property nvidia,pins \n " ) ;
2012-04-04 19:27:50 +04:00
goto exit ;
2012-04-23 20:05:22 +04:00
}
2012-04-04 19:27:50 +04:00
reserve * = ret ;
2013-08-21 15:23:38 +04:00
ret = pinctrl_utils_reserve_map ( pctldev , map , reserved_maps ,
num_maps , reserve ) ;
2012-04-04 19:27:50 +04:00
if ( ret < 0 )
goto exit ;
of_property_for_each_string ( np , " nvidia,pins " , prop , group ) {
if ( function ) {
2013-08-21 15:23:38 +04:00
ret = pinctrl_utils_add_map_mux ( pctldev , map ,
reserved_maps , num_maps , group ,
function ) ;
2012-04-04 19:27:50 +04:00
if ( ret < 0 )
goto exit ;
}
if ( num_configs ) {
2013-08-21 15:23:38 +04:00
ret = pinctrl_utils_add_map_configs ( pctldev , map ,
reserved_maps , num_maps , group ,
configs , num_configs ,
PIN_MAP_TYPE_CONFIGS_GROUP ) ;
2012-04-04 19:27:50 +04:00
if ( ret < 0 )
goto exit ;
}
}
ret = 0 ;
exit :
kfree ( configs ) ;
return ret ;
}
2012-11-11 06:31:31 +04:00
static int tegra_pinctrl_dt_node_to_map ( struct pinctrl_dev * pctldev ,
struct device_node * np_config ,
struct pinctrl_map * * map ,
unsigned * num_maps )
2012-04-04 19:27:50 +04:00
{
unsigned reserved_maps ;
struct device_node * np ;
int ret ;
reserved_maps = 0 ;
* map = NULL ;
* num_maps = 0 ;
for_each_child_of_node ( np_config , np ) {
2013-08-21 15:23:38 +04:00
ret = tegra_pinctrl_dt_subnode_to_map ( pctldev , np , map ,
2012-04-23 20:05:22 +04:00
& reserved_maps , num_maps ) ;
2012-04-04 19:27:50 +04:00
if ( ret < 0 ) {
2013-08-21 15:23:38 +04:00
pinctrl_utils_dt_free_map ( pctldev , * map ,
* num_maps ) ;
2012-04-04 19:27:50 +04:00
return ret ;
}
}
return 0 ;
}
2013-02-16 13:25:07 +04:00
static const struct pinctrl_ops tegra_pinctrl_ops = {
2012-03-30 09:55:40 +04:00
. get_groups_count = tegra_pinctrl_get_groups_count ,
2012-02-02 01:04:47 +04:00
. get_group_name = tegra_pinctrl_get_group_name ,
. get_group_pins = tegra_pinctrl_get_group_pins ,
2012-04-12 01:42:56 +04:00
# ifdef CONFIG_DEBUG_FS
2012-02-02 01:04:47 +04:00
. pin_dbg_show = tegra_pinctrl_pin_dbg_show ,
2012-04-12 01:42:56 +04:00
# endif
2012-04-04 19:27:50 +04:00
. dt_node_to_map = tegra_pinctrl_dt_node_to_map ,
2013-08-21 15:23:38 +04:00
. dt_free_map = pinctrl_utils_dt_free_map ,
2012-02-02 01:04:47 +04:00
} ;
2012-03-30 09:55:40 +04:00
static int tegra_pinctrl_get_funcs_count ( struct pinctrl_dev * pctldev )
2012-02-02 01:04:47 +04:00
{
struct tegra_pmx * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2012-03-30 09:55:40 +04:00
return pmx - > soc - > nfunctions ;
2012-02-02 01:04:47 +04:00
}
static const char * tegra_pinctrl_get_func_name ( struct pinctrl_dev * pctldev ,
unsigned function )
{
struct tegra_pmx * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
return pmx - > soc - > functions [ function ] . name ;
}
static int tegra_pinctrl_get_func_groups ( struct pinctrl_dev * pctldev ,
unsigned function ,
const char * const * * groups ,
unsigned * const num_groups )
{
struct tegra_pmx * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
* groups = pmx - > soc - > functions [ function ] . groups ;
* num_groups = pmx - > soc - > functions [ function ] . ngroups ;
return 0 ;
}
static int tegra_pinctrl_enable ( struct pinctrl_dev * pctldev , unsigned function ,
unsigned group )
{
struct tegra_pmx * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
const struct tegra_pingroup * g ;
int i ;
u32 val ;
g = & pmx - > soc - > groups [ group ] ;
2012-04-23 20:05:22 +04:00
if ( WARN_ON ( g - > mux_reg < 0 ) )
2012-02-02 01:04:47 +04:00
return - EINVAL ;
for ( i = 0 ; i < ARRAY_SIZE ( g - > funcs ) ; i + + ) {
if ( g - > funcs [ i ] = = function )
break ;
}
2012-04-23 20:05:22 +04:00
if ( WARN_ON ( i = = ARRAY_SIZE ( g - > funcs ) ) )
2012-02-02 01:04:47 +04:00
return - EINVAL ;
val = pmx_readl ( pmx , g - > mux_bank , g - > mux_reg ) ;
val & = ~ ( 0x3 < < g - > mux_bit ) ;
val | = i < < g - > mux_bit ;
pmx_writel ( pmx , val , g - > mux_bank , g - > mux_reg ) ;
return 0 ;
}
static void tegra_pinctrl_disable ( struct pinctrl_dev * pctldev ,
unsigned function , unsigned group )
{
struct tegra_pmx * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
const struct tegra_pingroup * g ;
u32 val ;
g = & pmx - > soc - > groups [ group ] ;
2012-04-23 20:05:22 +04:00
if ( WARN_ON ( g - > mux_reg < 0 ) )
2012-02-02 01:04:47 +04:00
return ;
val = pmx_readl ( pmx , g - > mux_bank , g - > mux_reg ) ;
val & = ~ ( 0x3 < < g - > mux_bit ) ;
val | = g - > func_safe < < g - > mux_bit ;
pmx_writel ( pmx , val , g - > mux_bank , g - > mux_reg ) ;
}
2013-02-16 13:25:07 +04:00
static const struct pinmux_ops tegra_pinmux_ops = {
2012-03-30 09:55:40 +04:00
. get_functions_count = tegra_pinctrl_get_funcs_count ,
2012-02-02 01:04:47 +04:00
. get_function_name = tegra_pinctrl_get_func_name ,
. get_function_groups = tegra_pinctrl_get_func_groups ,
. enable = tegra_pinctrl_enable ,
. disable = tegra_pinctrl_disable ,
} ;
static int tegra_pinconf_reg ( struct tegra_pmx * pmx ,
const struct tegra_pingroup * g ,
enum tegra_pinconf_param param ,
2012-04-12 01:42:56 +04:00
bool report_err ,
2012-02-02 01:04:47 +04:00
s8 * bank , s16 * reg , s8 * bit , s8 * width )
{
switch ( param ) {
case TEGRA_PINCONF_PARAM_PULL :
* bank = g - > pupd_bank ;
* reg = g - > pupd_reg ;
* bit = g - > pupd_bit ;
* width = 2 ;
break ;
case TEGRA_PINCONF_PARAM_TRISTATE :
* bank = g - > tri_bank ;
* reg = g - > tri_reg ;
* bit = g - > tri_bit ;
* width = 1 ;
break ;
case TEGRA_PINCONF_PARAM_ENABLE_INPUT :
* bank = g - > einput_bank ;
* reg = g - > einput_reg ;
* bit = g - > einput_bit ;
* width = 1 ;
break ;
case TEGRA_PINCONF_PARAM_OPEN_DRAIN :
* bank = g - > odrain_bank ;
* reg = g - > odrain_reg ;
* bit = g - > odrain_bit ;
* width = 1 ;
break ;
case TEGRA_PINCONF_PARAM_LOCK :
* bank = g - > lock_bank ;
* reg = g - > lock_reg ;
* bit = g - > lock_bit ;
* width = 1 ;
break ;
case TEGRA_PINCONF_PARAM_IORESET :
* bank = g - > ioreset_bank ;
* reg = g - > ioreset_reg ;
* bit = g - > ioreset_bit ;
* width = 1 ;
break ;
2013-01-08 11:32:36 +04:00
case TEGRA_PINCONF_PARAM_RCV_SEL :
* bank = g - > rcv_sel_bank ;
* reg = g - > rcv_sel_reg ;
* bit = g - > rcv_sel_bit ;
* width = 1 ;
break ;
2012-02-02 01:04:47 +04:00
case TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE :
* bank = g - > drv_bank ;
* reg = g - > drv_reg ;
* bit = g - > hsm_bit ;
* width = 1 ;
break ;
case TEGRA_PINCONF_PARAM_SCHMITT :
* bank = g - > drv_bank ;
* reg = g - > drv_reg ;
* bit = g - > schmitt_bit ;
* width = 1 ;
break ;
case TEGRA_PINCONF_PARAM_LOW_POWER_MODE :
* bank = g - > drv_bank ;
* reg = g - > drv_reg ;
* bit = g - > lpmd_bit ;
2012-10-17 15:39:36 +04:00
* width = 2 ;
2012-02-02 01:04:47 +04:00
break ;
case TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH :
* bank = g - > drv_bank ;
* reg = g - > drv_reg ;
* bit = g - > drvdn_bit ;
* width = g - > drvdn_width ;
break ;
case TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH :
* bank = g - > drv_bank ;
* reg = g - > drv_reg ;
* bit = g - > drvup_bit ;
* width = g - > drvup_width ;
break ;
case TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING :
* bank = g - > drv_bank ;
* reg = g - > drv_reg ;
* bit = g - > slwf_bit ;
* width = g - > slwf_width ;
break ;
case TEGRA_PINCONF_PARAM_SLEW_RATE_RISING :
* bank = g - > drv_bank ;
* reg = g - > drv_reg ;
* bit = g - > slwr_bit ;
* width = g - > slwr_width ;
break ;
2013-01-08 11:32:36 +04:00
case TEGRA_PINCONF_PARAM_DRIVE_TYPE :
* bank = g - > drvtype_bank ;
* reg = g - > drvtype_reg ;
* bit = g - > drvtype_bit ;
* width = 2 ;
break ;
2012-02-02 01:04:47 +04:00
default :
dev_err ( pmx - > dev , " Invalid config param %04x \n " , param ) ;
return - ENOTSUPP ;
}
if ( * reg < 0 ) {
2012-04-12 01:42:56 +04:00
if ( report_err )
dev_err ( pmx - > dev ,
" Config param %04x not supported on group %s \n " ,
param , g - > name ) ;
2012-02-02 01:04:47 +04:00
return - ENOTSUPP ;
}
return 0 ;
}
static int tegra_pinconf_get ( struct pinctrl_dev * pctldev ,
unsigned pin , unsigned long * config )
{
2012-04-23 20:05:22 +04:00
dev_err ( pctldev - > dev , " pin_config_get op not supported \n " ) ;
2012-02-02 01:04:47 +04:00
return - ENOTSUPP ;
}
static int tegra_pinconf_set ( struct pinctrl_dev * pctldev ,
unsigned pin , unsigned long config )
{
2012-04-23 20:05:22 +04:00
dev_err ( pctldev - > dev , " pin_config_set op not supported \n " ) ;
2012-02-02 01:04:47 +04:00
return - ENOTSUPP ;
}
static int tegra_pinconf_group_get ( struct pinctrl_dev * pctldev ,
unsigned group , unsigned long * config )
{
struct tegra_pmx * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM ( * config ) ;
u16 arg ;
const struct tegra_pingroup * g ;
int ret ;
s8 bank , bit , width ;
s16 reg ;
u32 val , mask ;
g = & pmx - > soc - > groups [ group ] ;
2012-04-12 01:42:56 +04:00
ret = tegra_pinconf_reg ( pmx , g , param , true , & bank , & reg , & bit ,
& width ) ;
2012-02-02 01:04:47 +04:00
if ( ret < 0 )
return ret ;
val = pmx_readl ( pmx , bank , reg ) ;
mask = ( 1 < < width ) - 1 ;
arg = ( val > > bit ) & mask ;
* config = TEGRA_PINCONF_PACK ( param , arg ) ;
return 0 ;
}
static int tegra_pinconf_group_set ( struct pinctrl_dev * pctldev ,
unsigned group , unsigned long config )
{
struct tegra_pmx * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM ( config ) ;
u16 arg = TEGRA_PINCONF_UNPACK_ARG ( config ) ;
const struct tegra_pingroup * g ;
int ret ;
s8 bank , bit , width ;
s16 reg ;
u32 val , mask ;
g = & pmx - > soc - > groups [ group ] ;
2012-04-12 01:42:56 +04:00
ret = tegra_pinconf_reg ( pmx , g , param , true , & bank , & reg , & bit ,
& width ) ;
2012-02-02 01:04:47 +04:00
if ( ret < 0 )
return ret ;
val = pmx_readl ( pmx , bank , reg ) ;
/* LOCK can't be cleared */
if ( param = = TEGRA_PINCONF_PARAM_LOCK ) {
2012-04-23 20:05:22 +04:00
if ( ( val & BIT ( bit ) ) & & ! arg ) {
dev_err ( pctldev - > dev , " LOCK bit cannot be cleared \n " ) ;
2012-02-02 01:04:47 +04:00
return - EINVAL ;
2012-04-23 20:05:22 +04:00
}
2012-02-02 01:04:47 +04:00
}
/* Special-case Boolean values; allow any non-zero as true */
if ( width = = 1 )
arg = ! ! arg ;
/* Range-check user-supplied value */
mask = ( 1 < < width ) - 1 ;
2012-04-23 20:05:22 +04:00
if ( arg & ~ mask ) {
dev_err ( pctldev - > dev ,
" config %lx: %x too big for %d bit register \n " ,
config , arg , width ) ;
2012-02-02 01:04:47 +04:00
return - EINVAL ;
2012-04-23 20:05:22 +04:00
}
2012-02-02 01:04:47 +04:00
/* Update register */
val & = ~ ( mask < < bit ) ;
val | = arg < < bit ;
pmx_writel ( pmx , val , bank , reg ) ;
return 0 ;
}
2012-04-12 01:42:56 +04:00
# ifdef CONFIG_DEBUG_FS
2012-02-02 01:04:47 +04:00
static void tegra_pinconf_dbg_show ( struct pinctrl_dev * pctldev ,
struct seq_file * s , unsigned offset )
{
}
2012-04-12 01:42:56 +04:00
static const char * strip_prefix ( const char * s )
{
const char * comma = strchr ( s , ' , ' ) ;
if ( ! comma )
return s ;
return comma + 1 ;
}
2012-02-02 01:04:47 +04:00
static void tegra_pinconf_group_dbg_show ( struct pinctrl_dev * pctldev ,
2012-04-12 01:42:56 +04:00
struct seq_file * s , unsigned group )
{
struct tegra_pmx * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
const struct tegra_pingroup * g ;
int i , ret ;
s8 bank , bit , width ;
s16 reg ;
u32 val ;
g = & pmx - > soc - > groups [ group ] ;
for ( i = 0 ; i < ARRAY_SIZE ( cfg_params ) ; i + + ) {
ret = tegra_pinconf_reg ( pmx , g , cfg_params [ i ] . param , false ,
& bank , & reg , & bit , & width ) ;
if ( ret < 0 )
continue ;
val = pmx_readl ( pmx , bank , reg ) ;
val > > = bit ;
val & = ( 1 < < width ) - 1 ;
seq_printf ( s , " \n \t %s=%u " ,
strip_prefix ( cfg_params [ i ] . property ) , val ) ;
}
}
static void tegra_pinconf_config_dbg_show ( struct pinctrl_dev * pctldev ,
struct seq_file * s ,
unsigned long config )
2012-02-02 01:04:47 +04:00
{
2012-04-12 01:42:56 +04:00
enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM ( config ) ;
u16 arg = TEGRA_PINCONF_UNPACK_ARG ( config ) ;
const char * pname = " unknown " ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( cfg_params ) ; i + + ) {
if ( cfg_params [ i ] . param = = param ) {
pname = cfg_params [ i ] . property ;
break ;
}
}
seq_printf ( s , " %s=%d " , strip_prefix ( pname ) , arg ) ;
2012-02-02 01:04:47 +04:00
}
2012-04-12 01:42:56 +04:00
# endif
2012-02-02 01:04:47 +04:00
2013-02-16 13:25:07 +04:00
static const struct pinconf_ops tegra_pinconf_ops = {
2012-02-02 01:04:47 +04:00
. pin_config_get = tegra_pinconf_get ,
. pin_config_set = tegra_pinconf_set ,
. pin_config_group_get = tegra_pinconf_group_get ,
. pin_config_group_set = tegra_pinconf_group_set ,
2012-04-12 01:42:56 +04:00
# ifdef CONFIG_DEBUG_FS
2012-02-02 01:04:47 +04:00
. pin_config_dbg_show = tegra_pinconf_dbg_show ,
. pin_config_group_dbg_show = tegra_pinconf_group_dbg_show ,
2012-04-12 01:42:56 +04:00
. pin_config_config_dbg_show = tegra_pinconf_config_dbg_show ,
# endif
2012-02-02 01:04:47 +04:00
} ;
static struct pinctrl_gpio_range tegra_pinctrl_gpio_range = {
. name = " Tegra GPIOs " ,
. id = 0 ,
. base = 0 ,
} ;
static struct pinctrl_desc tegra_pinctrl_desc = {
. pctlops = & tegra_pinctrl_ops ,
. pmxops = & tegra_pinmux_ops ,
. confops = & tegra_pinconf_ops ,
. owner = THIS_MODULE ,
} ;
2012-12-22 01:10:23 +04:00
int tegra_pinctrl_probe ( struct platform_device * pdev ,
2012-04-11 22:53:09 +04:00
const struct tegra_pinctrl_soc_data * soc_data )
2012-02-02 01:04:47 +04:00
{
struct tegra_pmx * pmx ;
struct resource * res ;
int i ;
pmx = devm_kzalloc ( & pdev - > dev , sizeof ( * pmx ) , GFP_KERNEL ) ;
if ( ! pmx ) {
dev_err ( & pdev - > dev , " Can't alloc tegra_pmx \n " ) ;
return - ENOMEM ;
}
pmx - > dev = & pdev - > dev ;
2012-04-11 22:53:09 +04:00
pmx - > soc = soc_data ;
2012-02-02 01:04:47 +04:00
tegra_pinctrl_gpio_range . npins = pmx - > soc - > ngpios ;
2012-04-11 22:53:09 +04:00
tegra_pinctrl_desc . name = dev_name ( & pdev - > dev ) ;
2012-02-02 01:04:47 +04:00
tegra_pinctrl_desc . pins = pmx - > soc - > pins ;
tegra_pinctrl_desc . npins = pmx - > soc - > npins ;
for ( i = 0 ; ; i + + ) {
res = platform_get_resource ( pdev , IORESOURCE_MEM , i ) ;
if ( ! res )
break ;
}
pmx - > nbanks = i ;
pmx - > regs = devm_kzalloc ( & pdev - > dev , pmx - > nbanks * sizeof ( * pmx - > regs ) ,
GFP_KERNEL ) ;
if ( ! pmx - > regs ) {
dev_err ( & pdev - > dev , " Can't alloc regs pointer \n " ) ;
return - ENODEV ;
}
for ( i = 0 ; i < pmx - > nbanks ; i + + ) {
res = platform_get_resource ( pdev , IORESOURCE_MEM , i ) ;
if ( ! res ) {
dev_err ( & pdev - > dev , " Missing MEM resource \n " ) ;
return - ENODEV ;
}
if ( ! devm_request_mem_region ( & pdev - > dev , res - > start ,
resource_size ( res ) ,
dev_name ( & pdev - > dev ) ) ) {
dev_err ( & pdev - > dev ,
" Couldn't request MEM resource %d \n " , i ) ;
return - ENODEV ;
}
pmx - > regs [ i ] = devm_ioremap ( & pdev - > dev , res - > start ,
resource_size ( res ) ) ;
if ( ! pmx - > regs [ i ] ) {
dev_err ( & pdev - > dev , " Couldn't ioremap regs %d \n " , i ) ;
return - ENODEV ;
}
}
pmx - > pctl = pinctrl_register ( & tegra_pinctrl_desc , & pdev - > dev , pmx ) ;
2012-06-18 21:44:31 +04:00
if ( ! pmx - > pctl ) {
2012-02-02 01:04:47 +04:00
dev_err ( & pdev - > dev , " Couldn't register pinctrl driver \n " ) ;
2012-06-18 21:44:31 +04:00
return - ENODEV ;
2012-02-02 01:04:47 +04:00
}
pinctrl_add_gpio_range ( pmx - > pctl , & tegra_pinctrl_gpio_range ) ;
platform_set_drvdata ( pdev , pmx ) ;
dev_dbg ( & pdev - > dev , " Probed Tegra pinctrl driver \n " ) ;
return 0 ;
}
2012-04-11 22:53:09 +04:00
EXPORT_SYMBOL_GPL ( tegra_pinctrl_probe ) ;
2012-02-02 01:04:47 +04:00
2012-11-19 22:26:06 +04:00
int tegra_pinctrl_remove ( struct platform_device * pdev )
2012-02-02 01:04:47 +04:00
{
struct tegra_pmx * pmx = platform_get_drvdata ( pdev ) ;
pinctrl_unregister ( pmx - > pctl ) ;
return 0 ;
}
2012-04-11 22:53:09 +04:00
EXPORT_SYMBOL_GPL ( tegra_pinctrl_remove ) ;