2019-05-29 17:17:59 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2016-11-28 19:40:25 +03:00
/*
* Pinconf driver for TI DA850 / OMAP - L138 / AM18XX pullup / pulldown groups
*
* Copyright ( C ) 2016 David Lechner
*/
# include <linux/bitops.h>
# include <linux/device.h>
# include <linux/io.h>
# include <linux/ioport.h>
# include <linux/mod_devicetable.h>
# include <linux/module.h>
# include <linux/pinctrl/pinconf.h>
# include <linux/pinctrl/pinconf-generic.h>
# include <linux/pinctrl/pinctrl.h>
# include <linux/platform_device.h>
# define DA850_PUPD_ENA 0x00
# define DA850_PUPD_SEL 0x04
struct da850_pupd_data {
void __iomem * base ;
struct pinctrl_desc desc ;
struct pinctrl_dev * pinctrl ;
} ;
static const char * const da850_pupd_group_names [ ] = {
" cp0 " , " cp1 " , " cp2 " , " cp3 " , " cp4 " , " cp5 " , " cp6 " , " cp7 " ,
" cp8 " , " cp9 " , " cp10 " , " cp11 " , " cp12 " , " cp13 " , " cp14 " , " cp15 " ,
" cp16 " , " cp17 " , " cp18 " , " cp19 " , " cp20 " , " cp21 " , " cp22 " , " cp23 " ,
" cp24 " , " cp25 " , " cp26 " , " cp27 " , " cp28 " , " cp29 " , " cp30 " , " cp31 " ,
} ;
static int da850_pupd_get_groups_count ( struct pinctrl_dev * pctldev )
{
return ARRAY_SIZE ( da850_pupd_group_names ) ;
}
static const char * da850_pupd_get_group_name ( struct pinctrl_dev * pctldev ,
unsigned int selector )
{
return da850_pupd_group_names [ selector ] ;
}
static int da850_pupd_get_group_pins ( struct pinctrl_dev * pctldev ,
unsigned int selector ,
const unsigned int * * pins ,
unsigned int * num_pins )
{
* num_pins = 0 ;
return 0 ;
}
static const struct pinctrl_ops da850_pupd_pctlops = {
. get_groups_count = da850_pupd_get_groups_count ,
. get_group_name = da850_pupd_get_group_name ,
. get_group_pins = da850_pupd_get_group_pins ,
. dt_node_to_map = pinconf_generic_dt_node_to_map_group ,
. dt_free_map = pinconf_generic_dt_free_map ,
} ;
static int da850_pupd_pin_config_group_get ( struct pinctrl_dev * pctldev ,
unsigned int selector ,
unsigned long * config )
{
struct da850_pupd_data * data = pinctrl_dev_get_drvdata ( pctldev ) ;
enum pin_config_param param = pinconf_to_config_param ( * config ) ;
u32 val ;
u16 arg ;
val = readl ( data - > base + DA850_PUPD_ENA ) ;
arg = ! ! ( ~ val & BIT ( selector ) ) ;
switch ( param ) {
case PIN_CONFIG_BIAS_DISABLE :
break ;
case PIN_CONFIG_BIAS_PULL_UP :
case PIN_CONFIG_BIAS_PULL_DOWN :
if ( arg ) {
/* bias is disabled */
arg = 0 ;
break ;
}
val = readl ( data - > base + DA850_PUPD_SEL ) ;
if ( param = = PIN_CONFIG_BIAS_PULL_DOWN )
val = ~ val ;
arg = ! ! ( val & BIT ( selector ) ) ;
break ;
default :
return - EINVAL ;
}
* config = pinconf_to_config_packed ( param , arg ) ;
return 0 ;
}
static int da850_pupd_pin_config_group_set ( struct pinctrl_dev * pctldev ,
unsigned int selector ,
unsigned long * configs ,
unsigned int num_configs )
{
struct da850_pupd_data * data = pinctrl_dev_get_drvdata ( pctldev ) ;
u32 ena , sel ;
enum pin_config_param param ;
int i ;
ena = readl ( data - > base + DA850_PUPD_ENA ) ;
sel = readl ( data - > base + DA850_PUPD_SEL ) ;
for ( i = 0 ; i < num_configs ; i + + ) {
param = pinconf_to_config_param ( configs [ i ] ) ;
switch ( param ) {
case PIN_CONFIG_BIAS_DISABLE :
ena & = ~ BIT ( selector ) ;
break ;
case PIN_CONFIG_BIAS_PULL_UP :
ena | = BIT ( selector ) ;
sel | = BIT ( selector ) ;
break ;
case PIN_CONFIG_BIAS_PULL_DOWN :
ena | = BIT ( selector ) ;
sel & = ~ BIT ( selector ) ;
break ;
default :
return - EINVAL ;
}
}
writel ( sel , data - > base + DA850_PUPD_SEL ) ;
writel ( ena , data - > base + DA850_PUPD_ENA ) ;
return 0 ;
}
static const struct pinconf_ops da850_pupd_confops = {
. is_generic = true ,
. pin_config_group_get = da850_pupd_pin_config_group_get ,
. pin_config_group_set = da850_pupd_pin_config_group_set ,
} ;
static int da850_pupd_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct da850_pupd_data * data ;
data = devm_kzalloc ( dev , sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
2019-11-04 17:26:54 +03:00
data - > base = devm_platform_ioremap_resource ( pdev , 0 ) ;
2016-11-28 19:40:25 +03:00
if ( IS_ERR ( data - > base ) ) {
dev_err ( dev , " Could not map resource \n " ) ;
return PTR_ERR ( data - > base ) ;
}
data - > desc . name = dev_name ( dev ) ;
data - > desc . pctlops = & da850_pupd_pctlops ;
data - > desc . confops = & da850_pupd_confops ;
data - > desc . owner = THIS_MODULE ;
data - > pinctrl = devm_pinctrl_register ( dev , & data - > desc , data ) ;
if ( IS_ERR ( data - > pinctrl ) ) {
dev_err ( dev , " Failed to register pinctrl \n " ) ;
return PTR_ERR ( data - > pinctrl ) ;
}
platform_set_drvdata ( pdev , data ) ;
return 0 ;
}
static int da850_pupd_remove ( struct platform_device * pdev )
{
return 0 ;
}
static const struct of_device_id da850_pupd_of_match [ ] = {
{ . compatible = " ti,da850-pupd " } ,
{ }
} ;
2017-01-06 02:43:41 +03:00
MODULE_DEVICE_TABLE ( of , da850_pupd_of_match ) ;
2016-11-28 19:40:25 +03:00
static struct platform_driver da850_pupd_driver = {
. driver = {
. name = " ti-da850-pupd " ,
. of_match_table = da850_pupd_of_match ,
} ,
. probe = da850_pupd_probe ,
. remove = da850_pupd_remove ,
} ;
module_platform_driver ( da850_pupd_driver ) ;
MODULE_AUTHOR ( " David Lechner <david@lechnology.com> " ) ;
MODULE_DESCRIPTION ( " TI DA850/OMAP-L138/AM18XX pullup/pulldown configuration " ) ;
MODULE_LICENSE ( " GPL " ) ;