2014-10-22 12:58:46 +03:00
/*
* Copyright ( c ) 2012 - 2014 , The Linux Foundation . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation .
*
* This program is distributed in the hope that 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 .
*/
2018-09-13 13:58:21 +02:00
# include <linux/gpio/driver.h>
2014-10-22 12:58:46 +03:00
# include <linux/module.h>
# include <linux/of.h>
2015-11-18 11:33:17 -08:00
# include <linux/of_irq.h>
2014-10-22 12:58:46 +03:00
# include <linux/pinctrl/pinconf-generic.h>
# include <linux/pinctrl/pinconf.h>
# include <linux/pinctrl/pinmux.h>
# include <linux/platform_device.h>
# include <linux/regmap.h>
# include <linux/slab.h>
# include <linux/types.h>
# include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
# include "../core.h"
# include "../pinctrl-utils.h"
# define PMIC_GPIO_ADDRESS_RANGE 0x100
/* type and subtype registers base address offsets */
# define PMIC_GPIO_REG_TYPE 0x4
# define PMIC_GPIO_REG_SUBTYPE 0x5
/* GPIO peripheral type and subtype out_values */
# define PMIC_GPIO_TYPE 0x10
# define PMIC_GPIO_SUBTYPE_GPIO_4CH 0x1
# define PMIC_GPIO_SUBTYPE_GPIOC_4CH 0x5
# define PMIC_GPIO_SUBTYPE_GPIO_8CH 0x9
# define PMIC_GPIO_SUBTYPE_GPIOC_8CH 0xd
2017-08-15 08:38:37 +08:00
# define PMIC_GPIO_SUBTYPE_GPIO_LV 0x10
# define PMIC_GPIO_SUBTYPE_GPIO_MV 0x11
2014-10-22 12:58:46 +03:00
# define PMIC_MPP_REG_RT_STS 0x10
# define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1
/* control register base address offsets */
# define PMIC_GPIO_REG_MODE_CTL 0x40
# define PMIC_GPIO_REG_DIG_VIN_CTL 0x41
# define PMIC_GPIO_REG_DIG_PULL_CTL 0x42
2017-08-15 08:38:37 +08:00
# define PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL 0x44
2017-08-15 08:38:38 +08:00
# define PMIC_GPIO_REG_DIG_IN_CTL 0x43
2014-10-22 12:58:46 +03:00
# define PMIC_GPIO_REG_DIG_OUT_CTL 0x45
# define PMIC_GPIO_REG_EN_CTL 0x46
2017-08-15 08:38:37 +08:00
# define PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL 0x4A
2014-10-22 12:58:46 +03:00
/* PMIC_GPIO_REG_MODE_CTL */
# define PMIC_GPIO_REG_MODE_VALUE_SHIFT 0x1
# define PMIC_GPIO_REG_MODE_FUNCTION_SHIFT 1
# define PMIC_GPIO_REG_MODE_FUNCTION_MASK 0x7
# define PMIC_GPIO_REG_MODE_DIR_SHIFT 4
# define PMIC_GPIO_REG_MODE_DIR_MASK 0x7
2017-08-15 08:38:37 +08:00
# define PMIC_GPIO_MODE_DIGITAL_INPUT 0
# define PMIC_GPIO_MODE_DIGITAL_OUTPUT 1
# define PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT 2
# define PMIC_GPIO_MODE_ANALOG_PASS_THRU 3
# define PMIC_GPIO_REG_LV_MV_MODE_DIR_MASK 0x3
2014-10-22 12:58:46 +03:00
/* PMIC_GPIO_REG_DIG_VIN_CTL */
# define PMIC_GPIO_REG_VIN_SHIFT 0
# define PMIC_GPIO_REG_VIN_MASK 0x7
/* PMIC_GPIO_REG_DIG_PULL_CTL */
# define PMIC_GPIO_REG_PULL_SHIFT 0
# define PMIC_GPIO_REG_PULL_MASK 0x7
# define PMIC_GPIO_PULL_DOWN 4
# define PMIC_GPIO_PULL_DISABLE 5
2017-08-15 08:38:37 +08:00
/* PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL for LV/MV */
# define PMIC_GPIO_LV_MV_OUTPUT_INVERT 0x80
# define PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT 7
# define PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK 0xF
2017-08-15 08:38:38 +08:00
/* PMIC_GPIO_REG_DIG_IN_CTL */
# define PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN 0x80
# define PMIC_GPIO_LV_MV_DIG_IN_DTEST_SEL_MASK 0x7
# define PMIC_GPIO_DIG_IN_DTEST_SEL_MASK 0xf
2014-10-22 12:58:46 +03:00
/* PMIC_GPIO_REG_DIG_OUT_CTL */
# define PMIC_GPIO_REG_OUT_STRENGTH_SHIFT 0
# define PMIC_GPIO_REG_OUT_STRENGTH_MASK 0x3
# define PMIC_GPIO_REG_OUT_TYPE_SHIFT 4
# define PMIC_GPIO_REG_OUT_TYPE_MASK 0x3
/*
* Output type - indicates pin should be configured as push - pull ,
* open drain or open source .
*/
# define PMIC_GPIO_OUT_BUF_CMOS 0
# define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS 1
# define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS 2
/* PMIC_GPIO_REG_EN_CTL */
# define PMIC_GPIO_REG_MASTER_EN_SHIFT 7
# define PMIC_GPIO_PHYSICAL_OFFSET 1
2017-08-15 08:38:37 +08:00
/* PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL */
# define PMIC_GPIO_LV_MV_ANA_MUX_SEL_MASK 0x3
2014-10-22 12:58:46 +03:00
/* Qualcomm specific pin configurations */
# define PMIC_GPIO_CONF_PULL_UP (PIN_CONFIG_END + 1)
# define PMIC_GPIO_CONF_STRENGTH (PIN_CONFIG_END + 2)
2017-08-15 08:38:37 +08:00
# define PMIC_GPIO_CONF_ATEST (PIN_CONFIG_END + 3)
# define PMIC_GPIO_CONF_ANALOG_PASS (PIN_CONFIG_END + 4)
2017-08-15 08:38:38 +08:00
# define PMIC_GPIO_CONF_DTEST_BUFFER (PIN_CONFIG_END + 5)
2017-08-15 08:38:37 +08:00
/* The index of each function in pmic_gpio_functions[] array */
enum pmic_gpio_func_index {
PMIC_GPIO_FUNC_INDEX_NORMAL ,
PMIC_GPIO_FUNC_INDEX_PAIRED ,
PMIC_GPIO_FUNC_INDEX_FUNC1 ,
PMIC_GPIO_FUNC_INDEX_FUNC2 ,
PMIC_GPIO_FUNC_INDEX_FUNC3 ,
PMIC_GPIO_FUNC_INDEX_FUNC4 ,
PMIC_GPIO_FUNC_INDEX_DTEST1 ,
PMIC_GPIO_FUNC_INDEX_DTEST2 ,
PMIC_GPIO_FUNC_INDEX_DTEST3 ,
PMIC_GPIO_FUNC_INDEX_DTEST4 ,
} ;
2014-10-22 12:58:46 +03:00
/**
* struct pmic_gpio_pad - keep current GPIO settings
* @ base : Address base in SPMI device .
* @ irq : IRQ number which this GPIO generate .
* @ is_enabled : Set to false when GPIO should be put in high Z state .
* @ out_value : Cached pin output value
* @ have_buffer : Set to true if GPIO output could be configured in push - pull ,
* open - drain or open - source mode .
* @ output_enabled : Set to true if GPIO output logic is enabled .
* @ input_enabled : Set to true if GPIO input buffer logic is enabled .
2017-08-15 08:38:37 +08:00
* @ analog_pass : Set to true if GPIO is in analog - pass - through mode .
* @ lv_mv_type : Set to true if GPIO subtype is GPIO_LV ( 0x10 ) or GPIO_MV ( 0x11 ) .
2014-10-22 12:58:46 +03:00
* @ num_sources : Number of power - sources supported by this GPIO .
* @ power_source : Current power - source used .
* @ buffer_type : Push - pull , open - drain or open - source .
* @ pullup : Constant current which flow trough GPIO output buffer .
* @ strength : No , Low , Medium , High
* @ function : See pmic_gpio_functions [ ]
2017-08-15 08:38:37 +08:00
* @ atest : the ATEST selection for GPIO analog - pass - through mode
2017-08-15 08:38:38 +08:00
* @ dtest_buffer : the DTEST buffer selection for digital input mode .
2014-10-22 12:58:46 +03:00
*/
struct pmic_gpio_pad {
u16 base ;
int irq ;
bool is_enabled ;
bool out_value ;
bool have_buffer ;
bool output_enabled ;
bool input_enabled ;
2017-08-15 08:38:37 +08:00
bool analog_pass ;
bool lv_mv_type ;
2014-10-22 12:58:46 +03:00
unsigned int num_sources ;
unsigned int power_source ;
unsigned int buffer_type ;
unsigned int pullup ;
unsigned int strength ;
unsigned int function ;
2017-08-15 08:38:37 +08:00
unsigned int atest ;
2017-08-15 08:38:38 +08:00
unsigned int dtest_buffer ;
2014-10-22 12:58:46 +03:00
} ;
struct pmic_gpio_state {
struct device * dev ;
struct regmap * map ;
struct pinctrl_dev * ctrl ;
struct gpio_chip chip ;
} ;
2015-01-12 00:45:55 +01:00
static const struct pinconf_generic_params pmic_gpio_bindings [ ] = {
2015-01-09 07:43:51 -08:00
{ " qcom,pull-up-strength " , PMIC_GPIO_CONF_PULL_UP , 0 } ,
{ " qcom,drive-strength " , PMIC_GPIO_CONF_STRENGTH , 0 } ,
2017-08-15 08:38:37 +08:00
{ " qcom,atest " , PMIC_GPIO_CONF_ATEST , 0 } ,
{ " qcom,analog-pass " , PMIC_GPIO_CONF_ANALOG_PASS , 0 } ,
2017-08-15 08:38:38 +08:00
{ " qcom,dtest-buffer " , PMIC_GPIO_CONF_DTEST_BUFFER , 0 } ,
2014-10-22 12:58:46 +03:00
} ;
2015-01-28 17:08:44 +01:00
# ifdef CONFIG_DEBUG_FS
2015-01-09 07:43:51 -08:00
static const struct pin_config_item pmic_conf_items [ ARRAY_SIZE ( pmic_gpio_bindings ) ] = {
PCONFDUMP ( PMIC_GPIO_CONF_PULL_UP , " pull up strength " , NULL , true ) ,
PCONFDUMP ( PMIC_GPIO_CONF_STRENGTH , " drive-strength " , NULL , true ) ,
2017-08-15 08:38:37 +08:00
PCONFDUMP ( PMIC_GPIO_CONF_ATEST , " atest " , NULL , true ) ,
PCONFDUMP ( PMIC_GPIO_CONF_ANALOG_PASS , " analog-pass " , NULL , true ) ,
2017-08-15 08:38:38 +08:00
PCONFDUMP ( PMIC_GPIO_CONF_DTEST_BUFFER , " dtest-buffer " , NULL , true ) ,
2014-10-22 12:58:46 +03:00
} ;
2015-01-28 17:08:44 +01:00
# endif
2014-10-22 12:58:46 +03:00
static const char * const pmic_gpio_groups [ ] = {
" gpio1 " , " gpio2 " , " gpio3 " , " gpio4 " , " gpio5 " , " gpio6 " , " gpio7 " , " gpio8 " ,
" gpio9 " , " gpio10 " , " gpio11 " , " gpio12 " , " gpio13 " , " gpio14 " , " gpio15 " ,
" gpio16 " , " gpio17 " , " gpio18 " , " gpio19 " , " gpio20 " , " gpio21 " , " gpio22 " ,
" gpio23 " , " gpio24 " , " gpio25 " , " gpio26 " , " gpio27 " , " gpio28 " , " gpio29 " ,
" gpio30 " , " gpio31 " , " gpio32 " , " gpio33 " , " gpio34 " , " gpio35 " , " gpio36 " ,
} ;
static const char * const pmic_gpio_functions [ ] = {
2017-08-15 08:38:37 +08:00
[ PMIC_GPIO_FUNC_INDEX_NORMAL ] = PMIC_GPIO_FUNC_NORMAL ,
[ PMIC_GPIO_FUNC_INDEX_PAIRED ] = PMIC_GPIO_FUNC_PAIRED ,
[ PMIC_GPIO_FUNC_INDEX_FUNC1 ] = PMIC_GPIO_FUNC_FUNC1 ,
[ PMIC_GPIO_FUNC_INDEX_FUNC2 ] = PMIC_GPIO_FUNC_FUNC2 ,
[ PMIC_GPIO_FUNC_INDEX_FUNC3 ] = PMIC_GPIO_FUNC_FUNC3 ,
[ PMIC_GPIO_FUNC_INDEX_FUNC4 ] = PMIC_GPIO_FUNC_FUNC4 ,
[ PMIC_GPIO_FUNC_INDEX_DTEST1 ] = PMIC_GPIO_FUNC_DTEST1 ,
[ PMIC_GPIO_FUNC_INDEX_DTEST2 ] = PMIC_GPIO_FUNC_DTEST2 ,
[ PMIC_GPIO_FUNC_INDEX_DTEST3 ] = PMIC_GPIO_FUNC_DTEST3 ,
[ PMIC_GPIO_FUNC_INDEX_DTEST4 ] = PMIC_GPIO_FUNC_DTEST4 ,
2014-10-22 12:58:46 +03:00
} ;
static int pmic_gpio_read ( struct pmic_gpio_state * state ,
struct pmic_gpio_pad * pad , unsigned int addr )
{
unsigned int val ;
int ret ;
ret = regmap_read ( state - > map , pad - > base + addr , & val ) ;
if ( ret < 0 )
dev_err ( state - > dev , " read 0x%x failed \n " , addr ) ;
else
ret = val ;
return ret ;
}
static int pmic_gpio_write ( struct pmic_gpio_state * state ,
struct pmic_gpio_pad * pad , unsigned int addr ,
unsigned int val )
{
int ret ;
ret = regmap_write ( state - > map , pad - > base + addr , val ) ;
if ( ret < 0 )
dev_err ( state - > dev , " write 0x%x failed \n " , addr ) ;
return ret ;
}
static int pmic_gpio_get_groups_count ( struct pinctrl_dev * pctldev )
{
/* Every PIN is a group */
return pctldev - > desc - > npins ;
}
static const char * pmic_gpio_get_group_name ( struct pinctrl_dev * pctldev ,
unsigned pin )
{
return pctldev - > desc - > pins [ pin ] . name ;
}
static int pmic_gpio_get_group_pins ( struct pinctrl_dev * pctldev , unsigned pin ,
const unsigned * * pins , unsigned * num_pins )
{
* pins = & pctldev - > desc - > pins [ pin ] . number ;
* num_pins = 1 ;
return 0 ;
}
static const struct pinctrl_ops pmic_gpio_pinctrl_ops = {
. get_groups_count = pmic_gpio_get_groups_count ,
. get_group_name = pmic_gpio_get_group_name ,
. get_group_pins = pmic_gpio_get_group_pins ,
2015-01-09 07:43:51 -08:00
. dt_node_to_map = pinconf_generic_dt_node_to_map_group ,
2016-03-31 14:44:42 +03:00
. dt_free_map = pinctrl_utils_free_map ,
2014-10-22 12:58:46 +03:00
} ;
static int pmic_gpio_get_functions_count ( struct pinctrl_dev * pctldev )
{
return ARRAY_SIZE ( pmic_gpio_functions ) ;
}
static const char * pmic_gpio_get_function_name ( struct pinctrl_dev * pctldev ,
unsigned function )
{
return pmic_gpio_functions [ function ] ;
}
static int pmic_gpio_get_function_groups ( struct pinctrl_dev * pctldev ,
unsigned function ,
const char * const * * groups ,
unsigned * const num_qgroups )
{
* groups = pmic_gpio_groups ;
* num_qgroups = pctldev - > desc - > npins ;
return 0 ;
}
static int pmic_gpio_set_mux ( struct pinctrl_dev * pctldev , unsigned function ,
unsigned pin )
{
struct pmic_gpio_state * state = pinctrl_dev_get_drvdata ( pctldev ) ;
struct pmic_gpio_pad * pad ;
unsigned int val ;
int ret ;
2017-08-15 08:38:37 +08:00
if ( function > PMIC_GPIO_FUNC_INDEX_DTEST4 ) {
pr_err ( " function: %d is not defined \n " , function ) ;
return - EINVAL ;
}
2014-10-22 12:58:46 +03:00
pad = pctldev - > desc - > pins [ pin ] . drv_data ;
2017-08-15 08:38:37 +08:00
/*
* Non - LV / MV subtypes only support 2 special functions ,
* offsetting the dtestx function values by 2
*/
if ( ! pad - > lv_mv_type ) {
if ( function = = PMIC_GPIO_FUNC_INDEX_FUNC3 | |
function = = PMIC_GPIO_FUNC_INDEX_FUNC4 ) {
pr_err ( " LV/MV subtype doesn't have func3/func4 \n " ) ;
return - EINVAL ;
}
if ( function > = PMIC_GPIO_FUNC_INDEX_DTEST1 )
function - = ( PMIC_GPIO_FUNC_INDEX_DTEST1 -
PMIC_GPIO_FUNC_INDEX_FUNC3 ) ;
}
2014-10-22 12:58:46 +03:00
pad - > function = function ;
2017-08-15 08:38:37 +08:00
if ( pad - > analog_pass )
val = PMIC_GPIO_MODE_ANALOG_PASS_THRU ;
else if ( pad - > output_enabled & & pad - > input_enabled )
val = PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT ;
else if ( pad - > output_enabled )
val = PMIC_GPIO_MODE_DIGITAL_OUTPUT ;
else
val = PMIC_GPIO_MODE_DIGITAL_INPUT ;
2014-10-22 12:58:46 +03:00
2017-08-15 08:38:37 +08:00
if ( pad - > lv_mv_type ) {
ret = pmic_gpio_write ( state , pad ,
PMIC_GPIO_REG_MODE_CTL , val ) ;
if ( ret < 0 )
return ret ;
2014-10-22 12:58:46 +03:00
2017-08-15 08:38:37 +08:00
val = pad - > atest - 1 ;
ret = pmic_gpio_write ( state , pad ,
PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL , val ) ;
if ( ret < 0 )
return ret ;
val = pad - > out_value
< < PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT ;
val | = pad - > function
& PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK ;
ret = pmic_gpio_write ( state , pad ,
PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL , val ) ;
if ( ret < 0 )
return ret ;
} else {
val = val < < PMIC_GPIO_REG_MODE_DIR_SHIFT ;
val | = pad - > function < < PMIC_GPIO_REG_MODE_FUNCTION_SHIFT ;
val | = pad - > out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT ;
ret = pmic_gpio_write ( state , pad , PMIC_GPIO_REG_MODE_CTL , val ) ;
if ( ret < 0 )
return ret ;
}
2014-10-22 12:58:46 +03:00
val = pad - > is_enabled < < PMIC_GPIO_REG_MASTER_EN_SHIFT ;
return pmic_gpio_write ( state , pad , PMIC_GPIO_REG_EN_CTL , val ) ;
}
static const struct pinmux_ops pmic_gpio_pinmux_ops = {
. get_functions_count = pmic_gpio_get_functions_count ,
. get_function_name = pmic_gpio_get_function_name ,
. get_function_groups = pmic_gpio_get_function_groups ,
. set_mux = pmic_gpio_set_mux ,
} ;
static int pmic_gpio_config_get ( struct pinctrl_dev * pctldev ,
unsigned int pin , unsigned long * config )
{
unsigned param = pinconf_to_config_param ( * config ) ;
struct pmic_gpio_pad * pad ;
unsigned arg ;
pad = pctldev - > desc - > pins [ pin ] . drv_data ;
switch ( param ) {
case PIN_CONFIG_DRIVE_PUSH_PULL :
2018-07-02 15:59:39 -07:00
if ( pad - > buffer_type ! = PMIC_GPIO_OUT_BUF_CMOS )
return - EINVAL ;
arg = 1 ;
2014-10-22 12:58:46 +03:00
break ;
case PIN_CONFIG_DRIVE_OPEN_DRAIN :
2018-07-02 15:59:39 -07:00
if ( pad - > buffer_type ! = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS )
return - EINVAL ;
arg = 1 ;
2014-10-22 12:58:46 +03:00
break ;
case PIN_CONFIG_DRIVE_OPEN_SOURCE :
2018-07-02 15:59:39 -07:00
if ( pad - > buffer_type ! = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS )
return - EINVAL ;
arg = 1 ;
2014-10-22 12:58:46 +03:00
break ;
case PIN_CONFIG_BIAS_PULL_DOWN :
2018-07-02 15:59:39 -07:00
if ( pad - > pullup ! = PMIC_GPIO_PULL_DOWN )
return - EINVAL ;
arg = 1 ;
2014-10-22 12:58:46 +03:00
break ;
case PIN_CONFIG_BIAS_DISABLE :
2018-07-02 15:59:39 -07:00
if ( pad - > pullup ! = PMIC_GPIO_PULL_DISABLE )
return - EINVAL ;
arg = 1 ;
2014-10-22 12:58:46 +03:00
break ;
case PIN_CONFIG_BIAS_PULL_UP :
2018-07-02 15:59:39 -07:00
if ( pad - > pullup ! = PMIC_GPIO_PULL_UP_30 )
return - EINVAL ;
arg = 1 ;
2014-10-22 12:58:46 +03:00
break ;
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE :
2018-07-02 15:59:39 -07:00
if ( pad - > is_enabled )
return - EINVAL ;
arg = 1 ;
2014-10-22 12:58:46 +03:00
break ;
case PIN_CONFIG_POWER_SOURCE :
arg = pad - > power_source ;
break ;
case PIN_CONFIG_INPUT_ENABLE :
2018-07-02 15:59:39 -07:00
if ( ! pad - > input_enabled )
return - EINVAL ;
arg = 1 ;
2014-10-22 12:58:46 +03:00
break ;
case PIN_CONFIG_OUTPUT :
arg = pad - > out_value ;
break ;
case PMIC_GPIO_CONF_PULL_UP :
arg = pad - > pullup ;
break ;
case PMIC_GPIO_CONF_STRENGTH :
arg = pad - > strength ;
break ;
2017-08-15 08:38:37 +08:00
case PMIC_GPIO_CONF_ATEST :
arg = pad - > atest ;
break ;
case PMIC_GPIO_CONF_ANALOG_PASS :
arg = pad - > analog_pass ;
break ;
2017-08-15 08:38:38 +08:00
case PMIC_GPIO_CONF_DTEST_BUFFER :
arg = pad - > dtest_buffer ;
break ;
2014-10-22 12:58:46 +03:00
default :
return - EINVAL ;
}
* config = pinconf_to_config_packed ( param , arg ) ;
return 0 ;
}
static int pmic_gpio_config_set ( struct pinctrl_dev * pctldev , unsigned int pin ,
unsigned long * configs , unsigned nconfs )
{
struct pmic_gpio_state * state = pinctrl_dev_get_drvdata ( pctldev ) ;
struct pmic_gpio_pad * pad ;
unsigned param , arg ;
unsigned int val ;
int i , ret ;
pad = pctldev - > desc - > pins [ pin ] . drv_data ;
2017-09-12 08:32:46 +08:00
pad - > is_enabled = true ;
2014-10-22 12:58:46 +03:00
for ( i = 0 ; i < nconfs ; i + + ) {
param = pinconf_to_config_param ( configs [ i ] ) ;
arg = pinconf_to_config_argument ( configs [ i ] ) ;
switch ( param ) {
case PIN_CONFIG_DRIVE_PUSH_PULL :
pad - > buffer_type = PMIC_GPIO_OUT_BUF_CMOS ;
break ;
case PIN_CONFIG_DRIVE_OPEN_DRAIN :
if ( ! pad - > have_buffer )
return - EINVAL ;
pad - > buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS ;
break ;
case PIN_CONFIG_DRIVE_OPEN_SOURCE :
if ( ! pad - > have_buffer )
return - EINVAL ;
pad - > buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS ;
break ;
case PIN_CONFIG_BIAS_DISABLE :
pad - > pullup = PMIC_GPIO_PULL_DISABLE ;
break ;
case PIN_CONFIG_BIAS_PULL_UP :
pad - > pullup = PMIC_GPIO_PULL_UP_30 ;
break ;
case PIN_CONFIG_BIAS_PULL_DOWN :
if ( arg )
pad - > pullup = PMIC_GPIO_PULL_DOWN ;
else
pad - > pullup = PMIC_GPIO_PULL_DISABLE ;
break ;
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE :
pad - > is_enabled = false ;
break ;
case PIN_CONFIG_POWER_SOURCE :
2017-07-19 14:39:55 +08:00
if ( arg > = pad - > num_sources )
2014-10-22 12:58:46 +03:00
return - EINVAL ;
pad - > power_source = arg ;
break ;
case PIN_CONFIG_INPUT_ENABLE :
pad - > input_enabled = arg ? true : false ;
break ;
case PIN_CONFIG_OUTPUT :
pad - > output_enabled = true ;
pad - > out_value = arg ;
break ;
case PMIC_GPIO_CONF_PULL_UP :
if ( arg > PMIC_GPIO_PULL_UP_1P5_30 )
return - EINVAL ;
pad - > pullup = arg ;
break ;
case PMIC_GPIO_CONF_STRENGTH :
if ( arg > PMIC_GPIO_STRENGTH_LOW )
return - EINVAL ;
pad - > strength = arg ;
break ;
2017-08-15 08:38:37 +08:00
case PMIC_GPIO_CONF_ATEST :
if ( ! pad - > lv_mv_type | | arg > 4 )
return - EINVAL ;
pad - > atest = arg ;
break ;
case PMIC_GPIO_CONF_ANALOG_PASS :
if ( ! pad - > lv_mv_type )
return - EINVAL ;
pad - > analog_pass = true ;
break ;
2017-08-15 08:38:38 +08:00
case PMIC_GPIO_CONF_DTEST_BUFFER :
if ( arg > 4 )
return - EINVAL ;
pad - > dtest_buffer = arg ;
break ;
2014-10-22 12:58:46 +03:00
default :
return - EINVAL ;
}
}
val = pad - > power_source < < PMIC_GPIO_REG_VIN_SHIFT ;
ret = pmic_gpio_write ( state , pad , PMIC_GPIO_REG_DIG_VIN_CTL , val ) ;
if ( ret < 0 )
return ret ;
val = pad - > pullup < < PMIC_GPIO_REG_PULL_SHIFT ;
ret = pmic_gpio_write ( state , pad , PMIC_GPIO_REG_DIG_PULL_CTL , val ) ;
if ( ret < 0 )
return ret ;
val = pad - > buffer_type < < PMIC_GPIO_REG_OUT_TYPE_SHIFT ;
2015-04-09 18:18:35 +03:00
val | = pad - > strength < < PMIC_GPIO_REG_OUT_STRENGTH_SHIFT ;
2014-10-22 12:58:46 +03:00
ret = pmic_gpio_write ( state , pad , PMIC_GPIO_REG_DIG_OUT_CTL , val ) ;
if ( ret < 0 )
return ret ;
2017-08-15 08:38:38 +08:00
if ( pad - > dtest_buffer = = 0 ) {
val = 0 ;
} else {
if ( pad - > lv_mv_type ) {
val = pad - > dtest_buffer - 1 ;
val | = PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN ;
} else {
val = BIT ( pad - > dtest_buffer - 1 ) ;
}
}
ret = pmic_gpio_write ( state , pad , PMIC_GPIO_REG_DIG_IN_CTL , val ) ;
if ( ret < 0 )
return ret ;
2017-08-15 08:38:37 +08:00
if ( pad - > analog_pass )
val = PMIC_GPIO_MODE_ANALOG_PASS_THRU ;
else if ( pad - > output_enabled & & pad - > input_enabled )
val = PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT ;
else if ( pad - > output_enabled )
val = PMIC_GPIO_MODE_DIGITAL_OUTPUT ;
else
val = PMIC_GPIO_MODE_DIGITAL_INPUT ;
2014-10-22 12:58:46 +03:00
2017-08-15 08:38:37 +08:00
if ( pad - > lv_mv_type ) {
ret = pmic_gpio_write ( state , pad ,
PMIC_GPIO_REG_MODE_CTL , val ) ;
if ( ret < 0 )
return ret ;
val = pad - > atest - 1 ;
ret = pmic_gpio_write ( state , pad ,
PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL , val ) ;
if ( ret < 0 )
return ret ;
val = pad - > out_value
< < PMIC_GPIO_LV_MV_OUTPUT_INVERT_SHIFT ;
val | = pad - > function
& PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK ;
ret = pmic_gpio_write ( state , pad ,
PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL , val ) ;
if ( ret < 0 )
return ret ;
} else {
val = val < < PMIC_GPIO_REG_MODE_DIR_SHIFT ;
val | = pad - > function < < PMIC_GPIO_REG_MODE_FUNCTION_SHIFT ;
val | = pad - > out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT ;
2014-10-22 12:58:46 +03:00
2017-08-15 08:38:37 +08:00
ret = pmic_gpio_write ( state , pad , PMIC_GPIO_REG_MODE_CTL , val ) ;
if ( ret < 0 )
return ret ;
}
2017-09-12 08:32:46 +08:00
val = pad - > is_enabled < < PMIC_GPIO_REG_MASTER_EN_SHIFT ;
ret = pmic_gpio_write ( state , pad , PMIC_GPIO_REG_EN_CTL , val ) ;
2017-08-15 08:38:37 +08:00
return ret ;
2014-10-22 12:58:46 +03:00
}
static void pmic_gpio_config_dbg_show ( struct pinctrl_dev * pctldev ,
struct seq_file * s , unsigned pin )
{
struct pmic_gpio_state * state = pinctrl_dev_get_drvdata ( pctldev ) ;
struct pmic_gpio_pad * pad ;
2017-08-15 08:38:37 +08:00
int ret , val , function ;
2014-10-22 12:58:46 +03:00
static const char * const biases [ ] = {
" pull-up 30uA " , " pull-up 1.5uA " , " pull-up 31.5uA " ,
" pull-up 1.5uA + 30uA boost " , " pull-down 10uA " , " no pull "
} ;
static const char * const buffer_types [ ] = {
" push-pull " , " open-drain " , " open-source "
} ;
static const char * const strengths [ ] = {
" no " , " high " , " medium " , " low "
} ;
pad = pctldev - > desc - > pins [ pin ] . drv_data ;
seq_printf ( s , " gpio%-2d: " , pin + PMIC_GPIO_PHYSICAL_OFFSET ) ;
val = pmic_gpio_read ( state , pad , PMIC_GPIO_REG_EN_CTL ) ;
if ( val < 0 | | ! ( val > > PMIC_GPIO_REG_MASTER_EN_SHIFT ) ) {
seq_puts ( s , " --- " ) ;
} else {
2015-04-09 18:18:36 +03:00
if ( pad - > input_enabled ) {
2014-10-22 12:58:46 +03:00
ret = pmic_gpio_read ( state , pad , PMIC_MPP_REG_RT_STS ) ;
2015-04-09 18:18:36 +03:00
if ( ret < 0 )
return ;
ret & = PMIC_MPP_REG_RT_STS_VAL_MASK ;
pad - > out_value = ret ;
2014-10-22 12:58:46 +03:00
}
2017-08-15 08:38:37 +08:00
/*
* For the non - LV / MV subtypes only 2 special functions are
* available , offsetting the dtest function values by 2.
*/
function = pad - > function ;
if ( ! pad - > lv_mv_type & &
pad - > function > = PMIC_GPIO_FUNC_INDEX_FUNC3 )
function + = PMIC_GPIO_FUNC_INDEX_DTEST1 -
PMIC_GPIO_FUNC_INDEX_FUNC3 ;
if ( pad - > analog_pass )
seq_puts ( s , " analog-pass " ) ;
else
seq_printf ( s , " %-4s " ,
pad - > output_enabled ? " out " : " in " ) ;
seq_printf ( s , " %-7s " , pmic_gpio_functions [ function ] ) ;
2014-10-22 12:58:46 +03:00
seq_printf ( s , " vin-%d " , pad - > power_source ) ;
seq_printf ( s , " %-27s " , biases [ pad - > pullup ] ) ;
seq_printf ( s , " %-10s " , buffer_types [ pad - > buffer_type ] ) ;
seq_printf ( s , " %-4s " , pad - > out_value ? " high " : " low " ) ;
seq_printf ( s , " %-7s " , strengths [ pad - > strength ] ) ;
2017-08-15 08:38:37 +08:00
seq_printf ( s , " atest-%d " , pad - > atest ) ;
2017-08-15 08:38:38 +08:00
seq_printf ( s , " dtest-%d " , pad - > dtest_buffer ) ;
2014-10-22 12:58:46 +03:00
}
}
static const struct pinconf_ops pmic_gpio_pinconf_ops = {
2015-01-09 07:43:51 -08:00
. is_generic = true ,
2014-10-22 12:58:46 +03:00
. pin_config_group_get = pmic_gpio_config_get ,
. pin_config_group_set = pmic_gpio_config_set ,
. pin_config_group_dbg_show = pmic_gpio_config_dbg_show ,
} ;
static int pmic_gpio_direction_input ( struct gpio_chip * chip , unsigned pin )
{
2015-12-08 09:51:47 +01:00
struct pmic_gpio_state * state = gpiochip_get_data ( chip ) ;
2014-10-22 12:58:46 +03:00
unsigned long config ;
config = pinconf_to_config_packed ( PIN_CONFIG_INPUT_ENABLE , 1 ) ;
return pmic_gpio_config_set ( state - > ctrl , pin , & config , 1 ) ;
}
static int pmic_gpio_direction_output ( struct gpio_chip * chip ,
unsigned pin , int val )
{
2015-12-08 09:51:47 +01:00
struct pmic_gpio_state * state = gpiochip_get_data ( chip ) ;
2014-10-22 12:58:46 +03:00
unsigned long config ;
config = pinconf_to_config_packed ( PIN_CONFIG_OUTPUT , val ) ;
return pmic_gpio_config_set ( state - > ctrl , pin , & config , 1 ) ;
}
static int pmic_gpio_get ( struct gpio_chip * chip , unsigned pin )
{
2015-12-08 09:51:47 +01:00
struct pmic_gpio_state * state = gpiochip_get_data ( chip ) ;
2014-10-22 12:58:46 +03:00
struct pmic_gpio_pad * pad ;
int ret ;
pad = state - > ctrl - > desc - > pins [ pin ] . drv_data ;
if ( ! pad - > is_enabled )
return - EINVAL ;
if ( pad - > input_enabled ) {
ret = pmic_gpio_read ( state , pad , PMIC_MPP_REG_RT_STS ) ;
if ( ret < 0 )
return ret ;
pad - > out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK ;
}
2015-12-21 16:29:50 +01:00
return ! ! pad - > out_value ;
2014-10-22 12:58:46 +03:00
}
static void pmic_gpio_set ( struct gpio_chip * chip , unsigned pin , int value )
{
2015-12-08 09:51:47 +01:00
struct pmic_gpio_state * state = gpiochip_get_data ( chip ) ;
2014-10-22 12:58:46 +03:00
unsigned long config ;
config = pinconf_to_config_packed ( PIN_CONFIG_OUTPUT , value ) ;
pmic_gpio_config_set ( state - > ctrl , pin , & config , 1 ) ;
}
static int pmic_gpio_of_xlate ( struct gpio_chip * chip ,
const struct of_phandle_args * gpio_desc ,
u32 * flags )
{
if ( chip - > of_gpio_n_cells < 2 )
return - EINVAL ;
if ( flags )
* flags = gpio_desc - > args [ 1 ] ;
return gpio_desc - > args [ 0 ] - PMIC_GPIO_PHYSICAL_OFFSET ;
}
static int pmic_gpio_to_irq ( struct gpio_chip * chip , unsigned pin )
{
2015-12-08 09:51:47 +01:00
struct pmic_gpio_state * state = gpiochip_get_data ( chip ) ;
2014-10-22 12:58:46 +03:00
struct pmic_gpio_pad * pad ;
pad = state - > ctrl - > desc - > pins [ pin ] . drv_data ;
return pad - > irq ;
}
static void pmic_gpio_dbg_show ( struct seq_file * s , struct gpio_chip * chip )
{
2015-12-08 09:51:47 +01:00
struct pmic_gpio_state * state = gpiochip_get_data ( chip ) ;
2014-10-22 12:58:46 +03:00
unsigned i ;
for ( i = 0 ; i < chip - > ngpio ; i + + ) {
pmic_gpio_config_dbg_show ( state - > ctrl , s , i ) ;
seq_puts ( s , " \n " ) ;
}
}
static const struct gpio_chip pmic_gpio_gpio_template = {
. direction_input = pmic_gpio_direction_input ,
. direction_output = pmic_gpio_direction_output ,
. get = pmic_gpio_get ,
. set = pmic_gpio_set ,
2015-10-11 17:34:19 +02:00
. request = gpiochip_generic_request ,
. free = gpiochip_generic_free ,
2014-10-22 12:58:46 +03:00
. of_xlate = pmic_gpio_of_xlate ,
. to_irq = pmic_gpio_to_irq ,
. dbg_show = pmic_gpio_dbg_show ,
} ;
static int pmic_gpio_populate ( struct pmic_gpio_state * state ,
struct pmic_gpio_pad * pad )
{
int type , subtype , val , dir ;
type = pmic_gpio_read ( state , pad , PMIC_GPIO_REG_TYPE ) ;
if ( type < 0 )
return type ;
if ( type ! = PMIC_GPIO_TYPE ) {
dev_err ( state - > dev , " incorrect block type 0x%x at 0x%x \n " ,
type , pad - > base ) ;
return - ENODEV ;
}
subtype = pmic_gpio_read ( state , pad , PMIC_GPIO_REG_SUBTYPE ) ;
if ( subtype < 0 )
return subtype ;
switch ( subtype ) {
case PMIC_GPIO_SUBTYPE_GPIO_4CH :
pad - > have_buffer = true ;
case PMIC_GPIO_SUBTYPE_GPIOC_4CH :
pad - > num_sources = 4 ;
break ;
case PMIC_GPIO_SUBTYPE_GPIO_8CH :
pad - > have_buffer = true ;
case PMIC_GPIO_SUBTYPE_GPIOC_8CH :
pad - > num_sources = 8 ;
break ;
2017-08-15 08:38:37 +08:00
case PMIC_GPIO_SUBTYPE_GPIO_LV :
pad - > num_sources = 1 ;
pad - > have_buffer = true ;
pad - > lv_mv_type = true ;
break ;
case PMIC_GPIO_SUBTYPE_GPIO_MV :
pad - > num_sources = 2 ;
pad - > have_buffer = true ;
pad - > lv_mv_type = true ;
break ;
2014-10-22 12:58:46 +03:00
default :
dev_err ( state - > dev , " unknown GPIO type 0x%x \n " , subtype ) ;
return - ENODEV ;
}
2017-08-15 08:38:37 +08:00
if ( pad - > lv_mv_type ) {
val = pmic_gpio_read ( state , pad ,
PMIC_GPIO_REG_LV_MV_DIG_OUT_SOURCE_CTL ) ;
if ( val < 0 )
return val ;
pad - > out_value = ! ! ( val & PMIC_GPIO_LV_MV_OUTPUT_INVERT ) ;
pad - > function = val & PMIC_GPIO_LV_MV_OUTPUT_SOURCE_SEL_MASK ;
val = pmic_gpio_read ( state , pad , PMIC_GPIO_REG_MODE_CTL ) ;
if ( val < 0 )
return val ;
dir = val & PMIC_GPIO_REG_LV_MV_MODE_DIR_MASK ;
} else {
val = pmic_gpio_read ( state , pad , PMIC_GPIO_REG_MODE_CTL ) ;
if ( val < 0 )
return val ;
2014-10-22 12:58:46 +03:00
2017-08-15 08:38:37 +08:00
pad - > out_value = val & PMIC_GPIO_REG_MODE_VALUE_SHIFT ;
dir = val > > PMIC_GPIO_REG_MODE_DIR_SHIFT ;
dir & = PMIC_GPIO_REG_MODE_DIR_MASK ;
pad - > function = val > > PMIC_GPIO_REG_MODE_FUNCTION_SHIFT ;
pad - > function & = PMIC_GPIO_REG_MODE_FUNCTION_MASK ;
}
2014-10-22 12:58:46 +03:00
switch ( dir ) {
2017-08-15 08:38:37 +08:00
case PMIC_GPIO_MODE_DIGITAL_INPUT :
2014-10-22 12:58:46 +03:00
pad - > input_enabled = true ;
pad - > output_enabled = false ;
break ;
2017-08-15 08:38:37 +08:00
case PMIC_GPIO_MODE_DIGITAL_OUTPUT :
2014-10-22 12:58:46 +03:00
pad - > input_enabled = false ;
pad - > output_enabled = true ;
break ;
2017-08-15 08:38:37 +08:00
case PMIC_GPIO_MODE_DIGITAL_INPUT_OUTPUT :
2014-10-22 12:58:46 +03:00
pad - > input_enabled = true ;
pad - > output_enabled = true ;
break ;
2017-08-15 08:38:37 +08:00
case PMIC_GPIO_MODE_ANALOG_PASS_THRU :
if ( ! pad - > lv_mv_type )
return - ENODEV ;
pad - > analog_pass = true ;
break ;
2014-10-22 12:58:46 +03:00
default :
dev_err ( state - > dev , " unknown GPIO direction \n " ) ;
return - ENODEV ;
}
val = pmic_gpio_read ( state , pad , PMIC_GPIO_REG_DIG_VIN_CTL ) ;
if ( val < 0 )
return val ;
pad - > power_source = val > > PMIC_GPIO_REG_VIN_SHIFT ;
pad - > power_source & = PMIC_GPIO_REG_VIN_MASK ;
val = pmic_gpio_read ( state , pad , PMIC_GPIO_REG_DIG_PULL_CTL ) ;
if ( val < 0 )
return val ;
pad - > pullup = val > > PMIC_GPIO_REG_PULL_SHIFT ;
pad - > pullup & = PMIC_GPIO_REG_PULL_MASK ;
2017-08-15 08:38:38 +08:00
val = pmic_gpio_read ( state , pad , PMIC_GPIO_REG_DIG_IN_CTL ) ;
if ( val < 0 )
return val ;
if ( pad - > lv_mv_type & & ( val & PMIC_GPIO_LV_MV_DIG_IN_DTEST_EN ) )
pad - > dtest_buffer =
( val & PMIC_GPIO_LV_MV_DIG_IN_DTEST_SEL_MASK ) + 1 ;
else if ( ! pad - > lv_mv_type )
pad - > dtest_buffer = ffs ( val ) ;
else
pad - > dtest_buffer = 0 ;
val = pmic_gpio_read ( state , pad , PMIC_GPIO_REG_DIG_OUT_CTL ) ;
if ( val < 0 )
return val ;
2014-10-22 12:58:46 +03:00
pad - > strength = val > > PMIC_GPIO_REG_OUT_STRENGTH_SHIFT ;
pad - > strength & = PMIC_GPIO_REG_OUT_STRENGTH_MASK ;
pad - > buffer_type = val > > PMIC_GPIO_REG_OUT_TYPE_SHIFT ;
pad - > buffer_type & = PMIC_GPIO_REG_OUT_TYPE_MASK ;
2017-08-15 08:38:37 +08:00
if ( pad - > lv_mv_type ) {
val = pmic_gpio_read ( state , pad ,
PMIC_GPIO_REG_LV_MV_ANA_PASS_THRU_SEL ) ;
if ( val < 0 )
return val ;
pad - > atest = ( val & PMIC_GPIO_LV_MV_ANA_MUX_SEL_MASK ) + 1 ;
}
2014-10-22 12:58:46 +03:00
/* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */
pad - > is_enabled = true ;
return 0 ;
}
static int pmic_gpio_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct pinctrl_pin_desc * pindesc ;
struct pinctrl_desc * pctrldesc ;
struct pmic_gpio_pad * pad , * pads ;
struct pmic_gpio_state * state ;
int ret , npins , i ;
2015-11-18 11:33:17 -08:00
u32 reg ;
2014-10-22 12:58:46 +03:00
2015-11-18 11:33:17 -08:00
ret = of_property_read_u32 ( dev - > of_node , " reg " , & reg ) ;
2014-10-22 12:58:46 +03:00
if ( ret < 0 ) {
2015-11-18 11:33:17 -08:00
dev_err ( dev , " missing base address " ) ;
2014-10-22 12:58:46 +03:00
return ret ;
}
2016-01-06 17:37:41 -08:00
npins = platform_irq_count ( pdev ) ;
2014-10-22 12:58:46 +03:00
if ( ! npins )
return - EINVAL ;
2016-01-06 17:37:41 -08:00
if ( npins < 0 )
return npins ;
2014-10-22 12:58:46 +03:00
BUG_ON ( npins > ARRAY_SIZE ( pmic_gpio_groups ) ) ;
state = devm_kzalloc ( dev , sizeof ( * state ) , GFP_KERNEL ) ;
if ( ! state )
return - ENOMEM ;
platform_set_drvdata ( pdev , state ) ;
state - > dev = & pdev - > dev ;
state - > map = dev_get_regmap ( dev - > parent , NULL ) ;
pindesc = devm_kcalloc ( dev , npins , sizeof ( * pindesc ) , GFP_KERNEL ) ;
if ( ! pindesc )
return - ENOMEM ;
pads = devm_kcalloc ( dev , npins , sizeof ( * pads ) , GFP_KERNEL ) ;
if ( ! pads )
return - ENOMEM ;
pctrldesc = devm_kzalloc ( dev , sizeof ( * pctrldesc ) , GFP_KERNEL ) ;
if ( ! pctrldesc )
return - ENOMEM ;
pctrldesc - > pctlops = & pmic_gpio_pinctrl_ops ;
pctrldesc - > pmxops = & pmic_gpio_pinmux_ops ;
pctrldesc - > confops = & pmic_gpio_pinconf_ops ;
pctrldesc - > owner = THIS_MODULE ;
pctrldesc - > name = dev_name ( dev ) ;
pctrldesc - > pins = pindesc ;
pctrldesc - > npins = npins ;
2015-01-12 00:45:55 +01:00
pctrldesc - > num_custom_params = ARRAY_SIZE ( pmic_gpio_bindings ) ;
pctrldesc - > custom_params = pmic_gpio_bindings ;
2015-01-28 17:08:44 +01:00
# ifdef CONFIG_DEBUG_FS
2015-01-12 00:45:55 +01:00
pctrldesc - > custom_conf_items = pmic_conf_items ;
2015-01-28 17:08:44 +01:00
# endif
2014-10-22 12:58:46 +03:00
for ( i = 0 ; i < npins ; i + + , pindesc + + ) {
pad = & pads [ i ] ;
pindesc - > drv_data = pad ;
pindesc - > number = i ;
pindesc - > name = pmic_gpio_groups [ i ] ;
pad - > irq = platform_get_irq ( pdev , i ) ;
if ( pad - > irq < 0 )
return pad - > irq ;
2015-11-18 11:33:17 -08:00
pad - > base = reg + i * PMIC_GPIO_ADDRESS_RANGE ;
2014-10-22 12:58:46 +03:00
ret = pmic_gpio_populate ( state , pad ) ;
if ( ret < 0 )
return ret ;
}
state - > chip = pmic_gpio_gpio_template ;
2015-11-04 09:56:26 +01:00
state - > chip . parent = dev ;
2014-10-22 12:58:46 +03:00
state - > chip . base = - 1 ;
state - > chip . ngpio = npins ;
state - > chip . label = dev_name ( dev ) ;
state - > chip . of_gpio_n_cells = 2 ;
state - > chip . can_sleep = false ;
2016-02-24 14:44:07 +05:30
state - > ctrl = devm_pinctrl_register ( dev , pctrldesc , state ) ;
2015-06-09 13:01:16 +09:00
if ( IS_ERR ( state - > ctrl ) )
return PTR_ERR ( state - > ctrl ) ;
2014-10-22 12:58:46 +03:00
2015-12-08 09:51:47 +01:00
ret = gpiochip_add_data ( & state - > chip , state ) ;
2014-10-22 12:58:46 +03:00
if ( ret ) {
dev_err ( state - > dev , " can't add gpio chip \n " ) ;
2016-02-24 14:44:07 +05:30
return ret ;
2014-10-22 12:58:46 +03:00
}
2018-10-31 20:11:47 -04:00
/*
* For DeviceTree - supported systems , the gpio core checks the
* pinctrl ' s device node for the " gpio-ranges " property .
* If it is present , it takes care of adding the pin ranges
* for the driver . In this case the driver can skip ahead .
*
* In order to remain compatible with older , existing DeviceTree
* files which don ' t set the " gpio-ranges " property or systems that
* utilize ACPI the driver has to call gpiochip_add_pin_range ( ) .
*/
if ( ! of_property_read_bool ( dev - > of_node , " gpio-ranges " ) ) {
ret = gpiochip_add_pin_range ( & state - > chip , dev_name ( dev ) , 0 , 0 ,
npins ) ;
if ( ret ) {
dev_err ( dev , " failed to add pin range \n " ) ;
goto err_range ;
}
2014-10-22 12:58:46 +03:00
}
return 0 ;
err_range :
gpiochip_remove ( & state - > chip ) ;
return ret ;
}
static int pmic_gpio_remove ( struct platform_device * pdev )
{
struct pmic_gpio_state * state = platform_get_drvdata ( pdev ) ;
gpiochip_remove ( & state - > chip ) ;
return 0 ;
}
static const struct of_device_id pmic_gpio_of_match [ ] = {
2019-01-19 15:42:39 -05:00
{ . compatible = " qcom,pm8005-gpio " } , /* 4 GPIO's */
2015-03-31 12:37:18 +03:00
{ . compatible = " qcom,pm8916-gpio " } , /* 4 GPIO's */
2014-10-22 12:58:46 +03:00
{ . compatible = " qcom,pm8941-gpio " } , /* 36 GPIO's */
2015-11-17 16:52:32 -08:00
{ . compatible = " qcom,pm8994-gpio " } , /* 22 GPIO's */
2017-11-02 14:59:42 +05:30
{ . compatible = " qcom,pmi8994-gpio " } , /* 10 GPIO's */
2019-01-19 15:42:39 -05:00
{ . compatible = " qcom,pm8998-gpio " } , /* 26 GPIO's */
{ . compatible = " qcom,pmi8998-gpio " } , /* 14 GPIO's */
2014-10-22 12:58:46 +03:00
{ . compatible = " qcom,pma8084-gpio " } , /* 22 GPIO's */
2018-11-20 13:45:22 +08:00
{ . compatible = " qcom,pms405-gpio " } , /* 12 GPIO's, holes on 1 9 10 */
2016-07-11 12:01:09 -07:00
{ . compatible = " qcom,spmi-gpio " } , /* Generic */
2014-10-22 12:58:46 +03:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , pmic_gpio_of_match ) ;
static struct platform_driver pmic_gpio_driver = {
. driver = {
. name = " qcom-spmi-gpio " ,
. of_match_table = pmic_gpio_of_match ,
} ,
. probe = pmic_gpio_probe ,
. remove = pmic_gpio_remove ,
} ;
module_platform_driver ( pmic_gpio_driver ) ;
MODULE_AUTHOR ( " Ivan T. Ivanov <iivanov@mm-sol.com> " ) ;
MODULE_DESCRIPTION ( " Qualcomm SPMI PMIC GPIO pin control driver " ) ;
MODULE_ALIAS ( " platform:qcom-spmi-gpio " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;