2015-06-13 01:47:10 +03:00
/*
* Copyright ( c ) 2012 - 2015 , 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 .
*/
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/err.h>
# include <linux/kernel.h>
# include <linux/interrupt.h>
# include <linux/bitops.h>
# include <linux/slab.h>
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/platform_device.h>
# include <linux/ktime.h>
# include <linux/regulator/driver.h>
# include <linux/regmap.h>
# include <linux/list.h>
2018-05-21 14:25:30 +03:00
# include <linux/mfd/syscon.h>
# include <linux/io.h>
2015-06-13 01:47:10 +03:00
2015-07-18 00:41:55 +03:00
/* Pin control enable input pins. */
# define SPMI_REGULATOR_PIN_CTRL_ENABLE_NONE 0x00
# define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN0 0x01
# define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN1 0x02
# define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN2 0x04
# define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN3 0x08
# define SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT 0x10
/* Pin control high power mode input pins. */
# define SPMI_REGULATOR_PIN_CTRL_HPM_NONE 0x00
# define SPMI_REGULATOR_PIN_CTRL_HPM_EN0 0x01
# define SPMI_REGULATOR_PIN_CTRL_HPM_EN1 0x02
# define SPMI_REGULATOR_PIN_CTRL_HPM_EN2 0x04
# define SPMI_REGULATOR_PIN_CTRL_HPM_EN3 0x08
# define SPMI_REGULATOR_PIN_CTRL_HPM_SLEEP_B 0x10
# define SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT 0x20
/*
* Used with enable parameters to specify that hardware default register values
* should be left unaltered .
*/
# define SPMI_REGULATOR_USE_HW_DEFAULT 2
/* Soft start strength of a voltage switch type regulator */
enum spmi_vs_soft_start_str {
SPMI_VS_SOFT_START_STR_0P05_UA = 0 ,
SPMI_VS_SOFT_START_STR_0P25_UA ,
SPMI_VS_SOFT_START_STR_0P55_UA ,
SPMI_VS_SOFT_START_STR_0P75_UA ,
SPMI_VS_SOFT_START_STR_HW_DEFAULT ,
} ;
/**
* struct spmi_regulator_init_data - spmi - regulator initialization data
* @ pin_ctrl_enable : Bit mask specifying which hardware pins should be
* used to enable the regulator , if any
* Value should be an ORing of
* SPMI_REGULATOR_PIN_CTRL_ENABLE_ * constants . If
* the bit specified by
* SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT is
* set , then pin control enable hardware registers
* will not be modified .
* @ pin_ctrl_hpm : Bit mask specifying which hardware pins should be
* used to force the regulator into high power
* mode , if any
* Value should be an ORing of
* SPMI_REGULATOR_PIN_CTRL_HPM_ * constants . If
* the bit specified by
* SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT is
* set , then pin control mode hardware registers
* will not be modified .
* @ vs_soft_start_strength : This parameter sets the soft start strength for
* voltage switch type regulators . Its value
* should be one of SPMI_VS_SOFT_START_STR_ * . If
* its value is SPMI_VS_SOFT_START_STR_HW_DEFAULT ,
* then the soft start strength will be left at its
* default hardware value .
*/
struct spmi_regulator_init_data {
unsigned pin_ctrl_enable ;
unsigned pin_ctrl_hpm ;
enum spmi_vs_soft_start_str vs_soft_start_strength ;
} ;
2015-06-13 01:47:10 +03:00
/* These types correspond to unique register layouts. */
enum spmi_regulator_logical_type {
SPMI_REGULATOR_LOGICAL_TYPE_SMPS ,
SPMI_REGULATOR_LOGICAL_TYPE_LDO ,
SPMI_REGULATOR_LOGICAL_TYPE_VS ,
SPMI_REGULATOR_LOGICAL_TYPE_BOOST ,
SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS ,
SPMI_REGULATOR_LOGICAL_TYPE_BOOST_BYP ,
SPMI_REGULATOR_LOGICAL_TYPE_LN_LDO ,
SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS ,
SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS ,
SPMI_REGULATOR_LOGICAL_TYPE_ULT_LDO ,
} ;
enum spmi_regulator_type {
SPMI_REGULATOR_TYPE_BUCK = 0x03 ,
SPMI_REGULATOR_TYPE_LDO = 0x04 ,
SPMI_REGULATOR_TYPE_VS = 0x05 ,
SPMI_REGULATOR_TYPE_BOOST = 0x1b ,
SPMI_REGULATOR_TYPE_FTS = 0x1c ,
SPMI_REGULATOR_TYPE_BOOST_BYP = 0x1f ,
SPMI_REGULATOR_TYPE_ULT_LDO = 0x21 ,
SPMI_REGULATOR_TYPE_ULT_BUCK = 0x22 ,
} ;
enum spmi_regulator_subtype {
SPMI_REGULATOR_SUBTYPE_GP_CTL = 0x08 ,
SPMI_REGULATOR_SUBTYPE_RF_CTL = 0x09 ,
SPMI_REGULATOR_SUBTYPE_N50 = 0x01 ,
SPMI_REGULATOR_SUBTYPE_N150 = 0x02 ,
SPMI_REGULATOR_SUBTYPE_N300 = 0x03 ,
SPMI_REGULATOR_SUBTYPE_N600 = 0x04 ,
SPMI_REGULATOR_SUBTYPE_N1200 = 0x05 ,
SPMI_REGULATOR_SUBTYPE_N600_ST = 0x06 ,
SPMI_REGULATOR_SUBTYPE_N1200_ST = 0x07 ,
SPMI_REGULATOR_SUBTYPE_N900_ST = 0x14 ,
SPMI_REGULATOR_SUBTYPE_N300_ST = 0x15 ,
SPMI_REGULATOR_SUBTYPE_P50 = 0x08 ,
SPMI_REGULATOR_SUBTYPE_P150 = 0x09 ,
SPMI_REGULATOR_SUBTYPE_P300 = 0x0a ,
SPMI_REGULATOR_SUBTYPE_P600 = 0x0b ,
SPMI_REGULATOR_SUBTYPE_P1200 = 0x0c ,
SPMI_REGULATOR_SUBTYPE_LN = 0x10 ,
SPMI_REGULATOR_SUBTYPE_LV_P50 = 0x28 ,
SPMI_REGULATOR_SUBTYPE_LV_P150 = 0x29 ,
SPMI_REGULATOR_SUBTYPE_LV_P300 = 0x2a ,
SPMI_REGULATOR_SUBTYPE_LV_P600 = 0x2b ,
SPMI_REGULATOR_SUBTYPE_LV_P1200 = 0x2c ,
SPMI_REGULATOR_SUBTYPE_LV_P450 = 0x2d ,
SPMI_REGULATOR_SUBTYPE_LV100 = 0x01 ,
SPMI_REGULATOR_SUBTYPE_LV300 = 0x02 ,
SPMI_REGULATOR_SUBTYPE_MV300 = 0x08 ,
SPMI_REGULATOR_SUBTYPE_MV500 = 0x09 ,
SPMI_REGULATOR_SUBTYPE_HDMI = 0x10 ,
SPMI_REGULATOR_SUBTYPE_OTG = 0x11 ,
SPMI_REGULATOR_SUBTYPE_5V_BOOST = 0x01 ,
SPMI_REGULATOR_SUBTYPE_FTS_CTL = 0x08 ,
SPMI_REGULATOR_SUBTYPE_FTS2p5_CTL = 0x09 ,
SPMI_REGULATOR_SUBTYPE_BB_2A = 0x01 ,
SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL1 = 0x0d ,
SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL2 = 0x0e ,
SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL3 = 0x0f ,
SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL4 = 0x10 ,
} ;
enum spmi_common_regulator_registers {
SPMI_COMMON_REG_DIG_MAJOR_REV = 0x01 ,
SPMI_COMMON_REG_TYPE = 0x04 ,
SPMI_COMMON_REG_SUBTYPE = 0x05 ,
SPMI_COMMON_REG_VOLTAGE_RANGE = 0x40 ,
SPMI_COMMON_REG_VOLTAGE_SET = 0x41 ,
SPMI_COMMON_REG_MODE = 0x45 ,
SPMI_COMMON_REG_ENABLE = 0x46 ,
SPMI_COMMON_REG_PULL_DOWN = 0x48 ,
SPMI_COMMON_REG_SOFT_START = 0x4c ,
SPMI_COMMON_REG_STEP_CTRL = 0x61 ,
} ;
enum spmi_vs_registers {
SPMI_VS_REG_OCP = 0x4a ,
SPMI_VS_REG_SOFT_START = 0x4c ,
} ;
enum spmi_boost_registers {
SPMI_BOOST_REG_CURRENT_LIMIT = 0x4a ,
} ;
enum spmi_boost_byp_registers {
SPMI_BOOST_BYP_REG_CURRENT_LIMIT = 0x4b ,
} ;
2018-05-21 14:25:30 +03:00
enum spmi_saw3_registers {
SAW3_SECURE = 0x00 ,
SAW3_ID = 0x04 ,
SAW3_SPM_STS = 0x0C ,
SAW3_AVS_STS = 0x10 ,
SAW3_PMIC_STS = 0x14 ,
SAW3_RST = 0x18 ,
SAW3_VCTL = 0x1C ,
SAW3_AVS_CTL = 0x20 ,
SAW3_AVS_LIMIT = 0x24 ,
SAW3_AVS_DLY = 0x28 ,
SAW3_AVS_HYSTERESIS = 0x2C ,
SAW3_SPM_STS2 = 0x38 ,
SAW3_SPM_PMIC_DATA_3 = 0x4C ,
SAW3_VERSION = 0xFD0 ,
} ;
2015-06-13 01:47:10 +03:00
/* Used for indexing into ctrl_reg. These are offets from 0x40 */
enum spmi_common_control_register_index {
SPMI_COMMON_IDX_VOLTAGE_RANGE = 0 ,
SPMI_COMMON_IDX_VOLTAGE_SET = 1 ,
SPMI_COMMON_IDX_MODE = 5 ,
SPMI_COMMON_IDX_ENABLE = 6 ,
} ;
/* Common regulator control register layout */
# define SPMI_COMMON_ENABLE_MASK 0x80
# define SPMI_COMMON_ENABLE 0x80
# define SPMI_COMMON_DISABLE 0x00
# define SPMI_COMMON_ENABLE_FOLLOW_HW_EN3_MASK 0x08
# define SPMI_COMMON_ENABLE_FOLLOW_HW_EN2_MASK 0x04
# define SPMI_COMMON_ENABLE_FOLLOW_HW_EN1_MASK 0x02
# define SPMI_COMMON_ENABLE_FOLLOW_HW_EN0_MASK 0x01
# define SPMI_COMMON_ENABLE_FOLLOW_ALL_MASK 0x0f
/* Common regulator mode register layout */
# define SPMI_COMMON_MODE_HPM_MASK 0x80
# define SPMI_COMMON_MODE_AUTO_MASK 0x40
# define SPMI_COMMON_MODE_BYPASS_MASK 0x20
# define SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK 0x10
# define SPMI_COMMON_MODE_FOLLOW_HW_EN3_MASK 0x08
# define SPMI_COMMON_MODE_FOLLOW_HW_EN2_MASK 0x04
# define SPMI_COMMON_MODE_FOLLOW_HW_EN1_MASK 0x02
# define SPMI_COMMON_MODE_FOLLOW_HW_EN0_MASK 0x01
# define SPMI_COMMON_MODE_FOLLOW_ALL_MASK 0x1f
/* Common regulator pull down control register layout */
# define SPMI_COMMON_PULL_DOWN_ENABLE_MASK 0x80
/* LDO regulator current limit control register layout */
# define SPMI_LDO_CURRENT_LIMIT_ENABLE_MASK 0x80
/* LDO regulator soft start control register layout */
# define SPMI_LDO_SOFT_START_ENABLE_MASK 0x80
/* VS regulator over current protection control register layout */
# define SPMI_VS_OCP_OVERRIDE 0x01
# define SPMI_VS_OCP_NO_OVERRIDE 0x00
/* VS regulator soft start control register layout */
# define SPMI_VS_SOFT_START_ENABLE_MASK 0x80
# define SPMI_VS_SOFT_START_SEL_MASK 0x03
/* Boost regulator current limit control register layout */
# define SPMI_BOOST_CURRENT_LIMIT_ENABLE_MASK 0x80
# define SPMI_BOOST_CURRENT_LIMIT_MASK 0x07
# define SPMI_VS_OCP_DEFAULT_MAX_RETRIES 10
# define SPMI_VS_OCP_DEFAULT_RETRY_DELAY_MS 30
# define SPMI_VS_OCP_FALL_DELAY_US 90
# define SPMI_VS_OCP_FAULT_DELAY_US 20000
# define SPMI_FTSMPS_STEP_CTRL_STEP_MASK 0x18
# define SPMI_FTSMPS_STEP_CTRL_STEP_SHIFT 3
# define SPMI_FTSMPS_STEP_CTRL_DELAY_MASK 0x07
# define SPMI_FTSMPS_STEP_CTRL_DELAY_SHIFT 0
/* Clock rate in kHz of the FTSMPS regulator reference clock. */
# define SPMI_FTSMPS_CLOCK_RATE 19200
/* Minimum voltage stepper delay for each step. */
# define SPMI_FTSMPS_STEP_DELAY 8
2016-03-31 04:57:49 +03:00
# define SPMI_DEFAULT_STEP_DELAY 20
2015-06-13 01:47:10 +03:00
/*
* The ratio SPMI_FTSMPS_STEP_MARGIN_NUM / SPMI_FTSMPS_STEP_MARGIN_DEN is used to
* adjust the step rate in order to account for oscillator variance .
*/
# define SPMI_FTSMPS_STEP_MARGIN_NUM 4
# define SPMI_FTSMPS_STEP_MARGIN_DEN 5
/* VSET value to decide the range of ULT SMPS */
# define ULT_SMPS_RANGE_SPLIT 0x60
/**
* struct spmi_voltage_range - regulator set point voltage mapping description
* @ min_uV : Minimum programmable output voltage resulting from
* set point register value 0x00
* @ max_uV : Maximum programmable output voltage
* @ step_uV : Output voltage increase resulting from the set point
* register value increasing by 1
* @ set_point_min_uV : Minimum allowed voltage
* @ set_point_max_uV : Maximum allowed voltage . This may be tweaked in order
* to pick which range should be used in the case of
* overlapping set points .
* @ n_voltages : Number of preferred voltage set points present in this
* range
* @ range_sel : Voltage range register value corresponding to this range
*
* The following relationships must be true for the values used in this struct :
* ( max_uV - min_uV ) % step_uV = = 0
* ( set_point_min_uV - min_uV ) % step_uV = = 0 *
* ( set_point_max_uV - min_uV ) % step_uV = = 0 *
* n_voltages = ( set_point_max_uV - set_point_min_uV ) / step_uV + 1
*
* * Note , set_point_min_uV = = set_point_max_uV = = 0 is allowed in order to
* specify that the voltage range has meaning , but is not preferred .
*/
struct spmi_voltage_range {
int min_uV ;
int max_uV ;
int step_uV ;
int set_point_min_uV ;
int set_point_max_uV ;
unsigned n_voltages ;
u8 range_sel ;
} ;
/*
* The ranges specified in the spmi_voltage_set_points struct must be listed
* so that range [ i ] . set_point_max_uV < range [ i + 1 ] . set_point_min_uV .
*/
struct spmi_voltage_set_points {
struct spmi_voltage_range * range ;
int count ;
unsigned n_voltages ;
} ;
struct spmi_regulator {
struct regulator_desc desc ;
struct device * dev ;
struct delayed_work ocp_work ;
struct regmap * regmap ;
struct spmi_voltage_set_points * set_points ;
enum spmi_regulator_logical_type logical_type ;
int ocp_irq ;
int ocp_count ;
int ocp_max_retries ;
int ocp_retry_delay_ms ;
int hpm_min_load ;
int slew_rate ;
ktime_t vs_enable_time ;
u16 base ;
struct list_head node ;
} ;
struct spmi_regulator_mapping {
enum spmi_regulator_type type ;
enum spmi_regulator_subtype subtype ;
enum spmi_regulator_logical_type logical_type ;
u32 revision_min ;
u32 revision_max ;
struct regulator_ops * ops ;
struct spmi_voltage_set_points * set_points ;
int hpm_min_load ;
} ;
struct spmi_regulator_data {
const char * name ;
u16 base ;
const char * supply ;
const char * ocp ;
u16 force_type ;
} ;
# define SPMI_VREG(_type, _subtype, _dig_major_min, _dig_major_max, \
_logical_type , _ops_val , _set_points_val , _hpm_min_load ) \
{ \
. type = SPMI_REGULATOR_TYPE_ # # _type , \
. subtype = SPMI_REGULATOR_SUBTYPE_ # # _subtype , \
. revision_min = _dig_major_min , \
. revision_max = _dig_major_max , \
. logical_type = SPMI_REGULATOR_LOGICAL_TYPE_ # # _logical_type , \
. ops = & spmi_ # # _ops_val # # _ops , \
. set_points = & _set_points_val # # _set_points , \
. hpm_min_load = _hpm_min_load , \
}
# define SPMI_VREG_VS(_subtype, _dig_major_min, _dig_major_max) \
{ \
. type = SPMI_REGULATOR_TYPE_VS , \
. subtype = SPMI_REGULATOR_SUBTYPE_ # # _subtype , \
. revision_min = _dig_major_min , \
. revision_max = _dig_major_max , \
. logical_type = SPMI_REGULATOR_LOGICAL_TYPE_VS , \
. ops = & spmi_vs_ops , \
}
# define SPMI_VOLTAGE_RANGE(_range_sel, _min_uV, _set_point_min_uV, \
_set_point_max_uV , _max_uV , _step_uV ) \
{ \
. min_uV = _min_uV , \
. max_uV = _max_uV , \
. set_point_min_uV = _set_point_min_uV , \
. set_point_max_uV = _set_point_max_uV , \
. step_uV = _step_uV , \
. range_sel = _range_sel , \
}
# define DEFINE_SPMI_SET_POINTS(name) \
struct spmi_voltage_set_points name # # _set_points = { \
. range = name # # _ranges , \
. count = ARRAY_SIZE ( name # # _ranges ) , \
}
/*
* These tables contain the physically available PMIC regulator voltage setpoint
* ranges . Where two ranges overlap in hardware , one of the ranges is trimmed
* to ensure that the setpoints available to software are monotonically
* increasing and unique . The set_voltage callback functions expect these
* properties to hold .
*/
static struct spmi_voltage_range pldo_ranges [ ] = {
SPMI_VOLTAGE_RANGE ( 2 , 750000 , 750000 , 1537500 , 1537500 , 12500 ) ,
SPMI_VOLTAGE_RANGE ( 3 , 1500000 , 1550000 , 3075000 , 3075000 , 25000 ) ,
SPMI_VOLTAGE_RANGE ( 4 , 1750000 , 3100000 , 4900000 , 4900000 , 50000 ) ,
} ;
static struct spmi_voltage_range nldo1_ranges [ ] = {
SPMI_VOLTAGE_RANGE ( 2 , 750000 , 750000 , 1537500 , 1537500 , 12500 ) ,
} ;
static struct spmi_voltage_range nldo2_ranges [ ] = {
SPMI_VOLTAGE_RANGE ( 0 , 375000 , 0 , 0 , 1537500 , 12500 ) ,
SPMI_VOLTAGE_RANGE ( 1 , 375000 , 375000 , 768750 , 768750 , 6250 ) ,
SPMI_VOLTAGE_RANGE ( 2 , 750000 , 775000 , 1537500 , 1537500 , 12500 ) ,
} ;
static struct spmi_voltage_range nldo3_ranges [ ] = {
SPMI_VOLTAGE_RANGE ( 0 , 375000 , 375000 , 1537500 , 1537500 , 12500 ) ,
SPMI_VOLTAGE_RANGE ( 1 , 375000 , 0 , 0 , 1537500 , 12500 ) ,
SPMI_VOLTAGE_RANGE ( 2 , 750000 , 0 , 0 , 1537500 , 12500 ) ,
} ;
static struct spmi_voltage_range ln_ldo_ranges [ ] = {
SPMI_VOLTAGE_RANGE ( 1 , 690000 , 690000 , 1110000 , 1110000 , 60000 ) ,
SPMI_VOLTAGE_RANGE ( 0 , 1380000 , 1380000 , 2220000 , 2220000 , 120000 ) ,
} ;
static struct spmi_voltage_range smps_ranges [ ] = {
SPMI_VOLTAGE_RANGE ( 0 , 375000 , 375000 , 1562500 , 1562500 , 12500 ) ,
SPMI_VOLTAGE_RANGE ( 1 , 1550000 , 1575000 , 3125000 , 3125000 , 25000 ) ,
} ;
static struct spmi_voltage_range ftsmps_ranges [ ] = {
SPMI_VOLTAGE_RANGE ( 0 , 0 , 350000 , 1275000 , 1275000 , 5000 ) ,
SPMI_VOLTAGE_RANGE ( 1 , 0 , 1280000 , 2040000 , 2040000 , 10000 ) ,
} ;
static struct spmi_voltage_range ftsmps2p5_ranges [ ] = {
SPMI_VOLTAGE_RANGE ( 0 , 80000 , 350000 , 1355000 , 1355000 , 5000 ) ,
SPMI_VOLTAGE_RANGE ( 1 , 160000 , 1360000 , 2200000 , 2200000 , 10000 ) ,
} ;
static struct spmi_voltage_range boost_ranges [ ] = {
SPMI_VOLTAGE_RANGE ( 0 , 4000000 , 4000000 , 5550000 , 5550000 , 50000 ) ,
} ;
static struct spmi_voltage_range boost_byp_ranges [ ] = {
SPMI_VOLTAGE_RANGE ( 0 , 2500000 , 2500000 , 5200000 , 5650000 , 50000 ) ,
} ;
static struct spmi_voltage_range ult_lo_smps_ranges [ ] = {
SPMI_VOLTAGE_RANGE ( 0 , 375000 , 375000 , 1562500 , 1562500 , 12500 ) ,
SPMI_VOLTAGE_RANGE ( 1 , 750000 , 0 , 0 , 1525000 , 25000 ) ,
} ;
static struct spmi_voltage_range ult_ho_smps_ranges [ ] = {
SPMI_VOLTAGE_RANGE ( 0 , 1550000 , 1550000 , 2325000 , 2325000 , 25000 ) ,
} ;
static struct spmi_voltage_range ult_nldo_ranges [ ] = {
SPMI_VOLTAGE_RANGE ( 0 , 375000 , 375000 , 1537500 , 1537500 , 12500 ) ,
} ;
static struct spmi_voltage_range ult_pldo_ranges [ ] = {
SPMI_VOLTAGE_RANGE ( 0 , 1750000 , 1750000 , 3337500 , 3337500 , 12500 ) ,
} ;
static DEFINE_SPMI_SET_POINTS ( pldo ) ;
static DEFINE_SPMI_SET_POINTS ( nldo1 ) ;
static DEFINE_SPMI_SET_POINTS ( nldo2 ) ;
static DEFINE_SPMI_SET_POINTS ( nldo3 ) ;
static DEFINE_SPMI_SET_POINTS ( ln_ldo ) ;
static DEFINE_SPMI_SET_POINTS ( smps ) ;
static DEFINE_SPMI_SET_POINTS ( ftsmps ) ;
static DEFINE_SPMI_SET_POINTS ( ftsmps2p5 ) ;
static DEFINE_SPMI_SET_POINTS ( boost ) ;
static DEFINE_SPMI_SET_POINTS ( boost_byp ) ;
static DEFINE_SPMI_SET_POINTS ( ult_lo_smps ) ;
static DEFINE_SPMI_SET_POINTS ( ult_ho_smps ) ;
static DEFINE_SPMI_SET_POINTS ( ult_nldo ) ;
static DEFINE_SPMI_SET_POINTS ( ult_pldo ) ;
static inline int spmi_vreg_read ( struct spmi_regulator * vreg , u16 addr , u8 * buf ,
int len )
{
return regmap_bulk_read ( vreg - > regmap , vreg - > base + addr , buf , len ) ;
}
static inline int spmi_vreg_write ( struct spmi_regulator * vreg , u16 addr ,
u8 * buf , int len )
{
return regmap_bulk_write ( vreg - > regmap , vreg - > base + addr , buf , len ) ;
}
static int spmi_vreg_update_bits ( struct spmi_regulator * vreg , u16 addr , u8 val ,
u8 mask )
{
return regmap_update_bits ( vreg - > regmap , vreg - > base + addr , mask , val ) ;
}
static int spmi_regulator_vs_enable ( struct regulator_dev * rdev )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
if ( vreg - > ocp_irq ) {
vreg - > ocp_count = 0 ;
vreg - > vs_enable_time = ktime_get ( ) ;
}
2017-11-29 17:02:46 +03:00
return regulator_enable_regmap ( rdev ) ;
2015-06-13 01:47:10 +03:00
}
2015-07-18 00:41:55 +03:00
static int spmi_regulator_vs_ocp ( struct regulator_dev * rdev )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
u8 reg = SPMI_VS_OCP_OVERRIDE ;
return spmi_vreg_write ( vreg , SPMI_VS_REG_OCP , & reg , 1 ) ;
}
2015-06-13 01:47:10 +03:00
static int spmi_regulator_select_voltage ( struct spmi_regulator * vreg ,
2016-03-31 04:57:50 +03:00
int min_uV , int max_uV )
2015-06-13 01:47:10 +03:00
{
const struct spmi_voltage_range * range ;
int uV = min_uV ;
int lim_min_uV , lim_max_uV , i , range_id , range_max_uV ;
2016-03-31 04:57:50 +03:00
int selector , voltage_sel ;
2015-06-13 01:47:10 +03:00
/* Check if request voltage is outside of physically settable range. */
lim_min_uV = vreg - > set_points - > range [ 0 ] . set_point_min_uV ;
lim_max_uV =
vreg - > set_points - > range [ vreg - > set_points - > count - 1 ] . set_point_max_uV ;
if ( uV < lim_min_uV & & max_uV > = lim_min_uV )
uV = lim_min_uV ;
if ( uV < lim_min_uV | | uV > lim_max_uV ) {
dev_err ( vreg - > dev ,
" request v=[%d, %d] is outside possible v=[%d, %d] \n " ,
min_uV , max_uV , lim_min_uV , lim_max_uV ) ;
return - EINVAL ;
}
/* Find the range which uV is inside of. */
for ( i = vreg - > set_points - > count - 1 ; i > 0 ; i - - ) {
range_max_uV = vreg - > set_points - > range [ i - 1 ] . set_point_max_uV ;
if ( uV > range_max_uV & & range_max_uV > 0 )
break ;
}
range_id = i ;
range = & vreg - > set_points - > range [ range_id ] ;
/*
* Force uV to be an allowed set point by applying a ceiling function to
* the uV value .
*/
2016-03-31 04:57:50 +03:00
voltage_sel = DIV_ROUND_UP ( uV - range - > min_uV , range - > step_uV ) ;
uV = voltage_sel * range - > step_uV + range - > min_uV ;
2015-06-13 01:47:10 +03:00
if ( uV > max_uV ) {
dev_err ( vreg - > dev ,
" request v=[%d, %d] cannot be met by any set point; "
" next set point: %d \n " ,
min_uV , max_uV , uV ) ;
return - EINVAL ;
}
2016-03-31 04:57:50 +03:00
selector = 0 ;
2015-06-13 01:47:10 +03:00
for ( i = 0 ; i < range_id ; i + + )
2016-03-31 04:57:50 +03:00
selector + = vreg - > set_points - > range [ i ] . n_voltages ;
selector + = ( uV - range - > set_point_min_uV ) / range - > step_uV ;
2015-06-13 01:47:10 +03:00
2016-03-31 04:57:50 +03:00
return selector ;
}
static int spmi_sw_selector_to_hw ( struct spmi_regulator * vreg ,
unsigned selector , u8 * range_sel ,
u8 * voltage_sel )
{
const struct spmi_voltage_range * range , * end ;
2017-11-02 08:06:19 +03:00
unsigned offset ;
2016-03-31 04:57:50 +03:00
range = vreg - > set_points - > range ;
end = range + vreg - > set_points - > count ;
for ( ; range < end ; range + + ) {
if ( selector < range - > n_voltages ) {
2017-11-02 08:06:19 +03:00
/*
* hardware selectors between set point min and real
* min are invalid so we ignore them
*/
offset = range - > set_point_min_uV - range - > min_uV ;
offset / = range - > step_uV ;
* voltage_sel = selector + offset ;
2016-03-31 04:57:50 +03:00
* range_sel = range - > range_sel ;
return 0 ;
}
selector - = range - > n_voltages ;
}
return - EINVAL ;
}
static int spmi_hw_selector_to_sw ( struct spmi_regulator * vreg , u8 hw_sel ,
const struct spmi_voltage_range * range )
{
2017-11-02 08:06:19 +03:00
unsigned sw_sel = 0 ;
unsigned offset , max_hw_sel ;
2016-03-31 04:57:50 +03:00
const struct spmi_voltage_range * r = vreg - > set_points - > range ;
2017-11-02 08:06:19 +03:00
const struct spmi_voltage_range * end = r + vreg - > set_points - > count ;
for ( ; r < end ; r + + ) {
if ( r = = range & & range - > n_voltages ) {
/*
* hardware selectors between set point min and real
* min and between set point max and real max are
* invalid so we return an error if they ' re
* programmed into the hardware
*/
offset = range - > set_point_min_uV - range - > min_uV ;
offset / = range - > step_uV ;
if ( hw_sel < offset )
return - EINVAL ;
max_hw_sel = range - > set_point_max_uV - range - > min_uV ;
max_hw_sel / = range - > step_uV ;
if ( hw_sel > max_hw_sel )
return - EINVAL ;
return sw_sel + hw_sel - offset ;
}
2016-03-31 04:57:50 +03:00
sw_sel + = r - > n_voltages ;
}
2017-11-02 08:06:19 +03:00
return - EINVAL ;
2015-06-13 01:47:10 +03:00
}
static const struct spmi_voltage_range *
spmi_regulator_find_range ( struct spmi_regulator * vreg )
{
u8 range_sel ;
const struct spmi_voltage_range * range , * end ;
range = vreg - > set_points - > range ;
end = range + vreg - > set_points - > count ;
spmi_vreg_read ( vreg , SPMI_COMMON_REG_VOLTAGE_RANGE , & range_sel , 1 ) ;
for ( ; range < end ; range + + )
if ( range - > range_sel = = range_sel )
return range ;
return NULL ;
}
static int spmi_regulator_select_voltage_same_range ( struct spmi_regulator * vreg ,
2016-03-31 04:57:50 +03:00
int min_uV , int max_uV )
2015-06-13 01:47:10 +03:00
{
const struct spmi_voltage_range * range ;
int uV = min_uV ;
2016-03-31 04:57:50 +03:00
int i , selector ;
2015-06-13 01:47:10 +03:00
range = spmi_regulator_find_range ( vreg ) ;
if ( ! range )
goto different_range ;
if ( uV < range - > min_uV & & max_uV > = range - > min_uV )
uV = range - > min_uV ;
if ( uV < range - > min_uV | | uV > range - > max_uV ) {
/* Current range doesn't support the requested voltage. */
goto different_range ;
}
/*
* Force uV to be an allowed set point by applying a ceiling function to
* the uV value .
*/
2016-03-31 04:57:50 +03:00
uV = DIV_ROUND_UP ( uV - range - > min_uV , range - > step_uV ) ;
uV = uV * range - > step_uV + range - > min_uV ;
2015-06-13 01:47:10 +03:00
if ( uV > max_uV ) {
/*
* No set point in the current voltage range is within the
* requested min_uV to max_uV range .
*/
goto different_range ;
}
2016-03-31 04:57:50 +03:00
selector = 0 ;
2015-06-13 01:47:10 +03:00
for ( i = 0 ; i < vreg - > set_points - > count ; i + + ) {
if ( uV > = vreg - > set_points - > range [ i ] . set_point_min_uV
2015-06-16 21:11:22 +03:00
& & uV < = vreg - > set_points - > range [ i ] . set_point_max_uV ) {
2016-03-31 04:57:50 +03:00
selector + =
2015-06-13 01:47:10 +03:00
( uV - vreg - > set_points - > range [ i ] . set_point_min_uV )
/ vreg - > set_points - > range [ i ] . step_uV ;
break ;
2015-06-16 21:11:22 +03:00
}
2015-06-13 01:47:10 +03:00
2016-03-31 04:57:50 +03:00
selector + = vreg - > set_points - > range [ i ] . n_voltages ;
2015-06-13 01:47:10 +03:00
}
2016-03-31 04:57:50 +03:00
if ( selector > = vreg - > set_points - > n_voltages )
2015-06-13 01:47:10 +03:00
goto different_range ;
2016-04-15 20:44:37 +03:00
return selector ;
2015-06-13 01:47:10 +03:00
different_range :
2016-03-31 04:57:50 +03:00
return spmi_regulator_select_voltage ( vreg , min_uV , max_uV ) ;
2015-06-13 01:47:10 +03:00
}
2016-03-31 04:57:50 +03:00
static int spmi_regulator_common_map_voltage ( struct regulator_dev * rdev ,
int min_uV , int max_uV )
2015-06-13 01:47:10 +03:00
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
/*
* Favor staying in the current voltage range if possible . This avoids
* voltage spikes that occur when changing the voltage range .
*/
2016-03-31 04:57:50 +03:00
return spmi_regulator_select_voltage_same_range ( vreg , min_uV , max_uV ) ;
}
static int
spmi_regulator_common_set_voltage ( struct regulator_dev * rdev , unsigned selector )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
int ret ;
u8 buf [ 2 ] ;
u8 range_sel , voltage_sel ;
ret = spmi_sw_selector_to_hw ( vreg , selector , & range_sel , & voltage_sel ) ;
2015-06-13 01:47:10 +03:00
if ( ret )
return ret ;
buf [ 0 ] = range_sel ;
buf [ 1 ] = voltage_sel ;
return spmi_vreg_write ( vreg , SPMI_COMMON_REG_VOLTAGE_RANGE , buf , 2 ) ;
}
static int spmi_regulator_set_voltage_time_sel ( struct regulator_dev * rdev ,
unsigned int old_selector , unsigned int new_selector )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
const struct spmi_voltage_range * range ;
int diff_uV ;
range = spmi_regulator_find_range ( vreg ) ;
if ( ! range )
return - EINVAL ;
diff_uV = abs ( new_selector - old_selector ) * range - > step_uV ;
return DIV_ROUND_UP ( diff_uV , vreg - > slew_rate ) ;
}
static int spmi_regulator_common_get_voltage ( struct regulator_dev * rdev )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
const struct spmi_voltage_range * range ;
u8 voltage_sel ;
spmi_vreg_read ( vreg , SPMI_COMMON_REG_VOLTAGE_SET , & voltage_sel , 1 ) ;
range = spmi_regulator_find_range ( vreg ) ;
if ( ! range )
2016-03-31 04:57:50 +03:00
return - EINVAL ;
2015-06-13 01:47:10 +03:00
2016-03-31 04:57:50 +03:00
return spmi_hw_selector_to_sw ( vreg , voltage_sel , range ) ;
2015-06-13 01:47:10 +03:00
}
2016-03-31 04:57:50 +03:00
static int spmi_regulator_single_map_voltage ( struct regulator_dev * rdev ,
int min_uV , int max_uV )
2015-06-13 01:47:10 +03:00
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
2016-03-31 04:57:50 +03:00
return spmi_regulator_select_voltage ( vreg , min_uV , max_uV ) ;
}
static int spmi_regulator_single_range_set_voltage ( struct regulator_dev * rdev ,
unsigned selector )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
u8 sel = selector ;
2015-06-13 01:47:10 +03:00
/*
* Certain types of regulators do not have a range select register so
* only voltage set register needs to be written .
*/
return spmi_vreg_write ( vreg , SPMI_COMMON_REG_VOLTAGE_SET , & sel , 1 ) ;
}
static int spmi_regulator_single_range_get_voltage ( struct regulator_dev * rdev )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
2016-03-31 04:57:50 +03:00
u8 selector ;
int ret ;
2015-06-13 01:47:10 +03:00
2016-03-31 04:57:50 +03:00
ret = spmi_vreg_read ( vreg , SPMI_COMMON_REG_VOLTAGE_SET , & selector , 1 ) ;
if ( ret )
return ret ;
2015-06-13 01:47:10 +03:00
2016-03-31 04:57:50 +03:00
return selector ;
2015-06-13 01:47:10 +03:00
}
static int spmi_regulator_ult_lo_smps_set_voltage ( struct regulator_dev * rdev ,
2016-03-31 04:57:50 +03:00
unsigned selector )
2015-06-13 01:47:10 +03:00
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
int ret ;
u8 range_sel , voltage_sel ;
2016-03-31 04:57:50 +03:00
ret = spmi_sw_selector_to_hw ( vreg , selector , & range_sel , & voltage_sel ) ;
2015-06-13 01:47:10 +03:00
if ( ret )
return ret ;
/*
* Calculate VSET based on range
* In case of range 0 : voltage_sel is a 7 bit value , can be written
* witout any modification .
* In case of range 1 : voltage_sel is a 5 bit value , bits [ 7 - 5 ] set to
* [ 011 ] .
*/
if ( range_sel = = 1 )
voltage_sel | = ULT_SMPS_RANGE_SPLIT ;
2015-06-16 16:45:14 +03:00
return spmi_vreg_update_bits ( vreg , SPMI_COMMON_REG_VOLTAGE_SET ,
2016-03-31 04:57:50 +03:00
voltage_sel , 0xff ) ;
2015-06-13 01:47:10 +03:00
}
static int spmi_regulator_ult_lo_smps_get_voltage ( struct regulator_dev * rdev )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
const struct spmi_voltage_range * range ;
u8 voltage_sel ;
spmi_vreg_read ( vreg , SPMI_COMMON_REG_VOLTAGE_SET , & voltage_sel , 1 ) ;
range = spmi_regulator_find_range ( vreg ) ;
if ( ! range )
2016-03-31 04:57:50 +03:00
return - EINVAL ;
2015-06-13 01:47:10 +03:00
if ( range - > range_sel = = 1 )
voltage_sel & = ~ ULT_SMPS_RANGE_SPLIT ;
2016-03-31 04:57:50 +03:00
return spmi_hw_selector_to_sw ( vreg , voltage_sel , range ) ;
2015-06-13 01:47:10 +03:00
}
static int spmi_regulator_common_list_voltage ( struct regulator_dev * rdev ,
unsigned selector )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
int uV = 0 ;
int i ;
if ( selector > = vreg - > set_points - > n_voltages )
return 0 ;
for ( i = 0 ; i < vreg - > set_points - > count ; i + + ) {
2015-06-16 21:11:22 +03:00
if ( selector < vreg - > set_points - > range [ i ] . n_voltages ) {
2015-06-13 01:47:10 +03:00
uV = selector * vreg - > set_points - > range [ i ] . step_uV
+ vreg - > set_points - > range [ i ] . set_point_min_uV ;
break ;
2015-06-16 21:11:22 +03:00
}
2015-06-13 01:47:10 +03:00
selector - = vreg - > set_points - > range [ i ] . n_voltages ;
}
return uV ;
}
static int
spmi_regulator_common_set_bypass ( struct regulator_dev * rdev , bool enable )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
u8 mask = SPMI_COMMON_MODE_BYPASS_MASK ;
u8 val = 0 ;
if ( enable )
val = mask ;
return spmi_vreg_update_bits ( vreg , SPMI_COMMON_REG_MODE , val , mask ) ;
}
static int
spmi_regulator_common_get_bypass ( struct regulator_dev * rdev , bool * enable )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
u8 val ;
int ret ;
ret = spmi_vreg_read ( vreg , SPMI_COMMON_REG_MODE , & val , 1 ) ;
* enable = val & SPMI_COMMON_MODE_BYPASS_MASK ;
return ret ;
}
static unsigned int spmi_regulator_common_get_mode ( struct regulator_dev * rdev )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
u8 reg ;
spmi_vreg_read ( vreg , SPMI_COMMON_REG_MODE , & reg , 1 ) ;
if ( reg & SPMI_COMMON_MODE_HPM_MASK )
return REGULATOR_MODE_NORMAL ;
2015-07-18 00:41:55 +03:00
if ( reg & SPMI_COMMON_MODE_AUTO_MASK )
return REGULATOR_MODE_FAST ;
2015-06-13 01:47:10 +03:00
return REGULATOR_MODE_IDLE ;
}
static int
spmi_regulator_common_set_mode ( struct regulator_dev * rdev , unsigned int mode )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
2015-07-18 00:41:55 +03:00
u8 mask = SPMI_COMMON_MODE_HPM_MASK | SPMI_COMMON_MODE_AUTO_MASK ;
2015-06-13 01:47:10 +03:00
u8 val = 0 ;
if ( mode = = REGULATOR_MODE_NORMAL )
2015-07-18 00:41:55 +03:00
val = SPMI_COMMON_MODE_HPM_MASK ;
else if ( mode = = REGULATOR_MODE_FAST )
val = SPMI_COMMON_MODE_AUTO_MASK ;
2015-06-13 01:47:10 +03:00
return spmi_vreg_update_bits ( vreg , SPMI_COMMON_REG_MODE , val , mask ) ;
}
static int
spmi_regulator_common_set_load ( struct regulator_dev * rdev , int load_uA )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
unsigned int mode ;
if ( load_uA > = vreg - > hpm_min_load )
mode = REGULATOR_MODE_NORMAL ;
else
mode = REGULATOR_MODE_IDLE ;
return spmi_regulator_common_set_mode ( rdev , mode ) ;
}
static int spmi_regulator_common_set_pull_down ( struct regulator_dev * rdev )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
unsigned int mask = SPMI_COMMON_PULL_DOWN_ENABLE_MASK ;
return spmi_vreg_update_bits ( vreg , SPMI_COMMON_REG_PULL_DOWN ,
mask , mask ) ;
}
static int spmi_regulator_common_set_soft_start ( struct regulator_dev * rdev )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
unsigned int mask = SPMI_LDO_SOFT_START_ENABLE_MASK ;
return spmi_vreg_update_bits ( vreg , SPMI_COMMON_REG_SOFT_START ,
mask , mask ) ;
}
static int spmi_regulator_set_ilim ( struct regulator_dev * rdev , int ilim_uA )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
enum spmi_regulator_logical_type type = vreg - > logical_type ;
unsigned int current_reg ;
u8 reg ;
u8 mask = SPMI_BOOST_CURRENT_LIMIT_MASK |
SPMI_BOOST_CURRENT_LIMIT_ENABLE_MASK ;
int max = ( SPMI_BOOST_CURRENT_LIMIT_MASK + 1 ) * 500 ;
if ( type = = SPMI_REGULATOR_LOGICAL_TYPE_BOOST )
current_reg = SPMI_BOOST_REG_CURRENT_LIMIT ;
else
current_reg = SPMI_BOOST_BYP_REG_CURRENT_LIMIT ;
if ( ilim_uA > max | | ilim_uA < = 0 )
return - EINVAL ;
reg = ( ilim_uA - 1 ) / 500 ;
reg | = SPMI_BOOST_CURRENT_LIMIT_ENABLE_MASK ;
return spmi_vreg_update_bits ( vreg , current_reg , reg , mask ) ;
}
static int spmi_regulator_vs_clear_ocp ( struct spmi_regulator * vreg )
{
int ret ;
ret = spmi_vreg_update_bits ( vreg , SPMI_COMMON_REG_ENABLE ,
SPMI_COMMON_DISABLE , SPMI_COMMON_ENABLE_MASK ) ;
vreg - > vs_enable_time = ktime_get ( ) ;
ret = spmi_vreg_update_bits ( vreg , SPMI_COMMON_REG_ENABLE ,
SPMI_COMMON_ENABLE , SPMI_COMMON_ENABLE_MASK ) ;
return ret ;
}
static void spmi_regulator_vs_ocp_work ( struct work_struct * work )
{
struct delayed_work * dwork = to_delayed_work ( work ) ;
struct spmi_regulator * vreg
= container_of ( dwork , struct spmi_regulator , ocp_work ) ;
spmi_regulator_vs_clear_ocp ( vreg ) ;
}
static irqreturn_t spmi_regulator_vs_ocp_isr ( int irq , void * data )
{
struct spmi_regulator * vreg = data ;
ktime_t ocp_irq_time ;
s64 ocp_trigger_delay_us ;
ocp_irq_time = ktime_get ( ) ;
ocp_trigger_delay_us = ktime_us_delta ( ocp_irq_time ,
vreg - > vs_enable_time ) ;
/*
* Reset the OCP count if there is a large delay between switch enable
* and when OCP triggers . This is indicative of a hotplug event as
* opposed to a fault .
*/
if ( ocp_trigger_delay_us > SPMI_VS_OCP_FAULT_DELAY_US )
vreg - > ocp_count = 0 ;
/* Wait for switch output to settle back to 0 V after OCP triggered. */
udelay ( SPMI_VS_OCP_FALL_DELAY_US ) ;
vreg - > ocp_count + + ;
if ( vreg - > ocp_count = = 1 ) {
/* Immediately clear the over current condition. */
spmi_regulator_vs_clear_ocp ( vreg ) ;
} else if ( vreg - > ocp_count < = vreg - > ocp_max_retries ) {
/* Schedule the over current clear task to run later. */
schedule_delayed_work ( & vreg - > ocp_work ,
msecs_to_jiffies ( vreg - > ocp_retry_delay_ms ) + 1 ) ;
} else {
dev_err ( vreg - > dev ,
" OCP triggered %d times; no further retries \n " ,
vreg - > ocp_count ) ;
}
return IRQ_HANDLED ;
}
2018-05-21 14:25:30 +03:00
# define SAW3_VCTL_DATA_MASK 0xFF
# define SAW3_VCTL_CLEAR_MASK 0x700FF
# define SAW3_AVS_CTL_EN_MASK 0x1
# define SAW3_AVS_CTL_TGGL_MASK 0x8000000
# define SAW3_AVS_CTL_CLEAR_MASK 0x7efc00
static struct regmap * saw_regmap = NULL ;
static void spmi_saw_set_vdd ( void * data )
{
u32 vctl , data3 , avs_ctl , pmic_sts ;
bool avs_enabled = false ;
unsigned long timeout ;
u8 voltage_sel = * ( u8 * ) data ;
regmap_read ( saw_regmap , SAW3_AVS_CTL , & avs_ctl ) ;
regmap_read ( saw_regmap , SAW3_VCTL , & vctl ) ;
regmap_read ( saw_regmap , SAW3_SPM_PMIC_DATA_3 , & data3 ) ;
/* select the band */
vctl & = ~ SAW3_VCTL_CLEAR_MASK ;
vctl | = ( u32 ) voltage_sel ;
data3 & = ~ SAW3_VCTL_CLEAR_MASK ;
data3 | = ( u32 ) voltage_sel ;
/* If AVS is enabled, switch it off during the voltage change */
avs_enabled = SAW3_AVS_CTL_EN_MASK & avs_ctl ;
if ( avs_enabled ) {
avs_ctl & = ~ SAW3_AVS_CTL_TGGL_MASK ;
regmap_write ( saw_regmap , SAW3_AVS_CTL , avs_ctl ) ;
}
regmap_write ( saw_regmap , SAW3_RST , 1 ) ;
regmap_write ( saw_regmap , SAW3_VCTL , vctl ) ;
regmap_write ( saw_regmap , SAW3_SPM_PMIC_DATA_3 , data3 ) ;
timeout = jiffies + usecs_to_jiffies ( 100 ) ;
do {
regmap_read ( saw_regmap , SAW3_PMIC_STS , & pmic_sts ) ;
pmic_sts & = SAW3_VCTL_DATA_MASK ;
if ( pmic_sts = = ( u32 ) voltage_sel )
break ;
cpu_relax ( ) ;
} while ( time_before ( jiffies , timeout ) ) ;
/* After successful voltage change, switch the AVS back on */
if ( avs_enabled ) {
pmic_sts & = 0x3f ;
avs_ctl & = ~ SAW3_AVS_CTL_CLEAR_MASK ;
avs_ctl | = ( ( pmic_sts - 4 ) < < 10 ) ;
avs_ctl | = ( pmic_sts < < 17 ) ;
avs_ctl | = SAW3_AVS_CTL_TGGL_MASK ;
regmap_write ( saw_regmap , SAW3_AVS_CTL , avs_ctl ) ;
}
}
static int
spmi_regulator_saw_set_voltage ( struct regulator_dev * rdev , unsigned selector )
{
struct spmi_regulator * vreg = rdev_get_drvdata ( rdev ) ;
int ret ;
u8 range_sel , voltage_sel ;
ret = spmi_sw_selector_to_hw ( vreg , selector , & range_sel , & voltage_sel ) ;
if ( ret )
return ret ;
if ( 0 ! = range_sel ) {
dev_dbg ( & rdev - > dev , " range_sel = %02X voltage_sel = %02X " , \
range_sel , voltage_sel ) ;
return - EINVAL ;
}
/* Always do the SAW register writes on the first CPU */
return smp_call_function_single ( 0 , spmi_saw_set_vdd , \
& voltage_sel , true ) ;
}
static struct regulator_ops spmi_saw_ops = { } ;
2015-06-13 01:47:10 +03:00
static struct regulator_ops spmi_smps_ops = {
2017-11-29 17:02:46 +03:00
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
2016-03-31 04:57:50 +03:00
. set_voltage_sel = spmi_regulator_common_set_voltage ,
2016-03-31 04:57:49 +03:00
. set_voltage_time_sel = spmi_regulator_set_voltage_time_sel ,
2016-03-31 04:57:50 +03:00
. get_voltage_sel = spmi_regulator_common_get_voltage ,
. map_voltage = spmi_regulator_common_map_voltage ,
2015-06-13 01:47:10 +03:00
. list_voltage = spmi_regulator_common_list_voltage ,
. set_mode = spmi_regulator_common_set_mode ,
. get_mode = spmi_regulator_common_get_mode ,
. set_load = spmi_regulator_common_set_load ,
. set_pull_down = spmi_regulator_common_set_pull_down ,
} ;
static struct regulator_ops spmi_ldo_ops = {
2017-11-29 17:02:46 +03:00
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
2016-03-31 04:57:50 +03:00
. set_voltage_sel = spmi_regulator_common_set_voltage ,
. get_voltage_sel = spmi_regulator_common_get_voltage ,
. map_voltage = spmi_regulator_common_map_voltage ,
2015-06-13 01:47:10 +03:00
. list_voltage = spmi_regulator_common_list_voltage ,
. set_mode = spmi_regulator_common_set_mode ,
. get_mode = spmi_regulator_common_get_mode ,
. set_load = spmi_regulator_common_set_load ,
. set_bypass = spmi_regulator_common_set_bypass ,
. get_bypass = spmi_regulator_common_get_bypass ,
. set_pull_down = spmi_regulator_common_set_pull_down ,
. set_soft_start = spmi_regulator_common_set_soft_start ,
} ;
static struct regulator_ops spmi_ln_ldo_ops = {
2017-11-29 17:02:46 +03:00
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
2016-03-31 04:57:50 +03:00
. set_voltage_sel = spmi_regulator_common_set_voltage ,
. get_voltage_sel = spmi_regulator_common_get_voltage ,
. map_voltage = spmi_regulator_common_map_voltage ,
2015-06-13 01:47:10 +03:00
. list_voltage = spmi_regulator_common_list_voltage ,
. set_bypass = spmi_regulator_common_set_bypass ,
. get_bypass = spmi_regulator_common_get_bypass ,
} ;
static struct regulator_ops spmi_vs_ops = {
. enable = spmi_regulator_vs_enable ,
2017-11-29 17:02:46 +03:00
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
2015-06-13 01:47:10 +03:00
. set_pull_down = spmi_regulator_common_set_pull_down ,
. set_soft_start = spmi_regulator_common_set_soft_start ,
2015-07-18 00:41:55 +03:00
. set_over_current_protection = spmi_regulator_vs_ocp ,
2016-06-26 08:52:13 +03:00
. set_mode = spmi_regulator_common_set_mode ,
. get_mode = spmi_regulator_common_get_mode ,
2015-06-13 01:47:10 +03:00
} ;
static struct regulator_ops spmi_boost_ops = {
2017-11-29 17:02:46 +03:00
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
2016-03-31 04:57:50 +03:00
. set_voltage_sel = spmi_regulator_single_range_set_voltage ,
. get_voltage_sel = spmi_regulator_single_range_get_voltage ,
. map_voltage = spmi_regulator_single_map_voltage ,
2015-06-13 01:47:10 +03:00
. list_voltage = spmi_regulator_common_list_voltage ,
. set_input_current_limit = spmi_regulator_set_ilim ,
} ;
static struct regulator_ops spmi_ftsmps_ops = {
2017-11-29 17:02:46 +03:00
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
2016-03-31 04:57:50 +03:00
. set_voltage_sel = spmi_regulator_common_set_voltage ,
2015-06-13 01:47:10 +03:00
. set_voltage_time_sel = spmi_regulator_set_voltage_time_sel ,
2016-03-31 04:57:50 +03:00
. get_voltage_sel = spmi_regulator_common_get_voltage ,
. map_voltage = spmi_regulator_common_map_voltage ,
2015-06-13 01:47:10 +03:00
. list_voltage = spmi_regulator_common_list_voltage ,
. set_mode = spmi_regulator_common_set_mode ,
. get_mode = spmi_regulator_common_get_mode ,
. set_load = spmi_regulator_common_set_load ,
. set_pull_down = spmi_regulator_common_set_pull_down ,
} ;
static struct regulator_ops spmi_ult_lo_smps_ops = {
2017-11-29 17:02:46 +03:00
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
2016-03-31 04:57:50 +03:00
. set_voltage_sel = spmi_regulator_ult_lo_smps_set_voltage ,
2016-03-31 04:57:49 +03:00
. set_voltage_time_sel = spmi_regulator_set_voltage_time_sel ,
2016-03-31 04:57:50 +03:00
. get_voltage_sel = spmi_regulator_ult_lo_smps_get_voltage ,
2015-06-13 01:47:10 +03:00
. list_voltage = spmi_regulator_common_list_voltage ,
. set_mode = spmi_regulator_common_set_mode ,
. get_mode = spmi_regulator_common_get_mode ,
. set_load = spmi_regulator_common_set_load ,
. set_pull_down = spmi_regulator_common_set_pull_down ,
} ;
static struct regulator_ops spmi_ult_ho_smps_ops = {
2017-11-29 17:02:46 +03:00
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
2016-03-31 04:57:50 +03:00
. set_voltage_sel = spmi_regulator_single_range_set_voltage ,
2016-03-31 04:57:49 +03:00
. set_voltage_time_sel = spmi_regulator_set_voltage_time_sel ,
2016-03-31 04:57:50 +03:00
. get_voltage_sel = spmi_regulator_single_range_get_voltage ,
. map_voltage = spmi_regulator_single_map_voltage ,
2015-06-13 01:47:10 +03:00
. list_voltage = spmi_regulator_common_list_voltage ,
. set_mode = spmi_regulator_common_set_mode ,
. get_mode = spmi_regulator_common_get_mode ,
. set_load = spmi_regulator_common_set_load ,
. set_pull_down = spmi_regulator_common_set_pull_down ,
} ;
static struct regulator_ops spmi_ult_ldo_ops = {
2017-11-29 17:02:46 +03:00
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
2016-03-31 04:57:50 +03:00
. set_voltage_sel = spmi_regulator_single_range_set_voltage ,
. get_voltage_sel = spmi_regulator_single_range_get_voltage ,
. map_voltage = spmi_regulator_single_map_voltage ,
2015-06-13 01:47:10 +03:00
. list_voltage = spmi_regulator_common_list_voltage ,
. set_mode = spmi_regulator_common_set_mode ,
. get_mode = spmi_regulator_common_get_mode ,
. set_load = spmi_regulator_common_set_load ,
. set_bypass = spmi_regulator_common_set_bypass ,
. get_bypass = spmi_regulator_common_get_bypass ,
. set_pull_down = spmi_regulator_common_set_pull_down ,
. set_soft_start = spmi_regulator_common_set_soft_start ,
} ;
/* Maximum possible digital major revision value */
# define INF 0xFF
static const struct spmi_regulator_mapping supported_regulators [ ] = {
/* type subtype dig_min dig_max ltype ops setpoints hpm_min */
SPMI_VREG ( BUCK , GP_CTL , 0 , INF , SMPS , smps , smps , 100000 ) ,
SPMI_VREG ( LDO , N300 , 0 , INF , LDO , ldo , nldo1 , 10000 ) ,
SPMI_VREG ( LDO , N600 , 0 , 0 , LDO , ldo , nldo2 , 10000 ) ,
SPMI_VREG ( LDO , N1200 , 0 , 0 , LDO , ldo , nldo2 , 10000 ) ,
SPMI_VREG ( LDO , N600 , 1 , INF , LDO , ldo , nldo3 , 10000 ) ,
SPMI_VREG ( LDO , N1200 , 1 , INF , LDO , ldo , nldo3 , 10000 ) ,
SPMI_VREG ( LDO , N600_ST , 0 , 0 , LDO , ldo , nldo2 , 10000 ) ,
SPMI_VREG ( LDO , N1200_ST , 0 , 0 , LDO , ldo , nldo2 , 10000 ) ,
SPMI_VREG ( LDO , N600_ST , 1 , INF , LDO , ldo , nldo3 , 10000 ) ,
SPMI_VREG ( LDO , N1200_ST , 1 , INF , LDO , ldo , nldo3 , 10000 ) ,
SPMI_VREG ( LDO , P50 , 0 , INF , LDO , ldo , pldo , 5000 ) ,
SPMI_VREG ( LDO , P150 , 0 , INF , LDO , ldo , pldo , 10000 ) ,
SPMI_VREG ( LDO , P300 , 0 , INF , LDO , ldo , pldo , 10000 ) ,
SPMI_VREG ( LDO , P600 , 0 , INF , LDO , ldo , pldo , 10000 ) ,
SPMI_VREG ( LDO , P1200 , 0 , INF , LDO , ldo , pldo , 10000 ) ,
SPMI_VREG ( LDO , LN , 0 , INF , LN_LDO , ln_ldo , ln_ldo , 0 ) ,
SPMI_VREG ( LDO , LV_P50 , 0 , INF , LDO , ldo , pldo , 5000 ) ,
SPMI_VREG ( LDO , LV_P150 , 0 , INF , LDO , ldo , pldo , 10000 ) ,
SPMI_VREG ( LDO , LV_P300 , 0 , INF , LDO , ldo , pldo , 10000 ) ,
SPMI_VREG ( LDO , LV_P600 , 0 , INF , LDO , ldo , pldo , 10000 ) ,
SPMI_VREG ( LDO , LV_P1200 , 0 , INF , LDO , ldo , pldo , 10000 ) ,
SPMI_VREG_VS ( LV100 , 0 , INF ) ,
SPMI_VREG_VS ( LV300 , 0 , INF ) ,
SPMI_VREG_VS ( MV300 , 0 , INF ) ,
SPMI_VREG_VS ( MV500 , 0 , INF ) ,
SPMI_VREG_VS ( HDMI , 0 , INF ) ,
SPMI_VREG_VS ( OTG , 0 , INF ) ,
SPMI_VREG ( BOOST , 5 V_BOOST , 0 , INF , BOOST , boost , boost , 0 ) ,
SPMI_VREG ( FTS , FTS_CTL , 0 , INF , FTSMPS , ftsmps , ftsmps , 100000 ) ,
SPMI_VREG ( FTS , FTS2p5_CTL , 0 , INF , FTSMPS , ftsmps , ftsmps2p5 , 100000 ) ,
SPMI_VREG ( BOOST_BYP , BB_2A , 0 , INF , BOOST_BYP , boost , boost_byp , 0 ) ,
SPMI_VREG ( ULT_BUCK , ULT_HF_CTL1 , 0 , INF , ULT_LO_SMPS , ult_lo_smps ,
ult_lo_smps , 100000 ) ,
SPMI_VREG ( ULT_BUCK , ULT_HF_CTL2 , 0 , INF , ULT_LO_SMPS , ult_lo_smps ,
ult_lo_smps , 100000 ) ,
SPMI_VREG ( ULT_BUCK , ULT_HF_CTL3 , 0 , INF , ULT_LO_SMPS , ult_lo_smps ,
ult_lo_smps , 100000 ) ,
SPMI_VREG ( ULT_BUCK , ULT_HF_CTL4 , 0 , INF , ULT_HO_SMPS , ult_ho_smps ,
ult_ho_smps , 100000 ) ,
SPMI_VREG ( ULT_LDO , N300_ST , 0 , INF , ULT_LDO , ult_ldo , ult_nldo , 10000 ) ,
SPMI_VREG ( ULT_LDO , N600_ST , 0 , INF , ULT_LDO , ult_ldo , ult_nldo , 10000 ) ,
SPMI_VREG ( ULT_LDO , N900_ST , 0 , INF , ULT_LDO , ult_ldo , ult_nldo , 10000 ) ,
SPMI_VREG ( ULT_LDO , N1200_ST , 0 , INF , ULT_LDO , ult_ldo , ult_nldo , 10000 ) ,
SPMI_VREG ( ULT_LDO , LV_P150 , 0 , INF , ULT_LDO , ult_ldo , ult_pldo , 10000 ) ,
SPMI_VREG ( ULT_LDO , LV_P300 , 0 , INF , ULT_LDO , ult_ldo , ult_pldo , 10000 ) ,
SPMI_VREG ( ULT_LDO , LV_P450 , 0 , INF , ULT_LDO , ult_ldo , ult_pldo , 10000 ) ,
SPMI_VREG ( ULT_LDO , P600 , 0 , INF , ULT_LDO , ult_ldo , ult_pldo , 10000 ) ,
SPMI_VREG ( ULT_LDO , P150 , 0 , INF , ULT_LDO , ult_ldo , ult_pldo , 10000 ) ,
SPMI_VREG ( ULT_LDO , P50 , 0 , INF , ULT_LDO , ult_ldo , ult_pldo , 5000 ) ,
} ;
static void spmi_calculate_num_voltages ( struct spmi_voltage_set_points * points )
{
unsigned int n ;
struct spmi_voltage_range * range = points - > range ;
for ( ; range < points - > range + points - > count ; range + + ) {
n = 0 ;
if ( range - > set_point_max_uV ) {
n = range - > set_point_max_uV - range - > set_point_min_uV ;
2015-06-18 03:50:39 +03:00
n = ( n / range - > step_uV ) + 1 ;
2015-06-13 01:47:10 +03:00
}
range - > n_voltages = n ;
points - > n_voltages + = n ;
}
}
static int spmi_regulator_match ( struct spmi_regulator * vreg , u16 force_type )
{
const struct spmi_regulator_mapping * mapping ;
int ret , i ;
u32 dig_major_rev ;
u8 version [ SPMI_COMMON_REG_SUBTYPE - SPMI_COMMON_REG_DIG_MAJOR_REV + 1 ] ;
u8 type , subtype ;
ret = spmi_vreg_read ( vreg , SPMI_COMMON_REG_DIG_MAJOR_REV , version ,
ARRAY_SIZE ( version ) ) ;
if ( ret ) {
2016-03-26 00:35:09 +03:00
dev_dbg ( vreg - > dev , " could not read version registers \n " ) ;
2015-06-13 01:47:10 +03:00
return ret ;
}
dig_major_rev = version [ SPMI_COMMON_REG_DIG_MAJOR_REV
- SPMI_COMMON_REG_DIG_MAJOR_REV ] ;
2018-05-21 14:25:30 +03:00
2015-06-13 01:47:10 +03:00
if ( ! force_type ) {
type = version [ SPMI_COMMON_REG_TYPE -
SPMI_COMMON_REG_DIG_MAJOR_REV ] ;
subtype = version [ SPMI_COMMON_REG_SUBTYPE -
SPMI_COMMON_REG_DIG_MAJOR_REV ] ;
} else {
type = force_type > > 8 ;
subtype = force_type ;
}
for ( i = 0 ; i < ARRAY_SIZE ( supported_regulators ) ; i + + ) {
mapping = & supported_regulators [ i ] ;
if ( mapping - > type = = type & & mapping - > subtype = = subtype
& & mapping - > revision_min < = dig_major_rev
& & mapping - > revision_max > = dig_major_rev )
goto found ;
}
dev_err ( vreg - > dev ,
" unsupported regulator: name=%s type=0x%02X, subtype=0x%02X, dig major rev=0x%02X \n " ,
vreg - > desc . name , type , subtype , dig_major_rev ) ;
return - ENODEV ;
found :
vreg - > logical_type = mapping - > logical_type ;
vreg - > set_points = mapping - > set_points ;
vreg - > hpm_min_load = mapping - > hpm_min_load ;
vreg - > desc . ops = mapping - > ops ;
if ( mapping - > set_points ) {
if ( ! mapping - > set_points - > n_voltages )
spmi_calculate_num_voltages ( mapping - > set_points ) ;
vreg - > desc . n_voltages = mapping - > set_points - > n_voltages ;
}
return 0 ;
}
2016-03-31 04:57:49 +03:00
static int spmi_regulator_init_slew_rate ( struct spmi_regulator * vreg )
2015-06-13 01:47:10 +03:00
{
int ret ;
u8 reg = 0 ;
2016-03-31 04:57:49 +03:00
int step , delay , slew_rate , step_delay ;
2015-06-13 01:47:10 +03:00
const struct spmi_voltage_range * range ;
ret = spmi_vreg_read ( vreg , SPMI_COMMON_REG_STEP_CTRL , & reg , 1 ) ;
if ( ret ) {
dev_err ( vreg - > dev , " spmi read failed, ret=%d \n " , ret ) ;
return ret ;
}
range = spmi_regulator_find_range ( vreg ) ;
if ( ! range )
return - EINVAL ;
2016-03-31 04:57:49 +03:00
switch ( vreg - > logical_type ) {
case SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS :
step_delay = SPMI_FTSMPS_STEP_DELAY ;
break ;
default :
step_delay = SPMI_DEFAULT_STEP_DELAY ;
break ;
}
2015-06-13 01:47:10 +03:00
step = reg & SPMI_FTSMPS_STEP_CTRL_STEP_MASK ;
step > > = SPMI_FTSMPS_STEP_CTRL_STEP_SHIFT ;
delay = reg & SPMI_FTSMPS_STEP_CTRL_DELAY_MASK ;
delay > > = SPMI_FTSMPS_STEP_CTRL_DELAY_SHIFT ;
/* slew_rate has units of uV/us */
slew_rate = SPMI_FTSMPS_CLOCK_RATE * range - > step_uV * ( 1 < < step ) ;
2016-03-31 04:57:49 +03:00
slew_rate / = 1000 * ( step_delay < < delay ) ;
2015-06-13 01:47:10 +03:00
slew_rate * = SPMI_FTSMPS_STEP_MARGIN_NUM ;
slew_rate / = SPMI_FTSMPS_STEP_MARGIN_DEN ;
/* Ensure that the slew rate is greater than 0 */
vreg - > slew_rate = max ( slew_rate , 1 ) ;
return ret ;
}
2015-07-18 00:41:55 +03:00
static int spmi_regulator_init_registers ( struct spmi_regulator * vreg ,
const struct spmi_regulator_init_data * data )
{
int ret ;
enum spmi_regulator_logical_type type ;
u8 ctrl_reg [ 8 ] , reg , mask ;
type = vreg - > logical_type ;
ret = spmi_vreg_read ( vreg , SPMI_COMMON_REG_VOLTAGE_RANGE , ctrl_reg , 8 ) ;
if ( ret )
return ret ;
/* Set up enable pin control. */
if ( ( type = = SPMI_REGULATOR_LOGICAL_TYPE_SMPS
| | type = = SPMI_REGULATOR_LOGICAL_TYPE_LDO
| | type = = SPMI_REGULATOR_LOGICAL_TYPE_VS )
& & ! ( data - > pin_ctrl_enable
& SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT ) ) {
ctrl_reg [ SPMI_COMMON_IDX_ENABLE ] & =
~ SPMI_COMMON_ENABLE_FOLLOW_ALL_MASK ;
ctrl_reg [ SPMI_COMMON_IDX_ENABLE ] | =
data - > pin_ctrl_enable & SPMI_COMMON_ENABLE_FOLLOW_ALL_MASK ;
}
/* Set up mode pin control. */
if ( ( type = = SPMI_REGULATOR_LOGICAL_TYPE_SMPS
| | type = = SPMI_REGULATOR_LOGICAL_TYPE_LDO )
& & ! ( data - > pin_ctrl_hpm
& SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT ) ) {
ctrl_reg [ SPMI_COMMON_IDX_MODE ] & =
~ SPMI_COMMON_MODE_FOLLOW_ALL_MASK ;
ctrl_reg [ SPMI_COMMON_IDX_MODE ] | =
data - > pin_ctrl_hpm & SPMI_COMMON_MODE_FOLLOW_ALL_MASK ;
}
if ( type = = SPMI_REGULATOR_LOGICAL_TYPE_VS
& & ! ( data - > pin_ctrl_hpm & SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT ) ) {
ctrl_reg [ SPMI_COMMON_IDX_MODE ] & =
~ SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK ;
ctrl_reg [ SPMI_COMMON_IDX_MODE ] | =
data - > pin_ctrl_hpm & SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK ;
}
if ( ( type = = SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS
| | type = = SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS
| | type = = SPMI_REGULATOR_LOGICAL_TYPE_ULT_LDO )
& & ! ( data - > pin_ctrl_hpm
& SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT ) ) {
ctrl_reg [ SPMI_COMMON_IDX_MODE ] & =
~ SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK ;
ctrl_reg [ SPMI_COMMON_IDX_MODE ] | =
data - > pin_ctrl_hpm & SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK ;
}
/* Write back any control register values that were modified. */
ret = spmi_vreg_write ( vreg , SPMI_COMMON_REG_VOLTAGE_RANGE , ctrl_reg , 8 ) ;
if ( ret )
return ret ;
/* Set soft start strength and over current protection for VS. */
if ( type = = SPMI_REGULATOR_LOGICAL_TYPE_VS ) {
if ( data - > vs_soft_start_strength
! = SPMI_VS_SOFT_START_STR_HW_DEFAULT ) {
reg = data - > vs_soft_start_strength
& SPMI_VS_SOFT_START_SEL_MASK ;
mask = SPMI_VS_SOFT_START_SEL_MASK ;
return spmi_vreg_update_bits ( vreg ,
SPMI_VS_REG_SOFT_START ,
reg , mask ) ;
}
}
return 0 ;
}
static void spmi_regulator_get_dt_config ( struct spmi_regulator * vreg ,
struct device_node * node , struct spmi_regulator_init_data * data )
{
/*
* Initialize configuration parameters to use hardware default in case
* no value is specified via device tree .
*/
data - > pin_ctrl_enable = SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT ;
data - > pin_ctrl_hpm = SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT ;
data - > vs_soft_start_strength = SPMI_VS_SOFT_START_STR_HW_DEFAULT ;
/* These bindings are optional, so it is okay if they aren't found. */
of_property_read_u32 ( node , " qcom,ocp-max-retries " ,
& vreg - > ocp_max_retries ) ;
of_property_read_u32 ( node , " qcom,ocp-retry-delay " ,
& vreg - > ocp_retry_delay_ms ) ;
of_property_read_u32 ( node , " qcom,pin-ctrl-enable " ,
& data - > pin_ctrl_enable ) ;
of_property_read_u32 ( node , " qcom,pin-ctrl-hpm " , & data - > pin_ctrl_hpm ) ;
of_property_read_u32 ( node , " qcom,vs-soft-start-strength " ,
& data - > vs_soft_start_strength ) ;
}
2015-06-13 01:47:10 +03:00
static unsigned int spmi_regulator_of_map_mode ( unsigned int mode )
{
2015-07-18 00:41:55 +03:00
if ( mode = = 1 )
2015-06-13 01:47:10 +03:00
return REGULATOR_MODE_NORMAL ;
2015-07-18 00:41:55 +03:00
if ( mode = = 2 )
return REGULATOR_MODE_FAST ;
2015-06-13 01:47:10 +03:00
return REGULATOR_MODE_IDLE ;
}
static int spmi_regulator_of_parse ( struct device_node * node ,
const struct regulator_desc * desc ,
struct regulator_config * config )
{
2015-07-18 00:41:55 +03:00
struct spmi_regulator_init_data data = { } ;
2015-06-13 01:47:10 +03:00
struct spmi_regulator * vreg = config - > driver_data ;
struct device * dev = config - > dev ;
int ret ;
2015-07-18 00:41:55 +03:00
spmi_regulator_get_dt_config ( vreg , node , & data ) ;
if ( ! vreg - > ocp_max_retries )
vreg - > ocp_max_retries = SPMI_VS_OCP_DEFAULT_MAX_RETRIES ;
if ( ! vreg - > ocp_retry_delay_ms )
vreg - > ocp_retry_delay_ms = SPMI_VS_OCP_DEFAULT_RETRY_DELAY_MS ;
ret = spmi_regulator_init_registers ( vreg , & data ) ;
if ( ret ) {
dev_err ( dev , " common initialization failed, ret=%d \n " , ret ) ;
return ret ;
}
2015-06-13 01:47:10 +03:00
2016-03-31 04:57:49 +03:00
switch ( vreg - > logical_type ) {
case SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS :
case SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS :
case SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS :
case SPMI_REGULATOR_LOGICAL_TYPE_SMPS :
ret = spmi_regulator_init_slew_rate ( vreg ) ;
2015-06-13 01:47:10 +03:00
if ( ret )
return ret ;
2016-03-31 04:57:49 +03:00
default :
break ;
2015-06-13 01:47:10 +03:00
}
if ( vreg - > logical_type ! = SPMI_REGULATOR_LOGICAL_TYPE_VS )
vreg - > ocp_irq = 0 ;
if ( vreg - > ocp_irq ) {
ret = devm_request_irq ( dev , vreg - > ocp_irq ,
spmi_regulator_vs_ocp_isr , IRQF_TRIGGER_RISING , " ocp " ,
vreg ) ;
if ( ret < 0 ) {
dev_err ( dev , " failed to request irq %d, ret=%d \n " ,
vreg - > ocp_irq , ret ) ;
return ret ;
}
INIT_DELAYED_WORK ( & vreg - > ocp_work , spmi_regulator_vs_ocp_work ) ;
}
return 0 ;
}
static const struct spmi_regulator_data pm8941_regulators [ ] = {
{ " s1 " , 0x1400 , " vdd_s1 " , } ,
{ " s2 " , 0x1700 , " vdd_s2 " , } ,
{ " s3 " , 0x1a00 , " vdd_s3 " , } ,
2016-06-26 08:52:11 +03:00
{ " s4 " , 0xa000 , } ,
2015-06-13 01:47:10 +03:00
{ " l1 " , 0x4000 , " vdd_l1_l3 " , } ,
{ " l2 " , 0x4100 , " vdd_l2_lvs_1_2_3 " , } ,
{ " l3 " , 0x4200 , " vdd_l1_l3 " , } ,
{ " l4 " , 0x4300 , " vdd_l4_l11 " , } ,
{ " l5 " , 0x4400 , " vdd_l5_l7 " , NULL , 0x0410 } ,
{ " l6 " , 0x4500 , " vdd_l6_l12_l14_l15 " , } ,
{ " l7 " , 0x4600 , " vdd_l5_l7 " , NULL , 0x0410 } ,
{ " l8 " , 0x4700 , " vdd_l8_l16_l18_19 " , } ,
{ " l9 " , 0x4800 , " vdd_l9_l10_l17_l22 " , } ,
{ " l10 " , 0x4900 , " vdd_l9_l10_l17_l22 " , } ,
{ " l11 " , 0x4a00 , " vdd_l4_l11 " , } ,
{ " l12 " , 0x4b00 , " vdd_l6_l12_l14_l15 " , } ,
{ " l13 " , 0x4c00 , " vdd_l13_l20_l23_l24 " , } ,
{ " l14 " , 0x4d00 , " vdd_l6_l12_l14_l15 " , } ,
{ " l15 " , 0x4e00 , " vdd_l6_l12_l14_l15 " , } ,
{ " l16 " , 0x4f00 , " vdd_l8_l16_l18_19 " , } ,
{ " l17 " , 0x5000 , " vdd_l9_l10_l17_l22 " , } ,
{ " l18 " , 0x5100 , " vdd_l8_l16_l18_19 " , } ,
{ " l19 " , 0x5200 , " vdd_l8_l16_l18_19 " , } ,
{ " l20 " , 0x5300 , " vdd_l13_l20_l23_l24 " , } ,
{ " l21 " , 0x5400 , " vdd_l21 " , } ,
{ " l22 " , 0x5500 , " vdd_l9_l10_l17_l22 " , } ,
{ " l23 " , 0x5600 , " vdd_l13_l20_l23_l24 " , } ,
{ " l24 " , 0x5700 , " vdd_l13_l20_l23_l24 " , } ,
{ " lvs1 " , 0x8000 , " vdd_l2_lvs_1_2_3 " , } ,
{ " lvs2 " , 0x8100 , " vdd_l2_lvs_1_2_3 " , } ,
{ " lvs3 " , 0x8200 , " vdd_l2_lvs_1_2_3 " , } ,
2016-06-26 08:52:12 +03:00
{ " 5vs1 " , 0x8300 , " vin_5vs " , " ocp-5vs1 " , } ,
{ " 5vs2 " , 0x8400 , " vin_5vs " , " ocp-5vs2 " , } ,
2015-06-13 01:47:10 +03:00
{ }
} ;
static const struct spmi_regulator_data pm8841_regulators [ ] = {
{ " s1 " , 0x1400 , " vdd_s1 " , } ,
{ " s2 " , 0x1700 , " vdd_s2 " , NULL , 0x1c08 } ,
{ " s3 " , 0x1a00 , " vdd_s3 " , } ,
{ " s4 " , 0x1d00 , " vdd_s4 " , NULL , 0x1c08 } ,
{ " s5 " , 0x2000 , " vdd_s5 " , NULL , 0x1c08 } ,
{ " s6 " , 0x2300 , " vdd_s6 " , NULL , 0x1c08 } ,
{ " s7 " , 0x2600 , " vdd_s7 " , NULL , 0x1c08 } ,
{ " s8 " , 0x2900 , " vdd_s8 " , NULL , 0x1c08 } ,
{ }
} ;
static const struct spmi_regulator_data pm8916_regulators [ ] = {
{ " s1 " , 0x1400 , " vdd_s1 " , } ,
{ " s2 " , 0x1700 , " vdd_s2 " , } ,
{ " s3 " , 0x1a00 , " vdd_s3 " , } ,
{ " s4 " , 0x1d00 , " vdd_s4 " , } ,
{ " l1 " , 0x4000 , " vdd_l1_l3 " , } ,
{ " l2 " , 0x4100 , " vdd_l2 " , } ,
{ " l3 " , 0x4200 , " vdd_l1_l3 " , } ,
{ " l4 " , 0x4300 , " vdd_l4_l5_l6 " , } ,
{ " l5 " , 0x4400 , " vdd_l4_l5_l6 " , } ,
{ " l6 " , 0x4500 , " vdd_l4_l5_l6 " , } ,
{ " l7 " , 0x4600 , " vdd_l7 " , } ,
{ " l8 " , 0x4700 , " vdd_l8_l11_l14_l15_l16 " , } ,
{ " l9 " , 0x4800 , " vdd_l9_l10_l12_l13_l17_l18 " , } ,
{ " l10 " , 0x4900 , " vdd_l9_l10_l12_l13_l17_l18 " , } ,
{ " l11 " , 0x4a00 , " vdd_l8_l11_l14_l15_l16 " , } ,
{ " l12 " , 0x4b00 , " vdd_l9_l10_l12_l13_l17_l18 " , } ,
{ " l13 " , 0x4c00 , " vdd_l9_l10_l12_l13_l17_l18 " , } ,
{ " l14 " , 0x4d00 , " vdd_l8_l11_l14_l15_l16 " , } ,
{ " l15 " , 0x4e00 , " vdd_l8_l11_l14_l15_l16 " , } ,
{ " l16 " , 0x4f00 , " vdd_l8_l11_l14_l15_l16 " , } ,
{ " l17 " , 0x5000 , " vdd_l9_l10_l12_l13_l17_l18 " , } ,
{ " l18 " , 0x5100 , " vdd_l9_l10_l12_l13_l17_l18 " , } ,
{ }
} ;
2016-03-26 00:35:08 +03:00
static const struct spmi_regulator_data pm8994_regulators [ ] = {
{ " s1 " , 0x1400 , " vdd_s1 " , } ,
{ " s2 " , 0x1700 , " vdd_s2 " , } ,
{ " s3 " , 0x1a00 , " vdd_s3 " , } ,
{ " s4 " , 0x1d00 , " vdd_s4 " , } ,
{ " s5 " , 0x2000 , " vdd_s5 " , } ,
{ " s6 " , 0x2300 , " vdd_s6 " , } ,
{ " s7 " , 0x2600 , " vdd_s7 " , } ,
{ " s8 " , 0x2900 , " vdd_s8 " , } ,
{ " s9 " , 0x2c00 , " vdd_s9 " , } ,
{ " s10 " , 0x2f00 , " vdd_s10 " , } ,
{ " s11 " , 0x3200 , " vdd_s11 " , } ,
{ " s12 " , 0x3500 , " vdd_s12 " , } ,
{ " l1 " , 0x4000 , " vdd_l1 " , } ,
{ " l2 " , 0x4100 , " vdd_l2_l26_l28 " , } ,
{ " l3 " , 0x4200 , " vdd_l3_l11 " , } ,
{ " l4 " , 0x4300 , " vdd_l4_l27_l31 " , } ,
{ " l5 " , 0x4400 , " vdd_l5_l7 " , } ,
{ " l6 " , 0x4500 , " vdd_l6_l12_l32 " , } ,
{ " l7 " , 0x4600 , " vdd_l5_l7 " , } ,
{ " l8 " , 0x4700 , " vdd_l8_l16_l30 " , } ,
{ " l9 " , 0x4800 , " vdd_l9_l10_l18_l22 " , } ,
{ " l10 " , 0x4900 , " vdd_l9_l10_l18_l22 " , } ,
{ " l11 " , 0x4a00 , " vdd_l3_l11 " , } ,
{ " l12 " , 0x4b00 , " vdd_l6_l12_l32 " , } ,
{ " l13 " , 0x4c00 , " vdd_l13_l19_l23_l24 " , } ,
{ " l14 " , 0x4d00 , " vdd_l14_l15 " , } ,
{ " l15 " , 0x4e00 , " vdd_l14_l15 " , } ,
{ " l16 " , 0x4f00 , " vdd_l8_l16_l30 " , } ,
{ " l17 " , 0x5000 , " vdd_l17_l29 " , } ,
{ " l18 " , 0x5100 , " vdd_l9_l10_l18_l22 " , } ,
{ " l19 " , 0x5200 , " vdd_l13_l19_l23_l24 " , } ,
{ " l20 " , 0x5300 , " vdd_l20_l21 " , } ,
{ " l21 " , 0x5400 , " vdd_l20_l21 " , } ,
{ " l22 " , 0x5500 , " vdd_l9_l10_l18_l22 " , } ,
{ " l23 " , 0x5600 , " vdd_l13_l19_l23_l24 " , } ,
{ " l24 " , 0x5700 , " vdd_l13_l19_l23_l24 " , } ,
{ " l25 " , 0x5800 , " vdd_l25 " , } ,
{ " l26 " , 0x5900 , " vdd_l2_l26_l28 " , } ,
{ " l27 " , 0x5a00 , " vdd_l4_l27_l31 " , } ,
{ " l28 " , 0x5b00 , " vdd_l2_l26_l28 " , } ,
{ " l29 " , 0x5c00 , " vdd_l17_l29 " , } ,
{ " l30 " , 0x5d00 , " vdd_l8_l16_l30 " , } ,
{ " l31 " , 0x5e00 , " vdd_l4_l27_l31 " , } ,
{ " l32 " , 0x5f00 , " vdd_l6_l12_l32 " , } ,
{ " lvs1 " , 0x8000 , " vdd_lvs_1_2 " , } ,
{ " lvs2 " , 0x8100 , " vdd_lvs_1_2 " , } ,
{ }
} ;
2017-11-02 12:24:00 +03:00
static const struct spmi_regulator_data pmi8994_regulators [ ] = {
{ " s1 " , 0x1400 , " vdd_s1 " , } ,
{ " s2 " , 0x1700 , " vdd_s2 " , } ,
{ " s3 " , 0x1a00 , " vdd_s3 " , } ,
{ " l1 " , 0x4000 , " vdd_l1 " , } ,
{ }
} ;
2015-06-13 01:47:10 +03:00
static const struct of_device_id qcom_spmi_regulator_match [ ] = {
{ . compatible = " qcom,pm8841-regulators " , . data = & pm8841_regulators } ,
{ . compatible = " qcom,pm8916-regulators " , . data = & pm8916_regulators } ,
{ . compatible = " qcom,pm8941-regulators " , . data = & pm8941_regulators } ,
2016-03-26 00:35:08 +03:00
{ . compatible = " qcom,pm8994-regulators " , . data = & pm8994_regulators } ,
2017-11-02 12:24:00 +03:00
{ . compatible = " qcom,pmi8994-regulators " , . data = & pmi8994_regulators } ,
2015-06-13 01:47:10 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , qcom_spmi_regulator_match ) ;
static int qcom_spmi_regulator_probe ( struct platform_device * pdev )
{
const struct spmi_regulator_data * reg ;
const struct of_device_id * match ;
struct regulator_config config = { } ;
struct regulator_dev * rdev ;
struct spmi_regulator * vreg ;
struct regmap * regmap ;
const char * name ;
struct device * dev = & pdev - > dev ;
2018-05-21 14:25:30 +03:00
struct device_node * node = pdev - > dev . of_node ;
2018-07-16 16:32:51 +03:00
struct device_node * syscon , * reg_node ;
struct property * reg_prop ;
2018-05-21 14:25:30 +03:00
int ret , lenp ;
2015-06-13 01:47:10 +03:00
struct list_head * vreg_list ;
vreg_list = devm_kzalloc ( dev , sizeof ( * vreg_list ) , GFP_KERNEL ) ;
if ( ! vreg_list )
return - ENOMEM ;
INIT_LIST_HEAD ( vreg_list ) ;
platform_set_drvdata ( pdev , vreg_list ) ;
regmap = dev_get_regmap ( dev - > parent , NULL ) ;
if ( ! regmap )
return - ENODEV ;
match = of_match_device ( qcom_spmi_regulator_match , & pdev - > dev ) ;
if ( ! match )
return - ENODEV ;
2018-05-21 14:25:30 +03:00
if ( of_find_property ( node , " qcom,saw-reg " , & lenp ) ) {
syscon = of_parse_phandle ( node , " qcom,saw-reg " , 0 ) ;
saw_regmap = syscon_node_to_regmap ( syscon ) ;
of_node_put ( syscon ) ;
2018-07-16 16:32:52 +03:00
if ( IS_ERR ( saw_regmap ) )
2018-05-21 14:25:30 +03:00
dev_err ( dev , " ERROR reading SAW regmap \n " ) ;
}
2015-06-13 01:47:10 +03:00
for ( reg = match - > data ; reg - > name ; reg + + ) {
2018-05-21 14:25:30 +03:00
2018-07-16 16:32:51 +03:00
if ( saw_regmap ) {
reg_node = of_get_child_by_name ( node , reg - > name ) ;
reg_prop = of_find_property ( reg_node , " qcom,saw-slave " ,
& lenp ) ;
of_node_put ( reg_node ) ;
if ( reg_prop )
continue ;
2018-05-21 14:25:30 +03:00
}
2015-06-13 01:47:10 +03:00
vreg = devm_kzalloc ( dev , sizeof ( * vreg ) , GFP_KERNEL ) ;
if ( ! vreg )
return - ENOMEM ;
vreg - > dev = dev ;
vreg - > base = reg - > base ;
vreg - > regmap = regmap ;
if ( reg - > ocp ) {
vreg - > ocp_irq = platform_get_irq_byname ( pdev , reg - > ocp ) ;
if ( vreg - > ocp_irq < 0 ) {
ret = vreg - > ocp_irq ;
goto err ;
}
}
vreg - > desc . id = - 1 ;
vreg - > desc . owner = THIS_MODULE ;
vreg - > desc . type = REGULATOR_VOLTAGE ;
2017-11-29 17:02:46 +03:00
vreg - > desc . enable_reg = reg - > base + SPMI_COMMON_REG_ENABLE ;
vreg - > desc . enable_mask = SPMI_COMMON_ENABLE_MASK ;
vreg - > desc . enable_val = SPMI_COMMON_ENABLE ;
2015-06-13 01:47:10 +03:00
vreg - > desc . name = name = reg - > name ;
vreg - > desc . supply_name = reg - > supply ;
vreg - > desc . of_match = reg - > name ;
vreg - > desc . of_parse_cb = spmi_regulator_of_parse ;
vreg - > desc . of_map_mode = spmi_regulator_of_map_mode ;
ret = spmi_regulator_match ( vreg , reg - > force_type ) ;
if ( ret )
2016-03-26 00:35:09 +03:00
continue ;
2015-06-13 01:47:10 +03:00
2018-07-16 16:32:51 +03:00
if ( saw_regmap ) {
reg_node = of_get_child_by_name ( node , reg - > name ) ;
reg_prop = of_find_property ( reg_node , " qcom,saw-leader " ,
& lenp ) ;
of_node_put ( reg_node ) ;
if ( reg_prop ) {
spmi_saw_ops = * ( vreg - > desc . ops ) ;
spmi_saw_ops . set_voltage_sel =
spmi_regulator_saw_set_voltage ;
vreg - > desc . ops = & spmi_saw_ops ;
}
2018-05-21 14:25:30 +03:00
}
2015-06-13 01:47:10 +03:00
config . dev = dev ;
config . driver_data = vreg ;
2017-11-29 17:02:46 +03:00
config . regmap = regmap ;
2015-06-13 01:47:10 +03:00
rdev = devm_regulator_register ( dev , & vreg - > desc , & config ) ;
if ( IS_ERR ( rdev ) ) {
dev_err ( dev , " failed to register %s \n " , name ) ;
ret = PTR_ERR ( rdev ) ;
goto err ;
}
INIT_LIST_HEAD ( & vreg - > node ) ;
list_add ( & vreg - > node , vreg_list ) ;
}
return 0 ;
err :
list_for_each_entry ( vreg , vreg_list , node )
if ( vreg - > ocp_irq )
cancel_delayed_work_sync ( & vreg - > ocp_work ) ;
return ret ;
}
static int qcom_spmi_regulator_remove ( struct platform_device * pdev )
{
struct spmi_regulator * vreg ;
struct list_head * vreg_list = platform_get_drvdata ( pdev ) ;
list_for_each_entry ( vreg , vreg_list , node )
if ( vreg - > ocp_irq )
cancel_delayed_work_sync ( & vreg - > ocp_work ) ;
return 0 ;
}
static struct platform_driver qcom_spmi_regulator_driver = {
. driver = {
. name = " qcom-spmi-regulator " ,
. of_match_table = qcom_spmi_regulator_match ,
} ,
. probe = qcom_spmi_regulator_probe ,
. remove = qcom_spmi_regulator_remove ,
} ;
module_platform_driver ( qcom_spmi_regulator_driver ) ;
MODULE_DESCRIPTION ( " Qualcomm SPMI PMIC regulator driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_ALIAS ( " platform:qcom-spmi-regulator " ) ;