2019-05-28 19:57:21 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2011-11-24 21:27:15 +04:00
/*
* Core driver for the generic pin config portions of the pin control subsystem
*
* Copyright ( C ) 2011 ST - Ericsson SA
* Written on behalf of Linaro for ST - Ericsson
*
* Author : Linus Walleij < linus . walleij @ linaro . org >
*/
# define pr_fmt(fmt) "generic pinconfig core: " fmt
# include <linux/kernel.h>
2013-02-17 15:42:53 +04:00
# include <linux/module.h>
2011-11-24 21:27:15 +04:00
# include <linux/init.h>
# include <linux/device.h>
# include <linux/slab.h>
# include <linux/debugfs.h>
# include <linux/seq_file.h>
# include <linux/pinctrl/pinctrl.h>
# include <linux/pinctrl/pinconf.h>
# include <linux/pinctrl/pinconf-generic.h>
2013-06-10 23:40:29 +04:00
# include <linux/of.h>
2011-11-24 21:27:15 +04:00
# include "core.h"
# include "pinconf.h"
2013-08-06 17:12:34 +04:00
# include "pinctrl-utils.h"
2011-11-24 21:27:15 +04:00
# ifdef CONFIG_DEBUG_FS
2014-11-03 22:05:25 +03:00
static const struct pin_config_item conf_items [ ] = {
2015-09-30 15:07:17 +03:00
PCONFDUMP ( PIN_CONFIG_BIAS_BUS_HOLD , " input bias bus hold " , NULL , false ) ,
2014-10-16 21:11:29 +04:00
PCONFDUMP ( PIN_CONFIG_BIAS_DISABLE , " input bias disabled " , NULL , false ) ,
PCONFDUMP ( PIN_CONFIG_BIAS_HIGH_IMPEDANCE , " input bias high impedance " , NULL , false ) ,
2022-03-08 13:09:46 +03:00
PCONFDUMP ( PIN_CONFIG_BIAS_PULL_DOWN , " input bias pull down " , " ohms " , true ) ,
2013-06-06 18:44:25 +04:00
PCONFDUMP ( PIN_CONFIG_BIAS_PULL_PIN_DEFAULT ,
2022-03-08 13:09:46 +03:00
" input bias pull to pin specific state " , " ohms " , true ) ,
PCONFDUMP ( PIN_CONFIG_BIAS_PULL_UP , " input bias pull up " , " ohms " , true ) ,
2014-10-16 21:11:29 +04:00
PCONFDUMP ( PIN_CONFIG_DRIVE_OPEN_DRAIN , " output drive open drain " , NULL , false ) ,
PCONFDUMP ( PIN_CONFIG_DRIVE_OPEN_SOURCE , " output drive open source " , NULL , false ) ,
2015-09-30 15:07:17 +03:00
PCONFDUMP ( PIN_CONFIG_DRIVE_PUSH_PULL , " output drive push pull " , NULL , false ) ,
2014-10-16 21:11:29 +04:00
PCONFDUMP ( PIN_CONFIG_DRIVE_STRENGTH , " output drive strength " , " mA " , true ) ,
2019-05-14 11:26:48 +03:00
PCONFDUMP ( PIN_CONFIG_DRIVE_STRENGTH_UA , " output drive strength " , " uA " , true ) ,
2015-09-30 15:07:17 +03:00
PCONFDUMP ( PIN_CONFIG_INPUT_DEBOUNCE , " input debounce " , " usec " , true ) ,
2014-10-16 21:11:29 +04:00
PCONFDUMP ( PIN_CONFIG_INPUT_ENABLE , " input enabled " , NULL , false ) ,
PCONFDUMP ( PIN_CONFIG_INPUT_SCHMITT , " input schmitt trigger " , NULL , false ) ,
2015-09-30 15:07:17 +03:00
PCONFDUMP ( PIN_CONFIG_INPUT_SCHMITT_ENABLE , " input schmitt enabled " , NULL , false ) ,
2021-04-12 17:07:40 +03:00
PCONFDUMP ( PIN_CONFIG_MODE_LOW_POWER , " pin low power " , " mode " , true ) ,
2017-06-22 13:00:58 +03:00
PCONFDUMP ( PIN_CONFIG_OUTPUT_ENABLE , " output enabled " , NULL , false ) ,
2014-10-16 21:11:29 +04:00
PCONFDUMP ( PIN_CONFIG_OUTPUT , " pin output " , " level " , true ) ,
2021-10-27 16:45:07 +03:00
PCONFDUMP ( PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS , " output impedance " , " ohms " , true ) ,
2015-09-30 15:07:17 +03:00
PCONFDUMP ( PIN_CONFIG_POWER_SOURCE , " pin power source " , " selector " , true ) ,
2017-08-17 09:50:36 +03:00
PCONFDUMP ( PIN_CONFIG_SLEEP_HARDWARE_STATE , " sleep hardware state " , NULL , false ) ,
2015-09-30 15:07:17 +03:00
PCONFDUMP ( PIN_CONFIG_SLEW_RATE , " slew rate " , NULL , true ) ,
2017-10-28 16:37:17 +03:00
PCONFDUMP ( PIN_CONFIG_SKEW_DELAY , " skew delay " , NULL , true ) ,
2011-11-24 21:27:15 +04:00
} ;
2015-01-09 18:43:46 +03:00
static void pinconf_generic_dump_one ( struct pinctrl_dev * pctldev ,
struct seq_file * s , const char * gname ,
unsigned pin ,
const struct pin_config_item * items ,
2016-05-25 09:37:27 +03:00
int nitems , int * print_sep )
2011-11-24 21:27:15 +04:00
{
int i ;
2015-01-09 18:43:46 +03:00
for ( i = 0 ; i < nitems ; i + + ) {
2011-11-24 21:27:15 +04:00
unsigned long config ;
int ret ;
/* We want to check out this parameter */
2015-01-09 18:43:46 +03:00
config = pinconf_to_config_packed ( items [ i ] . param , 0 ) ;
if ( gname )
ret = pin_config_group_get ( dev_name ( pctldev - > dev ) ,
gname , & config ) ;
else
ret = pin_config_get_for_pin ( pctldev , pin , & config ) ;
2011-11-24 21:27:15 +04:00
/* These are legal errors */
if ( ret = = - EINVAL | | ret = = - ENOTSUPP )
continue ;
if ( ret ) {
seq_printf ( s , " ERROR READING CONFIG SETTING %d " , i ) ;
continue ;
}
2016-05-25 09:37:27 +03:00
/* comma between multiple configs */
if ( * print_sep )
seq_puts ( s , " , " ) ;
* print_sep = 1 ;
2015-01-09 18:43:46 +03:00
seq_puts ( s , items [ i ] . display ) ;
2011-11-24 21:27:15 +04:00
/* Print unit if available */
2015-01-09 18:43:46 +03:00
if ( items [ i ] . has_arg ) {
2014-10-16 21:11:29 +04:00
seq_printf ( s , " (%u " ,
pinconf_to_config_argument ( config ) ) ;
2015-01-09 18:43:46 +03:00
if ( items [ i ] . format )
seq_printf ( s , " %s) " , items [ i ] . format ) ;
2014-10-16 21:11:29 +04:00
else
seq_puts ( s , " ) " ) ;
}
2011-11-24 21:27:15 +04:00
}
}
2015-01-09 18:43:46 +03:00
/**
* pinconf_generic_dump_pins - Print information about pin or group of pins
* @ pctldev : Pincontrol device
* @ s : File to print to
* @ gname : Group name specifying pins
* @ pin : Pin number specyfying pin
*
* Print the pinconf configuration for the requested pin ( s ) to @ s . Pins can be
* specified either by pin using @ pin or by group using @ gname . Only one needs
* to be specified the other can be NULL / 0.
*/
void pinconf_generic_dump_pins ( struct pinctrl_dev * pctldev , struct seq_file * s ,
const char * gname , unsigned pin )
2011-11-24 21:27:15 +04:00
{
const struct pinconf_ops * ops = pctldev - > desc - > confops ;
2016-05-25 09:37:27 +03:00
int print_sep = 0 ;
2011-11-24 21:27:15 +04:00
if ( ! ops - > is_generic )
return ;
2015-01-09 18:43:46 +03:00
/* generic parameters */
pinconf_generic_dump_one ( pctldev , s , gname , pin , conf_items ,
2016-05-25 09:37:27 +03:00
ARRAY_SIZE ( conf_items ) , & print_sep ) ;
2015-01-09 18:43:46 +03:00
/* driver-specific parameters */
2015-01-12 02:45:55 +03:00
if ( pctldev - > desc - > num_custom_params & &
pctldev - > desc - > custom_conf_items )
2015-01-09 18:43:46 +03:00
pinconf_generic_dump_one ( pctldev , s , gname , pin ,
2015-01-12 02:45:55 +03:00
pctldev - > desc - > custom_conf_items ,
2016-05-25 09:37:27 +03:00
pctldev - > desc - > num_custom_params ,
& print_sep ) ;
2011-11-24 21:27:15 +04:00
}
2013-02-17 15:42:53 +04:00
void pinconf_generic_dump_config ( struct pinctrl_dev * pctldev ,
struct seq_file * s , unsigned long config )
{
int i ;
2013-03-15 08:53:16 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( conf_items ) ; i + + ) {
2013-02-17 15:42:53 +04:00
if ( pinconf_to_config_param ( config ) ! = conf_items [ i ] . param )
continue ;
seq_printf ( s , " %s: 0x%x " , conf_items [ i ] . display ,
pinconf_to_config_argument ( config ) ) ;
}
2015-01-09 18:43:46 +03:00
2015-01-12 02:45:55 +03:00
if ( ! pctldev - > desc - > num_custom_params | |
! pctldev - > desc - > custom_conf_items )
2015-01-09 18:43:46 +03:00
return ;
2015-01-12 02:45:55 +03:00
for ( i = 0 ; i < pctldev - > desc - > num_custom_params ; i + + ) {
if ( pinconf_to_config_param ( config ) ! =
pctldev - > desc - > custom_conf_items [ i ] . param )
2015-01-09 18:43:46 +03:00
continue ;
2015-01-12 02:45:55 +03:00
seq_printf ( s , " %s: 0x%x " ,
pctldev - > desc - > custom_conf_items [ i ] . display ,
pinconf_to_config_argument ( config ) ) ;
2015-01-09 18:43:46 +03:00
}
2013-02-17 15:42:53 +04:00
}
EXPORT_SYMBOL_GPL ( pinconf_generic_dump_config ) ;
2011-11-24 21:27:15 +04:00
# endif
2013-06-10 23:40:29 +04:00
# ifdef CONFIG_OF
2015-01-12 02:45:55 +03:00
static const struct pinconf_generic_params dt_params [ ] = {
2015-09-30 15:07:17 +03:00
{ " bias-bus-hold " , PIN_CONFIG_BIAS_BUS_HOLD , 0 } ,
2013-06-10 23:40:29 +04:00
{ " bias-disable " , PIN_CONFIG_BIAS_DISABLE , 0 } ,
{ " bias-high-impedance " , PIN_CONFIG_BIAS_HIGH_IMPEDANCE , 0 } ,
2013-06-14 19:42:49 +04:00
{ " bias-pull-up " , PIN_CONFIG_BIAS_PULL_UP , 1 } ,
{ " bias-pull-pin-default " , PIN_CONFIG_BIAS_PULL_PIN_DEFAULT , 1 } ,
2015-09-30 15:07:17 +03:00
{ " bias-pull-down " , PIN_CONFIG_BIAS_PULL_DOWN , 1 } ,
2013-06-10 23:40:29 +04:00
{ " drive-open-drain " , PIN_CONFIG_DRIVE_OPEN_DRAIN , 0 } ,
{ " drive-open-source " , PIN_CONFIG_DRIVE_OPEN_SOURCE , 0 } ,
2015-09-30 15:07:17 +03:00
{ " drive-push-pull " , PIN_CONFIG_DRIVE_PUSH_PULL , 0 } ,
2013-06-10 23:40:29 +04:00
{ " drive-strength " , PIN_CONFIG_DRIVE_STRENGTH , 0 } ,
2019-05-14 11:26:48 +03:00
{ " drive-strength-microamp " , PIN_CONFIG_DRIVE_STRENGTH_UA , 0 } ,
2015-09-30 15:07:17 +03:00
{ " input-debounce " , PIN_CONFIG_INPUT_DEBOUNCE , 0 } ,
2013-12-11 22:37:17 +04:00
{ " input-disable " , PIN_CONFIG_INPUT_ENABLE , 0 } ,
2015-09-30 15:07:17 +03:00
{ " input-enable " , PIN_CONFIG_INPUT_ENABLE , 1 } ,
2015-09-30 15:07:18 +03:00
{ " input-schmitt " , PIN_CONFIG_INPUT_SCHMITT , 0 } ,
2013-06-10 23:40:29 +04:00
{ " input-schmitt-disable " , PIN_CONFIG_INPUT_SCHMITT_ENABLE , 0 } ,
2015-09-30 15:07:17 +03:00
{ " input-schmitt-enable " , PIN_CONFIG_INPUT_SCHMITT_ENABLE , 1 } ,
2021-04-12 17:07:40 +03:00
{ " low-power-disable " , PIN_CONFIG_MODE_LOW_POWER , 0 } ,
{ " low-power-enable " , PIN_CONFIG_MODE_LOW_POWER , 1 } ,
2017-06-22 13:00:58 +03:00
{ " output-disable " , PIN_CONFIG_OUTPUT_ENABLE , 0 } ,
{ " output-enable " , PIN_CONFIG_OUTPUT_ENABLE , 1 } ,
2013-06-10 23:40:29 +04:00
{ " output-high " , PIN_CONFIG_OUTPUT , 1 , } ,
2021-10-27 16:45:07 +03:00
{ " output-impedance-ohms " , PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS , 0 } ,
2015-09-30 15:07:17 +03:00
{ " output-low " , PIN_CONFIG_OUTPUT , 0 , } ,
{ " power-source " , PIN_CONFIG_POWER_SOURCE , 0 } ,
2017-08-17 09:50:36 +03:00
{ " sleep-hardware-state " , PIN_CONFIG_SLEEP_HARDWARE_STATE , 0 } ,
2015-09-30 15:07:17 +03:00
{ " slew-rate " , PIN_CONFIG_SLEW_RATE , 0 } ,
2017-10-28 16:37:17 +03:00
{ " skew-delay " , PIN_CONFIG_SKEW_DELAY , 0 } ,
2013-06-10 23:40:29 +04:00
} ;
2015-01-09 18:43:46 +03:00
/**
2015-01-12 02:45:55 +03:00
* parse_dt_cfg ( ) - Parse DT pinconf parameters
2015-01-09 18:43:46 +03:00
* @ np : DT node
2015-01-12 02:45:55 +03:00
* @ params : Array of describing generic parameters
2015-01-09 18:43:46 +03:00
* @ count : Number of entries in @ params
* @ cfg : Array of parsed config options
* @ ncfg : Number of entries in @ cfg
*
* Parse the config options described in @ params from @ np and puts the result
2017-02-28 17:59:56 +03:00
* in @ cfg . @ cfg does not need to be empty , entries are added beginning at
2015-01-09 18:43:46 +03:00
* @ ncfg . @ ncfg is updated to reflect the number of entries after parsing . @ cfg
* needs to have enough memory allocated to hold all possible entries .
*/
static void parse_dt_cfg ( struct device_node * np ,
2015-01-12 02:45:55 +03:00
const struct pinconf_generic_params * params ,
2015-01-09 18:43:46 +03:00
unsigned int count , unsigned long * cfg ,
unsigned int * ncfg )
{
int i ;
for ( i = 0 ; i < count ; i + + ) {
u32 val ;
int ret ;
2015-01-12 02:45:55 +03:00
const struct pinconf_generic_params * par = & params [ i ] ;
2015-01-09 18:43:46 +03:00
ret = of_property_read_u32 ( np , par - > property , & val ) ;
/* property not found */
if ( ret = = - EINVAL )
continue ;
/* use default value, when no value is specified */
if ( ret )
val = par - > default_value ;
pr_debug ( " found %s with value %u \n " , par - > property , val ) ;
cfg [ * ncfg ] = pinconf_to_config_packed ( par - > param , val ) ;
( * ncfg ) + + ;
}
}
2013-06-10 23:40:29 +04:00
/**
* pinconf_generic_parse_dt_config ( )
* parse the config properties into generic pinconfig values .
* @ np : node containing the pinconfig properties
2020-07-13 17:49:19 +03:00
* @ pctldev : pincontrol device
2013-06-10 23:40:29 +04:00
* @ configs : array with nconfigs entries containing the generic pinconf values
2015-11-25 15:13:23 +03:00
* must be freed when no longer necessary .
2020-07-13 17:49:19 +03:00
* @ nconfigs : number of configurations
2013-06-10 23:40:29 +04:00
*/
int pinconf_generic_parse_dt_config ( struct device_node * np ,
2015-01-09 18:43:46 +03:00
struct pinctrl_dev * pctldev ,
2013-06-10 23:40:29 +04:00
unsigned long * * configs ,
unsigned int * nconfigs )
{
2013-06-14 19:43:55 +04:00
unsigned long * cfg ;
2015-01-09 18:43:46 +03:00
unsigned int max_cfg , ncfg = 0 ;
2013-06-10 23:40:29 +04:00
int ret ;
if ( ! np )
return - EINVAL ;
2013-06-14 19:43:55 +04:00
/* allocate a temporary array big enough to hold one of each option */
2015-01-09 18:43:46 +03:00
max_cfg = ARRAY_SIZE ( dt_params ) ;
if ( pctldev )
2015-01-12 02:45:55 +03:00
max_cfg + = pctldev - > desc - > num_custom_params ;
2015-01-09 18:43:46 +03:00
cfg = kcalloc ( max_cfg , sizeof ( * cfg ) , GFP_KERNEL ) ;
2013-06-14 19:43:55 +04:00
if ( ! cfg )
return - ENOMEM ;
2015-01-09 18:43:46 +03:00
parse_dt_cfg ( np , dt_params , ARRAY_SIZE ( dt_params ) , cfg , & ncfg ) ;
2015-01-12 02:45:55 +03:00
if ( pctldev & & pctldev - > desc - > num_custom_params & &
pctldev - > desc - > custom_params )
parse_dt_cfg ( np , pctldev - > desc - > custom_params ,
pctldev - > desc - > num_custom_params , cfg , & ncfg ) ;
2013-06-10 23:40:29 +04:00
2013-06-14 19:43:55 +04:00
ret = 0 ;
2013-06-14 19:43:21 +04:00
/* no configs found at all */
if ( ncfg = = 0 ) {
* configs = NULL ;
* nconfigs = 0 ;
2013-06-14 19:43:55 +04:00
goto out ;
2013-06-14 19:43:21 +04:00
}
2013-06-10 23:40:29 +04:00
/*
* Now limit the number of configs to the real number of
* found properties .
*/
2014-05-26 19:21:27 +04:00
* configs = kmemdup ( cfg , ncfg * sizeof ( unsigned long ) , GFP_KERNEL ) ;
2013-06-14 19:43:55 +04:00
if ( ! * configs ) {
ret = - ENOMEM ;
goto out ;
}
2013-06-10 23:40:29 +04:00
* nconfigs = ncfg ;
2013-06-14 19:43:55 +04:00
out :
kfree ( cfg ) ;
return ret ;
2013-06-10 23:40:29 +04:00
}
2020-02-27 07:13:46 +03:00
EXPORT_SYMBOL_GPL ( pinconf_generic_parse_dt_config ) ;
2013-08-06 17:12:34 +04:00
int pinconf_generic_dt_subnode_to_map ( struct pinctrl_dev * pctldev ,
struct device_node * np , struct pinctrl_map * * map ,
2013-08-21 15:23:37 +04:00
unsigned * reserved_maps , unsigned * num_maps ,
enum pinctrl_map_type type )
2013-08-06 17:12:34 +04:00
{
int ret ;
const char * function ;
struct device * dev = pctldev - > dev ;
unsigned long * configs = NULL ;
unsigned num_configs = 0 ;
2015-03-19 23:17:41 +03:00
unsigned reserve , strings_count ;
2013-08-06 17:12:34 +04:00
struct property * prop ;
const char * group ;
2015-01-09 18:43:45 +03:00
const char * subnode_target_type = " pins " ;
2013-08-06 17:12:34 +04:00
2015-03-19 23:17:41 +03:00
ret = of_property_count_strings ( np , " pins " ) ;
if ( ret < 0 ) {
ret = of_property_count_strings ( np , " groups " ) ;
if ( ret < 0 )
/* skip this node; may contain config child nodes */
return 0 ;
if ( type = = PIN_MAP_TYPE_INVALID )
type = PIN_MAP_TYPE_CONFIGS_GROUP ;
subnode_target_type = " groups " ;
} else {
if ( type = = PIN_MAP_TYPE_INVALID )
type = PIN_MAP_TYPE_CONFIGS_PIN ;
}
strings_count = ret ;
2013-08-06 17:12:34 +04:00
ret = of_property_read_string ( np , " function " , & function ) ;
if ( ret < 0 ) {
/* EINVAL=missing, which is fine since it's optional */
if ( ret ! = - EINVAL )
2017-07-19 00:43:23 +03:00
dev_err ( dev , " %pOF: could not parse property function \n " ,
np ) ;
2013-08-06 17:12:34 +04:00
function = NULL ;
}
2015-01-09 18:43:46 +03:00
ret = pinconf_generic_parse_dt_config ( np , pctldev , & configs ,
& num_configs ) ;
2013-08-06 17:12:34 +04:00
if ( ret < 0 ) {
2017-07-19 00:43:23 +03:00
dev_err ( dev , " %pOF: could not parse node property \n " , np ) ;
2013-08-06 17:12:34 +04:00
return ret ;
}
reserve = 0 ;
if ( function ! = NULL )
reserve + + ;
if ( num_configs )
reserve + + ;
2015-01-09 18:43:45 +03:00
2015-03-19 23:17:41 +03:00
reserve * = strings_count ;
2013-08-06 17:12:34 +04:00
ret = pinctrl_utils_reserve_map ( pctldev , map , reserved_maps ,
num_maps , reserve ) ;
if ( ret < 0 )
goto exit ;
2015-01-09 18:43:45 +03:00
of_property_for_each_string ( np , subnode_target_type , prop , group ) {
2013-08-06 17:12:34 +04:00
if ( function ) {
ret = pinctrl_utils_add_map_mux ( pctldev , map ,
reserved_maps , num_maps , group ,
function ) ;
if ( ret < 0 )
goto exit ;
}
if ( num_configs ) {
ret = pinctrl_utils_add_map_configs ( pctldev , map ,
reserved_maps , num_maps , group , configs ,
2013-08-21 15:23:37 +04:00
num_configs , type ) ;
2013-08-06 17:12:34 +04:00
if ( ret < 0 )
goto exit ;
}
}
ret = 0 ;
exit :
kfree ( configs ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( pinconf_generic_dt_subnode_to_map ) ;
int pinconf_generic_dt_node_to_map ( struct pinctrl_dev * pctldev ,
struct device_node * np_config , struct pinctrl_map * * map ,
2013-08-21 15:23:37 +04:00
unsigned * num_maps , enum pinctrl_map_type type )
2013-08-06 17:12:34 +04:00
{
unsigned reserved_maps ;
struct device_node * np ;
int ret ;
reserved_maps = 0 ;
* map = NULL ;
* num_maps = 0 ;
2015-03-19 23:17:41 +03:00
ret = pinconf_generic_dt_subnode_to_map ( pctldev , np_config , map ,
& reserved_maps , num_maps , type ) ;
if ( ret < 0 )
goto exit ;
2016-10-28 14:24:21 +03:00
for_each_available_child_of_node ( np_config , np ) {
2013-08-06 17:12:34 +04:00
ret = pinconf_generic_dt_subnode_to_map ( pctldev , np , map ,
2013-08-21 15:23:37 +04:00
& reserved_maps , num_maps , type ) ;
2015-03-19 23:17:41 +03:00
if ( ret < 0 )
goto exit ;
2013-08-06 17:12:34 +04:00
}
return 0 ;
2015-03-19 23:17:41 +03:00
exit :
2016-03-31 14:44:42 +03:00
pinctrl_utils_free_map ( pctldev , * map , * num_maps ) ;
2015-03-19 23:17:41 +03:00
return ret ;
2013-08-06 17:12:34 +04:00
}
EXPORT_SYMBOL_GPL ( pinconf_generic_dt_node_to_map ) ;
2016-06-17 15:03:40 +03:00
void pinconf_generic_dt_free_map ( struct pinctrl_dev * pctldev ,
struct pinctrl_map * map ,
unsigned num_maps )
{
pinctrl_utils_free_map ( pctldev , map , num_maps ) ;
}
EXPORT_SYMBOL_GPL ( pinconf_generic_dt_free_map ) ;
2013-06-10 23:40:29 +04:00
# endif