2012-07-10 07:08:14 +04: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 11:18:21 +04:00
2012-12-16 02:50:47 +04:00
# define DRV_NAME "sh-pfc"
2012-07-10 07:08:14 +04:00
2012-12-16 02:50:48 +04:00
# include <linux/device.h>
2012-12-16 02:50:52 +04:00
# include <linux/err.h>
2012-07-10 07:08:14 +04:00
# include <linux/init.h>
# include <linux/module.h>
2013-06-17 22:50:02 +04:00
# include <linux/of.h>
2012-07-10 07:08:14 +04:00
# include <linux/pinctrl/consumer.h>
2013-06-17 22:50:02 +04:00
# include <linux/pinctrl/machine.h>
2012-07-10 07:08:14 +04:00
# include <linux/pinctrl/pinconf.h>
# include <linux/pinctrl/pinconf-generic.h>
2012-12-16 02:50:52 +04:00
# include <linux/pinctrl/pinctrl.h>
# include <linux/pinctrl/pinmux.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
2012-07-10 07:08:14 +04:00
2012-12-16 02:50:44 +04:00
# include "core.h"
2013-03-10 19:44:02 +04:00
# include "../core.h"
# include "../pinconf.h"
2012-12-16 02:50:44 +04:00
2013-03-08 20:43:54 +04:00
struct sh_pfc_pin_config {
u32 type ;
} ;
2012-07-10 07:08:14 +04:00
struct sh_pfc_pinctrl {
struct pinctrl_dev * pctl ;
2013-02-16 19:38:30 +04:00
struct pinctrl_desc pctl_desc ;
2012-07-10 07:08:14 +04:00
struct sh_pfc * pfc ;
2013-01-03 17:33:13 +04:00
struct pinctrl_pin_desc * pins ;
2013-03-08 20:43:54 +04:00
struct sh_pfc_pin_config * configs ;
2015-06-30 11:29:57 +03:00
const char * func_prop_name ;
const char * groups_prop_name ;
const char * pins_prop_name ;
2012-07-10 07:08:14 +04:00
} ;
2012-07-17 10:48:18 +04:00
static int sh_pfc_get_groups_count ( struct pinctrl_dev * pctldev )
2012-07-10 07:08:14 +04:00
{
2012-07-17 10:48:18 +04:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2013-01-03 17:33:13 +04:00
return pmx - > pfc - > info - > nr_groups ;
2012-07-10 07:08:14 +04:00
}
2012-07-17 10:48:18 +04:00
static const char * sh_pfc_get_group_name ( struct pinctrl_dev * pctldev ,
2012-07-10 07:08:14 +04:00
unsigned selector )
{
2012-07-17 10:48:18 +04:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2013-01-03 17:33:13 +04:00
return pmx - > pfc - > info - > groups [ selector ] . name ;
2012-07-10 07:08:14 +04:00
}
2013-01-03 17:33:13 +04:00
static int sh_pfc_get_group_pins ( struct pinctrl_dev * pctldev , unsigned selector ,
2012-07-10 07:08:14 +04:00
const unsigned * * pins , unsigned * num_pins )
{
2012-07-17 10:48:18 +04:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2013-01-03 17:33:13 +04:00
* pins = pmx - > pfc - > info - > groups [ selector ] . pins ;
* num_pins = pmx - > pfc - > info - > groups [ selector ] . nr_pins ;
2012-07-17 10:48:18 +04:00
return 0 ;
2012-07-10 07:08:14 +04:00
}
2012-07-20 11:39:09 +04: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-06-19 15:26:02 +04:00
# ifdef CONFIG_OF
2013-06-17 22:50:03 +04:00
static int sh_pfc_map_add_config ( struct pinctrl_map * map ,
const char * group_or_pin ,
enum pinctrl_map_type type ,
unsigned long * configs ,
unsigned int num_configs )
{
unsigned long * cfgs ;
cfgs = kmemdup ( configs , num_configs * sizeof ( * cfgs ) ,
GFP_KERNEL ) ;
if ( cfgs = = NULL )
return - ENOMEM ;
map - > type = type ;
map - > data . configs . group_or_pin = group_or_pin ;
map - > data . configs . configs = cfgs ;
map - > data . configs . num_configs = num_configs ;
return 0 ;
}
2015-06-30 11:29:57 +03:00
static int sh_pfc_dt_subnode_to_map ( struct pinctrl_dev * pctldev ,
struct device_node * np ,
2013-06-17 22:50:02 +04:00
struct pinctrl_map * * map ,
unsigned int * num_maps , unsigned int * index )
{
2015-06-30 11:29:57 +03:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
struct device * dev = pmx - > pfc - > dev ;
2013-06-17 22:50:02 +04:00
struct pinctrl_map * maps = * map ;
unsigned int nmaps = * num_maps ;
unsigned int idx = * index ;
2013-06-17 22:50:03 +04:00
unsigned int num_configs ;
2013-06-17 22:50:02 +04:00
const char * function = NULL ;
2013-06-17 22:50:03 +04:00
unsigned long * configs ;
2013-06-17 22:50:02 +04:00
struct property * prop ;
2013-06-17 22:50:03 +04:00
unsigned int num_groups ;
unsigned int num_pins ;
2013-06-17 22:50:02 +04:00
const char * group ;
2013-06-17 22:50:03 +04:00
const char * pin ;
2013-06-17 22:50:02 +04:00
int ret ;
2015-06-30 11:29:57 +03:00
/* Support both the old Renesas-specific properties and the new standard
* properties . Mixing old and new properties isn ' t allowed , neither
* inside a subnode nor across subnodes .
*/
if ( ! pmx - > func_prop_name ) {
if ( of_find_property ( np , " groups " , NULL ) | |
of_find_property ( np , " pins " , NULL ) ) {
pmx - > func_prop_name = " function " ;
pmx - > groups_prop_name = " groups " ;
pmx - > pins_prop_name = " pins " ;
} else {
pmx - > func_prop_name = " renesas,function " ;
pmx - > groups_prop_name = " renesas,groups " ;
pmx - > pins_prop_name = " renesas,pins " ;
}
}
2013-06-17 22:50:02 +04:00
/* Parse the function and configuration properties. At least a function
* or one configuration must be specified .
*/
2015-06-30 11:29:57 +03:00
ret = of_property_read_string ( np , pmx - > func_prop_name , & function ) ;
2013-06-17 22:50:02 +04:00
if ( ret < 0 & & ret ! = - EINVAL ) {
dev_err ( dev , " Invalid function in DT \n " ) ;
return ret ;
}
2015-01-09 18:43:46 +03:00
ret = pinconf_generic_parse_dt_config ( np , NULL , & configs , & num_configs ) ;
2013-06-17 22:50:03 +04:00
if ( ret < 0 )
return ret ;
if ( ! function & & num_configs = = 0 ) {
dev_err ( dev ,
" DT node must contain at least a function or config \n " ) ;
2015-06-30 11:29:57 +03:00
ret = - ENODEV ;
2013-06-17 22:50:02 +04:00
goto done ;
}
2013-06-17 22:50:03 +04:00
/* Count the number of pins and groups and reallocate mappings. */
2015-06-30 11:29:57 +03:00
ret = of_property_count_strings ( np , pmx - > pins_prop_name ) ;
2013-06-17 22:50:03 +04:00
if ( ret = = - EINVAL ) {
num_pins = 0 ;
} else if ( ret < 0 ) {
dev_err ( dev , " Invalid pins list in DT \n " ) ;
goto done ;
} else {
num_pins = ret ;
}
2015-06-30 11:29:57 +03:00
ret = of_property_count_strings ( np , pmx - > groups_prop_name ) ;
2013-06-17 22:50:03 +04:00
if ( ret = = - EINVAL ) {
num_groups = 0 ;
} else if ( ret < 0 ) {
2013-06-17 22:50:02 +04:00
dev_err ( dev , " Invalid pin groups list in DT \n " ) ;
goto done ;
2013-06-17 22:50:03 +04:00
} else {
num_groups = ret ;
2013-06-17 22:50:02 +04:00
}
2013-06-17 22:50:03 +04:00
if ( ! num_pins & & ! num_groups ) {
dev_err ( dev , " No pin or group provided in DT node \n " ) ;
2013-06-17 22:50:02 +04:00
ret = - ENODEV ;
goto done ;
}
2013-06-17 22:50:03 +04:00
if ( function )
nmaps + = num_groups ;
if ( configs )
nmaps + = num_pins + num_groups ;
2013-06-17 22:50:02 +04:00
maps = krealloc ( maps , sizeof ( * maps ) * nmaps , GFP_KERNEL ) ;
if ( maps = = NULL ) {
ret = - ENOMEM ;
goto done ;
}
* map = maps ;
* num_maps = nmaps ;
/* Iterate over pins and groups and create the mappings. */
2015-06-30 11:29:57 +03:00
of_property_for_each_string ( np , pmx - > groups_prop_name , prop , group ) {
2013-06-17 22:50:03 +04:00
if ( function ) {
maps [ idx ] . type = PIN_MAP_TYPE_MUX_GROUP ;
maps [ idx ] . data . mux . group = group ;
maps [ idx ] . data . mux . function = function ;
idx + + ;
}
if ( configs ) {
ret = sh_pfc_map_add_config ( & maps [ idx ] , group ,
PIN_MAP_TYPE_CONFIGS_GROUP ,
configs , num_configs ) ;
if ( ret < 0 )
goto done ;
idx + + ;
}
2013-06-17 22:50:02 +04:00
}
2013-06-17 22:50:03 +04:00
if ( ! configs ) {
ret = 0 ;
goto done ;
}
2015-06-30 11:29:57 +03:00
of_property_for_each_string ( np , pmx - > pins_prop_name , prop , pin ) {
2013-06-17 22:50:03 +04:00
ret = sh_pfc_map_add_config ( & maps [ idx ] , pin ,
PIN_MAP_TYPE_CONFIGS_PIN ,
configs , num_configs ) ;
if ( ret < 0 )
goto done ;
idx + + ;
}
2013-06-17 22:50:02 +04:00
done :
* index = idx ;
2013-06-17 22:50:03 +04:00
kfree ( configs ) ;
2013-06-17 22:50:02 +04:00
return ret ;
}
static void sh_pfc_dt_free_map ( struct pinctrl_dev * pctldev ,
struct pinctrl_map * map , unsigned num_maps )
{
2013-06-17 22:50:03 +04:00
unsigned int i ;
if ( map = = NULL )
return ;
for ( i = 0 ; i < num_maps ; + + i ) {
if ( map [ i ] . type = = PIN_MAP_TYPE_CONFIGS_GROUP | |
map [ i ] . type = = PIN_MAP_TYPE_CONFIGS_PIN )
kfree ( map [ i ] . data . configs . configs ) ;
}
2013-06-17 22:50:02 +04:00
kfree ( map ) ;
}
static int sh_pfc_dt_node_to_map ( struct pinctrl_dev * pctldev ,
struct device_node * np ,
struct pinctrl_map * * map , unsigned * num_maps )
{
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
struct device * dev = pmx - > pfc - > dev ;
struct device_node * child ;
unsigned int index ;
int ret ;
* map = NULL ;
* num_maps = 0 ;
index = 0 ;
for_each_child_of_node ( np , child ) {
2015-06-30 11:29:57 +03:00
ret = sh_pfc_dt_subnode_to_map ( pctldev , child , map , num_maps ,
2013-06-17 22:50:02 +04:00
& index ) ;
if ( ret < 0 )
goto done ;
}
/* If no mapping has been found in child nodes try the config node. */
if ( * num_maps = = 0 ) {
2015-06-30 11:29:57 +03:00
ret = sh_pfc_dt_subnode_to_map ( pctldev , np , map , num_maps ,
& index ) ;
2013-06-17 22:50:02 +04:00
if ( ret < 0 )
goto done ;
}
if ( * num_maps )
return 0 ;
dev_err ( dev , " no mapping found in node %s \n " , np - > full_name ) ;
ret = - EINVAL ;
done :
if ( ret < 0 )
sh_pfc_dt_free_map ( pctldev , * map , * num_maps ) ;
return ret ;
}
2013-06-19 15:26:02 +04:00
# endif /* CONFIG_OF */
2013-06-17 22:50:02 +04:00
2013-02-15 19:04:47 +04:00
static const struct pinctrl_ops sh_pfc_pinctrl_ops = {
2012-07-17 10:48:18 +04:00
. get_groups_count = sh_pfc_get_groups_count ,
. get_group_name = sh_pfc_get_group_name ,
2012-07-10 07:08:14 +04:00
. get_group_pins = sh_pfc_get_group_pins ,
2012-07-20 11:39:09 +04:00
. pin_dbg_show = sh_pfc_pin_dbg_show ,
2013-06-19 15:26:02 +04:00
# ifdef CONFIG_OF
2013-06-17 22:50:02 +04:00
. dt_node_to_map = sh_pfc_dt_node_to_map ,
. dt_free_map = sh_pfc_dt_free_map ,
2013-06-19 15:26:02 +04:00
# endif
2012-07-10 07:08:14 +04:00
} ;
2012-07-11 12:17:10 +04: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 17:33:13 +04:00
return pmx - > pfc - > info - > nr_functions ;
2012-07-11 12:17:10 +04: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 17:33:13 +04:00
return pmx - > pfc - > info - > functions [ selector ] . name ;
2012-07-11 12:17:10 +04:00
}
2012-07-10 07:08:14 +04:00
2013-01-03 17:33:13 +04:00
static int sh_pfc_get_function_groups ( struct pinctrl_dev * pctldev ,
unsigned selector ,
2012-07-10 07:08:14 +04:00
const char * const * * groups ,
unsigned * const num_groups )
{
2012-07-11 12:17:10 +04:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2013-01-03 17:33:13 +04:00
* groups = pmx - > pfc - > info - > functions [ selector ] . groups ;
* num_groups = pmx - > pfc - > info - > functions [ selector ] . nr_groups ;
2012-07-11 12:17:10 +04:00
2012-07-10 07:08:14 +04:00
return 0 ;
}
2014-09-03 15:02:56 +04:00
static int sh_pfc_func_set_mux ( struct pinctrl_dev * pctldev , unsigned selector ,
unsigned group )
2012-07-10 07:08:14 +04:00
{
2013-01-03 17:33:13 +04: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 19:38:23 +04:00
int ret = 0 ;
2013-01-03 17:33:13 +04:00
spin_lock_irqsave ( & pfc - > lock , flags ) ;
2013-03-10 20:25:29 +04: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 17:33:13 +04:00
for ( i = 0 ; i < grp - > nr_pins ; + + i ) {
2013-03-10 19:38:23 +04:00
ret = sh_pfc_config_mux ( pfc , grp - > mux [ i ] , PINMUX_TYPE_FUNCTION ) ;
if ( ret < 0 )
break ;
2013-01-03 17:33:13 +04:00
}
2013-03-10 20:25:29 +04:00
done :
2013-01-03 17:33:13 +04:00
spin_unlock_irqrestore ( & pfc - > lock , flags ) ;
return ret ;
2012-07-10 07:08:14 +04: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 20:43:54 +04:00
int idx = sh_pfc_get_pin_index ( pfc , offset ) ;
struct sh_pfc_pin_config * cfg = & pmx - > configs [ idx ] ;
2012-07-10 07:08:14 +04:00
unsigned long flags ;
2013-03-08 20:43:54 +04:00
int ret ;
2012-07-10 07:08:14 +04:00
spin_lock_irqsave ( & pfc - > lock , flags ) ;
2013-03-10 20:25:29 +04:00
if ( cfg - > type ! = PINMUX_TYPE_NONE ) {
2013-03-10 21:00:02 +04:00
dev_err ( pfc - > dev ,
" Pin %u is busy, can't configure it as GPIO. \n " ,
offset ) ;
2013-03-10 20:25:29 +04:00
ret = - EBUSY ;
goto done ;
2012-07-11 12:17:10 +04:00
}
2012-07-10 07:08:14 +04:00
2013-03-10 20:30:25 +04: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 20:25:29 +04:00
cfg - > type = PINMUX_TYPE_GPIO ;
2012-07-10 07:08:14 +04:00
ret = 0 ;
2013-03-10 20:25:29 +04:00
done :
2012-07-10 07:08:14 +04: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 20:25:29 +04: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 07:08:14 +04: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 19:55:19 +04: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 20:25:29 +04:00
struct sh_pfc_pin_config * cfg = & pmx - > configs [ idx ] ;
2013-03-10 19:55:19 +04:00
unsigned long flags ;
2013-03-13 21:18:30 +04:00
unsigned int dir ;
2013-03-10 19:55:19 +04:00
int ret ;
2012-07-10 07:08:14 +04:00
2013-03-13 21:18:30 +04: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 19:55:19 +04:00
spin_lock_irqsave ( & pfc - > lock , flags ) ;
2013-03-10 20:25:29 +04:00
ret = sh_pfc_config_mux ( pfc , pin - > enum_id , new_type ) ;
2013-03-10 19:55:19 +04:00
if ( ret < 0 )
goto done ;
cfg - > type = new_type ;
done :
spin_unlock_irqrestore ( & pfc - > lock , flags ) ;
return ret ;
2012-07-10 07:08:14 +04:00
}
2013-02-15 19:04:47 +04:00
static const struct pinmux_ops sh_pfc_pinmux_ops = {
2012-07-11 12:17:10 +04:00
. get_functions_count = sh_pfc_get_functions_count ,
. get_function_name = sh_pfc_get_function_name ,
2012-07-10 07:08:14 +04:00
. get_function_groups = sh_pfc_get_function_groups ,
2014-09-03 15:02:56 +04:00
. set_mux = sh_pfc_func_set_mux ,
2012-07-10 07:08:14 +04: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 19:44:02 +04: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 ;
2015-06-30 19:53:59 +03:00
case PIN_CONFIG_POWER_SOURCE :
return pin - > configs & SH_PFC_PIN_CFG_IO_VOLTAGE ;
2013-03-10 19:44:02 +04:00
default :
return false ;
}
}
2013-02-15 01:35:09 +04:00
static int sh_pfc_pinconf_get ( struct pinctrl_dev * pctldev , unsigned _pin ,
2012-07-10 07:08:14 +04:00
unsigned long * config )
{
2012-07-20 11:39:09 +04:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
struct sh_pfc * pfc = pmx - > pfc ;
2013-03-10 19:44:02 +04:00
enum pin_config_param param = pinconf_to_config_param ( * config ) ;
unsigned long flags ;
if ( ! sh_pfc_pinconf_validate ( pfc , _pin , param ) )
return - ENOTSUPP ;
switch ( param ) {
case PIN_CONFIG_BIAS_DISABLE :
case PIN_CONFIG_BIAS_PULL_UP :
2015-06-30 19:53:59 +03:00
case PIN_CONFIG_BIAS_PULL_DOWN : {
unsigned int bias ;
2013-03-10 19:44:02 +04:00
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 ;
2015-06-30 19:53:59 +03:00
}
case PIN_CONFIG_POWER_SOURCE : {
int ret ;
if ( ! pfc - > info - > ops | | ! pfc - > info - > ops - > get_io_voltage )
return - ENOTSUPP ;
spin_lock_irqsave ( & pfc - > lock , flags ) ;
ret = pfc - > info - > ops - > get_io_voltage ( pfc , _pin ) ;
spin_unlock_irqrestore ( & pfc - > lock , flags ) ;
if ( ret < 0 )
return ret ;
* config = ret ;
break ;
}
2012-07-11 12:17:10 +04:00
2013-03-10 19:44:02 +04:00
default :
return - ENOTSUPP ;
}
2012-07-11 12:17:10 +04:00
2012-07-20 11:39:09 +04:00
return 0 ;
2012-07-10 07:08:14 +04:00
}
2013-03-10 19:44:02 +04:00
static int sh_pfc_pinconf_set ( struct pinctrl_dev * pctldev , unsigned _pin ,
2013-08-27 22:32:12 +04:00
unsigned long * configs , unsigned num_configs )
2012-07-10 07:08:14 +04:00
{
2012-07-20 11:39:09 +04:00
struct sh_pfc_pinctrl * pmx = pinctrl_dev_get_drvdata ( pctldev ) ;
2013-03-10 19:44:02 +04:00
struct sh_pfc * pfc = pmx - > pfc ;
2013-08-27 22:32:12 +04:00
enum pin_config_param param ;
2013-03-10 19:44:02 +04:00
unsigned long flags ;
2013-08-27 22:32:12 +04:00
unsigned int i ;
2012-07-20 11:39:09 +04:00
2013-08-27 22:32:12 +04:00
for ( i = 0 ; i < num_configs ; i + + ) {
param = pinconf_to_config_param ( configs [ i ] ) ;
2012-07-20 11:39:09 +04:00
2013-08-27 22:32:12 +04:00
if ( ! sh_pfc_pinconf_validate ( pfc , _pin , param ) )
2013-03-10 19:44:02 +04:00
return - ENOTSUPP ;
2013-08-27 22:32:12 +04: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 ;
2013-03-10 19:44:02 +04:00
2013-08-27 22:32:12 +04:00
spin_lock_irqsave ( & pfc - > lock , flags ) ;
pfc - > info - > ops - > set_bias ( pfc , _pin , param ) ;
spin_unlock_irqrestore ( & pfc - > lock , flags ) ;
2013-03-10 19:44:02 +04:00
2013-08-27 22:32:12 +04:00
break ;
2015-06-30 19:53:59 +03:00
case PIN_CONFIG_POWER_SOURCE : {
unsigned int arg =
pinconf_to_config_argument ( configs [ i ] ) ;
int ret ;
if ( ! pfc - > info - > ops | | ! pfc - > info - > ops - > set_io_voltage )
return - ENOTSUPP ;
spin_lock_irqsave ( & pfc - > lock , flags ) ;
ret = pfc - > info - > ops - > set_io_voltage ( pfc , _pin , arg ) ;
spin_unlock_irqrestore ( & pfc - > lock , flags ) ;
if ( ret )
return ret ;
break ;
}
2013-08-27 22:32:12 +04:00
default :
return - ENOTSUPP ;
}
} /* for each config */
2013-03-10 19:44:02 +04:00
return 0 ;
2012-07-20 11:39:09 +04:00
}
2013-03-10 19:44:02 +04:00
static int sh_pfc_pinconf_group_set ( struct pinctrl_dev * pctldev , unsigned group ,
2013-08-27 22:32:12 +04:00
unsigned long * configs ,
unsigned num_configs )
2012-07-20 11:39:09 +04:00
{
2013-03-10 19:44:02 +04: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 )
2013-08-27 22:32:12 +04:00
sh_pfc_pinconf_set ( pctldev , pins [ i ] , configs , num_configs ) ;
2013-03-10 19:44:02 +04:00
return 0 ;
2012-07-10 07:08:14 +04:00
}
2013-02-15 19:04:47 +04:00
static const struct pinconf_ops sh_pfc_pinconf_ops = {
2013-03-10 19:44:02 +04: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 07:08:14 +04:00
} ;
2013-02-15 04:33:38 +04:00
/* PFC ranges -> pinctrl pin descs */
static int sh_pfc_map_pins ( struct sh_pfc * pfc , struct sh_pfc_pinctrl * pmx )
2012-07-10 07:08:14 +04:00
{
2013-02-15 04:33:38 +04:00
unsigned int i ;
2013-07-15 20:38:30 +04:00
/* Allocate and initialize the pins and configs arrays. */
2013-01-03 17:33:13 +04:00
pmx - > pins = devm_kzalloc ( pfc - > dev ,
sizeof ( * pmx - > pins ) * pfc - > info - > nr_pins ,
2012-12-16 02:50:48 +04:00
GFP_KERNEL ) ;
2013-01-03 17:33:13 +04:00
if ( unlikely ( ! pmx - > pins ) )
2012-07-10 07:08:14 +04:00
return - ENOMEM ;
2013-03-08 20:43:54 +04:00
pmx - > configs = devm_kzalloc ( pfc - > dev ,
sizeof ( * pmx - > configs ) * pfc - > info - > nr_pins ,
GFP_KERNEL ) ;
if ( unlikely ( ! pmx - > configs ) )
return - ENOMEM ;
2013-07-15 20:38:30 +04:00
for ( i = 0 ; i < pfc - > info - > nr_pins ; + + i ) {
const struct sh_pfc_pin * info = & pfc - > info - > pins [ i ] ;
struct sh_pfc_pin_config * cfg = & pmx - > configs [ i ] ;
struct pinctrl_pin_desc * pin = & pmx - > pins [ i ] ;
2013-02-15 04:33:38 +04:00
2013-07-15 20:38:30 +04:00
/* If the pin number is equal to -1 all pins are considered */
pin - > number = info - > pin ! = ( u16 ) - 1 ? info - > pin : i ;
pin - > name = info - > name ;
cfg - > type = PINMUX_TYPE_NONE ;
2012-07-10 07:08:14 +04:00
}
2013-07-15 20:38:30 +04:00
return 0 ;
2012-07-10 07:08:14 +04:00
}
2012-12-16 02:50:47 +04:00
int sh_pfc_register_pinctrl ( struct sh_pfc * pfc )
2012-07-10 07:08:14 +04:00
{
2012-12-16 02:50:47 +04:00
struct sh_pfc_pinctrl * pmx ;
2013-07-15 20:38:30 +04:00
int ret ;
2012-07-10 07:08:14 +04:00
2012-12-16 02:50:48 +04:00
pmx = devm_kzalloc ( pfc - > dev , sizeof ( * pmx ) , GFP_KERNEL ) ;
2012-12-16 02:50:47 +04:00
if ( unlikely ( ! pmx ) )
return - ENOMEM ;
pmx - > pfc = pfc ;
pfc - > pinctrl = pmx ;
2012-07-10 07:08:14 +04:00
2013-07-15 20:38:30 +04:00
ret = sh_pfc_map_pins ( pfc , pmx ) ;
if ( ret < 0 )
return ret ;
2012-07-10 07:08:14 +04:00
2013-02-16 19:38:30 +04: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 17:33:13 +04:00
pmx - > pctl_desc . pins = pmx - > pins ;
2013-02-15 04:33:38 +04:00
pmx - > pctl_desc . npins = pfc - > info - > nr_pins ;
2013-02-16 19:38:30 +04:00
pmx - > pctl = pinctrl_register ( & pmx - > pctl_desc , pfc - > dev , pmx ) ;
2015-06-09 07:01:16 +03:00
if ( IS_ERR ( pmx - > pctl ) )
return PTR_ERR ( pmx - > pctl ) ;
2012-07-10 07:08:14 +04:00
return 0 ;
}
2012-12-16 02:50:47 +04:00
int sh_pfc_unregister_pinctrl ( struct sh_pfc * pfc )
2012-07-10 07:08:14 +04:00
{
2012-12-16 02:50:47 +04:00
struct sh_pfc_pinctrl * pmx = pfc - > pinctrl ;
2012-07-10 07:08:14 +04:00
pinctrl_unregister ( pmx - > pctl ) ;
2012-12-16 02:50:47 +04:00
pfc - > pinctrl = NULL ;
2012-07-10 07:08:14 +04:00
return 0 ;
}