2012-07-10 12:08:14 +09:00
/*
* SuperH Pin Function Controller pinmux support .
*
* Copyright ( C ) 2012 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*/
2012-07-20 16:18:21 +09:00
2012-12-15 23:50:47 +01:00
# define DRV_NAME "sh-pfc"
2012-07-10 12:08:14 +09:00
2012-12-15 23:50:48 +01:00
# include <linux/device.h>
2012-12-15 23:50:52 +01:00
# include <linux/err.h>
2012-07-10 12:08:14 +09:00
# include <linux/init.h>
# include <linux/module.h>
# include <linux/pinctrl/consumer.h>
# include <linux/pinctrl/pinconf.h>
# include <linux/pinctrl/pinconf-generic.h>
2012-12-15 23:50:52 +01:00
# include <linux/pinctrl/pinctrl.h>
# include <linux/pinctrl/pinmux.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
2012-07-10 12:08:14 +09:00
2012-12-15 23:50:44 +01:00
# include "core.h"
2013-03-10 16:44:02 +01:00
# include "../core.h"
# include "../pinconf.h"
2012-12-15 23:50:44 +01:00
2013-03-08 17:43:54 +01:00
struct sh_pfc_pin_config {
u32 type ;
} ;
2012-07-10 12:08:14 +09:00
struct sh_pfc_pinctrl {
struct pinctrl_dev * pctl ;
2013-02-16 16:38:30 +01:00
struct pinctrl_desc pctl_desc ;
2012-07-10 12:08:14 +09:00
struct sh_pfc * pfc ;
2013-01-03 14:33:13 +01:00
struct pinctrl_pin_desc * pins ;
2013-03-08 17:43:54 +01:00
struct sh_pfc_pin_config * configs ;
2012-07-10 12:08:14 +09:00
} ;
2012-07-17 15:48:18 +09:00
static int sh_pfc_get_groups_count ( struct pinctrl_dev * pctldev )
2012-07-10 12:08:14 +09:00
{
2012-07-17 15:48:18 +09:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2013-01-03 14:33:13 +01:00
return pmx - > pfc - > info - > nr_groups ;
2012-07-10 12:08:14 +09:00
}
2012-07-17 15:48:18 +09:00
static const char * sh_pfc_get_group_name ( struct pinctrl_dev * pctldev ,
2012-07-10 12:08:14 +09:00
unsigned selector )
{
2012-07-17 15:48:18 +09:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2013-01-03 14:33:13 +01:00
return pmx - > pfc - > info - > groups [ selector ] . name ;
2012-07-10 12:08:14 +09:00
}
2013-01-03 14:33:13 +01:00
static int sh_pfc_get_group_pins ( struct pinctrl_dev * pctldev , unsigned selector ,
2012-07-10 12:08:14 +09:00
const unsigned * * pins , unsigned * num_pins )
{
2012-07-17 15:48:18 +09:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2013-01-03 14:33:13 +01:00
* pins = pmx - > pfc - > info - > groups [ selector ] . pins ;
* num_pins = pmx - > pfc - > info - > groups [ selector ] . nr_pins ;
2012-07-17 15:48:18 +09:00
return 0 ;
2012-07-10 12:08:14 +09:00
}
2012-07-20 16:39:09 +09:00
static void sh_pfc_pin_dbg_show ( struct pinctrl_dev * pctldev , struct seq_file * s ,
unsigned offset )
{
seq_printf ( s , " %s " , DRV_NAME ) ;
}
2013-02-15 16:04:47 +01:00
static const struct pinctrl_ops sh_pfc_pinctrl_ops = {
2012-07-17 15:48:18 +09:00
. get_groups_count = sh_pfc_get_groups_count ,
. get_group_name = sh_pfc_get_group_name ,
2012-07-10 12:08:14 +09:00
. get_group_pins = sh_pfc_get_group_pins ,
2012-07-20 16:39:09 +09:00
. pin_dbg_show = sh_pfc_pin_dbg_show ,
2012-07-10 12:08:14 +09:00
} ;
2012-07-11 17:17:10 +09:00
static int sh_pfc_get_functions_count ( struct pinctrl_dev * pctldev )
{
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2013-01-03 14:33:13 +01:00
return pmx - > pfc - > info - > nr_functions ;
2012-07-11 17:17:10 +09:00
}
static const char * sh_pfc_get_function_name ( struct pinctrl_dev * pctldev ,
unsigned selector )
{
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2013-01-03 14:33:13 +01:00
return pmx - > pfc - > info - > functions [ selector ] . name ;
2012-07-11 17:17:10 +09:00
}
2012-07-10 12:08:14 +09:00
2013-01-03 14:33:13 +01:00
static int sh_pfc_get_function_groups ( struct pinctrl_dev * pctldev ,
unsigned selector ,
2012-07-10 12:08:14 +09:00
const char * const * * groups ,
unsigned * const num_groups )
{
2012-07-11 17:17:10 +09:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2013-01-03 14:33:13 +01:00
* groups = pmx - > pfc - > info - > functions [ selector ] . groups ;
* num_groups = pmx - > pfc - > info - > functions [ selector ] . nr_groups ;
2012-07-11 17:17:10 +09:00
2012-07-10 12:08:14 +09:00
return 0 ;
}
2013-01-03 14:33:13 +01:00
static int sh_pfc_func_enable ( struct pinctrl_dev * pctldev , unsigned selector ,
2012-07-10 12:08:14 +09:00
unsigned group )
{
2013-01-03 14:33:13 +01:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
struct sh_pfc * pfc = pmx - > pfc ;
const struct sh_pfc_pin_group * grp = & pfc - > info - > groups [ group ] ;
unsigned long flags ;
unsigned int i ;
2013-03-10 16:38:23 +01:00
int ret = 0 ;
2013-01-03 14:33:13 +01:00
spin_lock_irqsave ( & pfc - > lock , flags ) ;
2013-03-10 17:25:29 +01:00
for ( i = 0 ; i < grp - > nr_pins ; + + i ) {
int idx = sh_pfc_get_pin_index ( pfc , grp - > pins [ i ] ) ;
struct sh_pfc_pin_config * cfg = & pmx - > configs [ idx ] ;
if ( cfg - > type ! = PINMUX_TYPE_NONE ) {
ret = - EBUSY ;
goto done ;
}
}
2013-01-03 14:33:13 +01:00
for ( i = 0 ; i < grp - > nr_pins ; + + i ) {
2013-03-10 16:38:23 +01:00
ret = sh_pfc_config_mux ( pfc , grp - > mux [ i ] , PINMUX_TYPE_FUNCTION ) ;
if ( ret < 0 )
break ;
2013-01-03 14:33:13 +01:00
}
2013-03-10 17:25:29 +01:00
done :
2013-01-03 14:33:13 +01:00
spin_unlock_irqrestore ( & pfc - > lock , flags ) ;
return ret ;
2012-07-10 12:08:14 +09:00
}
2013-01-03 14:33:13 +01:00
static void sh_pfc_func_disable ( struct pinctrl_dev * pctldev , unsigned selector ,
2012-07-10 12:08:14 +09:00
unsigned group )
{
2013-03-10 17:25:29 +01:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
struct sh_pfc * pfc = pmx - > pfc ;
const struct sh_pfc_pin_group * grp = & pfc - > info - > groups [ group ] ;
unsigned long flags ;
unsigned int i ;
spin_lock_irqsave ( & pfc - > lock , flags ) ;
for ( i = 0 ; i < grp - > nr_pins ; + + i ) {
int idx = sh_pfc_get_pin_index ( pfc , grp - > pins [ i ] ) ;
struct sh_pfc_pin_config * cfg = & pmx - > configs [ idx ] ;
cfg - > type = PINMUX_TYPE_NONE ;
}
spin_unlock_irqrestore ( & pfc - > lock , flags ) ;
2012-07-10 12:08:14 +09:00
}
static int sh_pfc_gpio_request_enable ( struct pinctrl_dev * pctldev ,
struct pinctrl_gpio_range * range ,
unsigned offset )
{
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
struct sh_pfc * pfc = pmx - > pfc ;
2013-03-08 17:43:54 +01:00
int idx = sh_pfc_get_pin_index ( pfc , offset ) ;
struct sh_pfc_pin_config * cfg = & pmx - > configs [ idx ] ;
2012-07-10 12:08:14 +09:00
unsigned long flags ;
2013-03-08 17:43:54 +01:00
int ret ;
2012-07-10 12:08:14 +09:00
spin_lock_irqsave ( & pfc - > lock , flags ) ;
2013-03-10 17:25:29 +01:00
if ( cfg - > type ! = PINMUX_TYPE_NONE ) {
2013-03-10 18:00:02 +01:00
dev_err ( pfc - > dev ,
" Pin %u is busy, can't configure it as GPIO. \n " ,
offset ) ;
2013-03-10 17:25:29 +01:00
ret = - EBUSY ;
goto done ;
2012-07-11 17:17:10 +09:00
}
2012-07-10 12:08:14 +09:00
2013-03-10 17:30:25 +01:00
if ( ! pfc - > gpio ) {
/* If GPIOs are handled externally the pin mux type need to be
* set to GPIO here .
*/
const struct sh_pfc_pin * pin = & pfc - > info - > pins [ idx ] ;
ret = sh_pfc_config_mux ( pfc , pin - > enum_id , PINMUX_TYPE_GPIO ) ;
if ( ret < 0 )
goto done ;
}
2013-03-10 17:25:29 +01:00
cfg - > type = PINMUX_TYPE_GPIO ;
2012-07-10 12:08:14 +09:00
ret = 0 ;
2013-03-10 17:25:29 +01:00
done :
2012-07-10 12:08:14 +09:00
spin_unlock_irqrestore ( & pfc - > lock , flags ) ;
return ret ;
}
static void sh_pfc_gpio_disable_free ( struct pinctrl_dev * pctldev ,
struct pinctrl_gpio_range * range ,
unsigned offset )
{
2013-03-10 17:25:29 +01:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
struct sh_pfc * pfc = pmx - > pfc ;
int idx = sh_pfc_get_pin_index ( pfc , offset ) ;
struct sh_pfc_pin_config * cfg = & pmx - > configs [ idx ] ;
unsigned long flags ;
spin_lock_irqsave ( & pfc - > lock , flags ) ;
cfg - > type = PINMUX_TYPE_NONE ;
spin_unlock_irqrestore ( & pfc - > lock , flags ) ;
2012-07-10 12:08:14 +09:00
}
static int sh_pfc_gpio_set_direction ( struct pinctrl_dev * pctldev ,
struct pinctrl_gpio_range * range ,
unsigned offset , bool input )
{
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2013-03-10 16:55:19 +01:00
struct sh_pfc * pfc = pmx - > pfc ;
int new_type = input ? PINMUX_TYPE_INPUT : PINMUX_TYPE_OUTPUT ;
int idx = sh_pfc_get_pin_index ( pfc , offset ) ;
const struct sh_pfc_pin * pin = & pfc - > info - > pins [ idx ] ;
2013-03-10 17:25:29 +01:00
struct sh_pfc_pin_config * cfg = & pmx - > configs [ idx ] ;
2013-03-10 16:55:19 +01:00
unsigned long flags ;
2013-03-13 18:18:30 +01:00
unsigned int dir ;
2013-03-10 16:55:19 +01:00
int ret ;
2012-07-10 12:08:14 +09:00
2013-03-13 18:18:30 +01:00
/* Check if the requested direction is supported by the pin. Not all SoC
* provide pin config data , so perform the check conditionally .
*/
if ( pin - > configs ) {
dir = input ? SH_PFC_PIN_CFG_INPUT : SH_PFC_PIN_CFG_OUTPUT ;
if ( ! ( pin - > configs & dir ) )
return - EINVAL ;
}
2013-03-10 16:55:19 +01:00
spin_lock_irqsave ( & pfc - > lock , flags ) ;
2013-03-10 17:25:29 +01:00
ret = sh_pfc_config_mux ( pfc , pin - > enum_id , new_type ) ;
2013-03-10 16:55:19 +01:00
if ( ret < 0 )
goto done ;
cfg - > type = new_type ;
done :
spin_unlock_irqrestore ( & pfc - > lock , flags ) ;
return ret ;
2012-07-10 12:08:14 +09:00
}
2013-02-15 16:04:47 +01:00
static const struct pinmux_ops sh_pfc_pinmux_ops = {
2012-07-11 17:17:10 +09:00
. get_functions_count = sh_pfc_get_functions_count ,
. get_function_name = sh_pfc_get_function_name ,
2012-07-10 12:08:14 +09:00
. get_function_groups = sh_pfc_get_function_groups ,
2013-01-03 14:33:13 +01:00
. enable = sh_pfc_func_enable ,
. disable = sh_pfc_func_disable ,
2012-07-10 12:08:14 +09:00
. gpio_request_enable = sh_pfc_gpio_request_enable ,
. gpio_disable_free = sh_pfc_gpio_disable_free ,
. gpio_set_direction = sh_pfc_gpio_set_direction ,
} ;
2013-03-10 16:44:02 +01:00
/* Check whether the requested parameter is supported for a pin. */
static bool sh_pfc_pinconf_validate ( struct sh_pfc * pfc , unsigned int _pin ,
enum pin_config_param param )
{
int idx = sh_pfc_get_pin_index ( pfc , _pin ) ;
const struct sh_pfc_pin * pin = & pfc - > info - > pins [ idx ] ;
switch ( param ) {
case PIN_CONFIG_BIAS_DISABLE :
return true ;
case PIN_CONFIG_BIAS_PULL_UP :
return pin - > configs & SH_PFC_PIN_CFG_PULL_UP ;
case PIN_CONFIG_BIAS_PULL_DOWN :
return pin - > configs & SH_PFC_PIN_CFG_PULL_DOWN ;
default :
return false ;
}
}
2013-02-14 22:35:09 +01:00
static int sh_pfc_pinconf_get ( struct pinctrl_dev * pctldev , unsigned _pin ,
2012-07-10 12:08:14 +09:00
unsigned long * config )
{
2012-07-20 16:39:09 +09:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
struct sh_pfc * pfc = pmx - > pfc ;
2013-03-10 16:44:02 +01:00
enum pin_config_param param = pinconf_to_config_param ( * config ) ;
unsigned long flags ;
unsigned int bias ;
if ( ! sh_pfc_pinconf_validate ( pfc , _pin , param ) )
return - ENOTSUPP ;
switch ( param ) {
case PIN_CONFIG_BIAS_DISABLE :
case PIN_CONFIG_BIAS_PULL_UP :
case PIN_CONFIG_BIAS_PULL_DOWN :
if ( ! pfc - > info - > ops | | ! pfc - > info - > ops - > get_bias )
return - ENOTSUPP ;
spin_lock_irqsave ( & pfc - > lock , flags ) ;
bias = pfc - > info - > ops - > get_bias ( pfc , _pin ) ;
spin_unlock_irqrestore ( & pfc - > lock , flags ) ;
if ( bias ! = param )
return - EINVAL ;
* config = 0 ;
break ;
2012-07-11 17:17:10 +09:00
2013-03-10 16:44:02 +01:00
default :
return - ENOTSUPP ;
}
2012-07-11 17:17:10 +09:00
2012-07-20 16:39:09 +09:00
return 0 ;
2012-07-10 12:08:14 +09:00
}
2013-03-10 16:44:02 +01:00
static int sh_pfc_pinconf_set ( struct pinctrl_dev * pctldev , unsigned _pin ,
2012-07-10 12:08:14 +09:00
unsigned long config )
{
2012-07-20 16:39:09 +09:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2013-03-10 16:44:02 +01:00
struct sh_pfc * pfc = pmx - > pfc ;
enum pin_config_param param = pinconf_to_config_param ( config ) ;
unsigned long flags ;
2012-07-20 16:39:09 +09:00
2013-03-10 16:44:02 +01:00
if ( ! sh_pfc_pinconf_validate ( pfc , _pin , param ) )
return - ENOTSUPP ;
2012-07-20 16:39:09 +09:00
2013-03-10 16:44:02 +01:00
switch ( param ) {
case PIN_CONFIG_BIAS_PULL_UP :
case PIN_CONFIG_BIAS_PULL_DOWN :
case PIN_CONFIG_BIAS_DISABLE :
if ( ! pfc - > info - > ops | | ! pfc - > info - > ops - > set_bias )
return - ENOTSUPP ;
spin_lock_irqsave ( & pfc - > lock , flags ) ;
pfc - > info - > ops - > set_bias ( pfc , _pin , param ) ;
spin_unlock_irqrestore ( & pfc - > lock , flags ) ;
break ;
default :
return - ENOTSUPP ;
}
return 0 ;
2012-07-20 16:39:09 +09:00
}
2013-03-10 16:44:02 +01:00
static int sh_pfc_pinconf_group_set ( struct pinctrl_dev * pctldev , unsigned group ,
unsigned long config )
2012-07-20 16:39:09 +09:00
{
2013-03-10 16:44:02 +01:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
const unsigned int * pins ;
unsigned int num_pins ;
unsigned int i ;
pins = pmx - > pfc - > info - > groups [ group ] . pins ;
num_pins = pmx - > pfc - > info - > groups [ group ] . nr_pins ;
for ( i = 0 ; i < num_pins ; + + i )
sh_pfc_pinconf_set ( pctldev , pins [ i ] , config ) ;
return 0 ;
2012-07-10 12:08:14 +09:00
}
2013-02-15 16:04:47 +01:00
static const struct pinconf_ops sh_pfc_pinconf_ops = {
2013-03-10 16:44:02 +01:00
. is_generic = true ,
. pin_config_get = sh_pfc_pinconf_get ,
. pin_config_set = sh_pfc_pinconf_set ,
. pin_config_group_set = sh_pfc_pinconf_group_set ,
. pin_config_config_dbg_show = pinconf_generic_dump_config ,
2012-07-10 12:08:14 +09:00
} ;
2013-02-15 01:33:38 +01:00
/* PFC ranges -> pinctrl pin descs */
static int sh_pfc_map_pins ( struct sh_pfc * pfc , struct sh_pfc_pinctrl * pmx )
2012-07-10 12:08:14 +09:00
{
2013-02-15 01:33:38 +01:00
const struct pinmux_range * ranges ;
struct pinmux_range def_range ;
unsigned int nr_ranges ;
unsigned int nr_pins ;
unsigned int i ;
if ( pfc - > info - > ranges = = NULL ) {
def_range . begin = 0 ;
def_range . end = pfc - > info - > nr_pins - 1 ;
ranges = & def_range ;
nr_ranges = 1 ;
} else {
ranges = pfc - > info - > ranges ;
nr_ranges = pfc - > info - > nr_ranges ;
}
2012-07-10 12:08:14 +09:00
2013-01-03 14:33:13 +01:00
pmx - > pins = devm_kzalloc ( pfc - > dev ,
sizeof ( * pmx - > pins ) * pfc - > info - > nr_pins ,
2012-12-15 23:50:48 +01:00
GFP_KERNEL ) ;
2013-01-03 14:33:13 +01:00
if ( unlikely ( ! pmx - > pins ) )
2012-07-10 12:08:14 +09:00
return - ENOMEM ;
2013-03-08 17:43:54 +01:00
pmx - > configs = devm_kzalloc ( pfc - > dev ,
sizeof ( * pmx - > configs ) * pfc - > info - > nr_pins ,
GFP_KERNEL ) ;
if ( unlikely ( ! pmx - > configs ) )
return - ENOMEM ;
2013-02-15 01:33:38 +01:00
for ( i = 0 , nr_pins = 0 ; i < nr_ranges ; + + i ) {
const struct pinmux_range * range = & ranges [ i ] ;
unsigned int number ;
for ( number = range - > begin ; number < = range - > end ;
number + + , nr_pins + + ) {
2013-03-08 17:43:54 +01:00
struct sh_pfc_pin_config * cfg = & pmx - > configs [ nr_pins ] ;
2013-01-03 14:33:13 +01:00
struct pinctrl_pin_desc * pin = & pmx - > pins [ nr_pins ] ;
2013-02-16 18:47:05 +01:00
const struct sh_pfc_pin * info =
& pfc - > info - > pins [ nr_pins ] ;
2012-07-10 12:08:14 +09:00
2013-02-15 01:33:38 +01:00
pin - > number = number ;
pin - > name = info - > name ;
2013-03-10 17:25:29 +01:00
cfg - > type = PINMUX_TYPE_NONE ;
2013-02-15 01:33:38 +01:00
}
2012-07-10 12:08:14 +09:00
}
2013-02-15 01:33:38 +01:00
pfc - > nr_pins = ranges [ nr_ranges - 1 ] . end + 1 ;
return nr_ranges ;
2012-07-10 12:08:14 +09:00
}
2012-12-15 23:50:47 +01:00
int sh_pfc_register_pinctrl ( struct sh_pfc * pfc )
2012-07-10 12:08:14 +09:00
{
2012-12-15 23:50:47 +01:00
struct sh_pfc_pinctrl * pmx ;
2013-02-15 01:33:38 +01:00
int nr_ranges ;
2012-07-10 12:08:14 +09:00
2012-12-15 23:50:48 +01:00
pmx = devm_kzalloc ( pfc - > dev , sizeof ( * pmx ) , GFP_KERNEL ) ;
2012-12-15 23:50:47 +01:00
if ( unlikely ( ! pmx ) )
return - ENOMEM ;
pmx - > pfc = pfc ;
pfc - > pinctrl = pmx ;
2012-07-10 12:08:14 +09:00
2013-02-15 01:33:38 +01:00
nr_ranges = sh_pfc_map_pins ( pfc , pmx ) ;
if ( unlikely ( nr_ranges < 0 ) )
return nr_ranges ;
2012-07-10 12:08:14 +09:00
2013-02-16 16:38:30 +01:00
pmx - > pctl_desc . name = DRV_NAME ;
pmx - > pctl_desc . owner = THIS_MODULE ;
pmx - > pctl_desc . pctlops = & sh_pfc_pinctrl_ops ;
pmx - > pctl_desc . pmxops = & sh_pfc_pinmux_ops ;
pmx - > pctl_desc . confops = & sh_pfc_pinconf_ops ;
2013-01-03 14:33:13 +01:00
pmx - > pctl_desc . pins = pmx - > pins ;
2013-02-15 01:33:38 +01:00
pmx - > pctl_desc . npins = pfc - > info - > nr_pins ;
2013-02-16 16:38:30 +01:00
pmx - > pctl = pinctrl_register ( & pmx - > pctl_desc , pfc - > dev , pmx ) ;
2013-03-11 22:08:12 +08:00
if ( pmx - > pctl = = NULL )
return - EINVAL ;
2012-07-10 12:08:14 +09:00
return 0 ;
}
2012-12-15 23:50:47 +01:00
int sh_pfc_unregister_pinctrl ( struct sh_pfc * pfc )
2012-07-10 12:08:14 +09:00
{
2012-12-15 23:50:47 +01:00
struct sh_pfc_pinctrl * pmx = pfc - > pinctrl ;
2012-07-10 12:08:14 +09:00
pinctrl_unregister ( pmx - > pctl ) ;
2012-12-15 23:50:47 +01:00
pfc - > pinctrl = NULL ;
2012-07-10 12:08:14 +09:00
return 0 ;
}