mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 18:30:06 +00:00
regulator: qcom_spmi: Add support for PM8005
The PM8005 is used on the msm8998 MTP. The S1 regulator is VDD_GFX, ie it needs to be on and controlled inorder to use the GPU. Add support to drive the PM8005 regulators so that we can bring up the GPU on msm8998. Signed-off-by: Jeffrey Hugo <jeffrey.l.hugo@gmail.com> Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
4fe0676b04
commit
42ba89c8bb
1 changed files with 176 additions and 0 deletions
|
@ -96,6 +96,7 @@ enum spmi_regulator_logical_type {
|
|||
SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS,
|
||||
SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS,
|
||||
SPMI_REGULATOR_LOGICAL_TYPE_ULT_LDO,
|
||||
SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS426,
|
||||
};
|
||||
|
||||
enum spmi_regulator_type {
|
||||
|
@ -142,6 +143,7 @@ enum spmi_regulator_subtype {
|
|||
SPMI_REGULATOR_SUBTYPE_5V_BOOST = 0x01,
|
||||
SPMI_REGULATOR_SUBTYPE_FTS_CTL = 0x08,
|
||||
SPMI_REGULATOR_SUBTYPE_FTS2p5_CTL = 0x09,
|
||||
SPMI_REGULATOR_SUBTYPE_FTS426_CTL = 0x0a,
|
||||
SPMI_REGULATOR_SUBTYPE_BB_2A = 0x01,
|
||||
SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL1 = 0x0d,
|
||||
SPMI_REGULATOR_SUBTYPE_ULT_HF_CTL2 = 0x0e,
|
||||
|
@ -162,6 +164,18 @@ enum spmi_common_regulator_registers {
|
|||
SPMI_COMMON_REG_STEP_CTRL = 0x61,
|
||||
};
|
||||
|
||||
/*
|
||||
* Second common register layout used by newer devices starting with ftsmps426
|
||||
* Note that some of the registers from the first common layout remain
|
||||
* unchanged and their definition is not duplicated.
|
||||
*/
|
||||
enum spmi_ftsmps426_regulator_registers {
|
||||
SPMI_FTSMPS426_REG_VOLTAGE_LSB = 0x40,
|
||||
SPMI_FTSMPS426_REG_VOLTAGE_MSB = 0x41,
|
||||
SPMI_FTSMPS426_REG_VOLTAGE_ULS_LSB = 0x68,
|
||||
SPMI_FTSMPS426_REG_VOLTAGE_ULS_MSB = 0x69,
|
||||
};
|
||||
|
||||
enum spmi_vs_registers {
|
||||
SPMI_VS_REG_OCP = 0x4a,
|
||||
SPMI_VS_REG_SOFT_START = 0x4c,
|
||||
|
@ -221,6 +235,14 @@ enum spmi_common_control_register_index {
|
|||
#define SPMI_COMMON_MODE_FOLLOW_HW_EN0_MASK 0x01
|
||||
#define SPMI_COMMON_MODE_FOLLOW_ALL_MASK 0x1f
|
||||
|
||||
#define SPMI_FTSMPS426_MODE_BYPASS_MASK 3
|
||||
#define SPMI_FTSMPS426_MODE_RETENTION_MASK 4
|
||||
#define SPMI_FTSMPS426_MODE_LPM_MASK 5
|
||||
#define SPMI_FTSMPS426_MODE_AUTO_MASK 6
|
||||
#define SPMI_FTSMPS426_MODE_HPM_MASK 7
|
||||
|
||||
#define SPMI_FTSMPS426_MODE_MASK 0x07
|
||||
|
||||
/* Common regulator pull down control register layout */
|
||||
#define SPMI_COMMON_PULL_DOWN_ENABLE_MASK 0x80
|
||||
|
||||
|
@ -266,6 +288,23 @@ enum spmi_common_control_register_index {
|
|||
#define SPMI_FTSMPS_STEP_MARGIN_NUM 4
|
||||
#define SPMI_FTSMPS_STEP_MARGIN_DEN 5
|
||||
|
||||
#define SPMI_FTSMPS426_STEP_CTRL_DELAY_MASK 0x03
|
||||
#define SPMI_FTSMPS426_STEP_CTRL_DELAY_SHIFT 0
|
||||
|
||||
/* Clock rate in kHz of the FTSMPS426 regulator reference clock. */
|
||||
#define SPMI_FTSMPS426_CLOCK_RATE 4800
|
||||
|
||||
/* Minimum voltage stepper delay for each step. */
|
||||
#define SPMI_FTSMPS426_STEP_DELAY 2
|
||||
|
||||
/*
|
||||
* The ratio SPMI_FTSMPS426_STEP_MARGIN_NUM/SPMI_FTSMPS426_STEP_MARGIN_DEN is
|
||||
* used to adjust the step rate in order to account for oscillator variance.
|
||||
*/
|
||||
#define SPMI_FTSMPS426_STEP_MARGIN_NUM 10
|
||||
#define SPMI_FTSMPS426_STEP_MARGIN_DEN 11
|
||||
|
||||
|
||||
/* VSET value to decide the range of ULT SMPS */
|
||||
#define ULT_SMPS_RANGE_SPLIT 0x60
|
||||
|
||||
|
@ -439,6 +478,10 @@ static struct spmi_voltage_range ftsmps2p5_ranges[] = {
|
|||
SPMI_VOLTAGE_RANGE(1, 160000, 1360000, 2200000, 2200000, 10000),
|
||||
};
|
||||
|
||||
static struct spmi_voltage_range ftsmps426_ranges[] = {
|
||||
SPMI_VOLTAGE_RANGE(0, 0, 320000, 1352000, 1352000, 4000),
|
||||
};
|
||||
|
||||
static struct spmi_voltage_range boost_ranges[] = {
|
||||
SPMI_VOLTAGE_RANGE(0, 4000000, 4000000, 5550000, 5550000, 50000),
|
||||
};
|
||||
|
@ -472,6 +515,7 @@ 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(ftsmps426);
|
||||
static DEFINE_SPMI_SET_POINTS(boost);
|
||||
static DEFINE_SPMI_SET_POINTS(boost_byp);
|
||||
static DEFINE_SPMI_SET_POINTS(ult_lo_smps);
|
||||
|
@ -739,6 +783,23 @@ spmi_regulator_common_set_voltage(struct regulator_dev *rdev, unsigned selector)
|
|||
return spmi_vreg_write(vreg, SPMI_COMMON_REG_VOLTAGE_RANGE, buf, 2);
|
||||
}
|
||||
|
||||
static int spmi_regulator_common_list_voltage(struct regulator_dev *rdev,
|
||||
unsigned selector);
|
||||
|
||||
static int spmi_regulator_ftsmps426_set_voltage(struct regulator_dev *rdev,
|
||||
unsigned selector)
|
||||
{
|
||||
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
|
||||
u8 buf[2];
|
||||
int mV;
|
||||
|
||||
mV = spmi_regulator_common_list_voltage(rdev, selector) / 1000;
|
||||
|
||||
buf[0] = mV & 0xff;
|
||||
buf[1] = mV >> 8;
|
||||
return spmi_vreg_write(vreg, SPMI_FTSMPS426_REG_VOLTAGE_LSB, buf, 2);
|
||||
}
|
||||
|
||||
static int spmi_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
|
||||
unsigned int old_selector, unsigned int new_selector)
|
||||
{
|
||||
|
@ -770,6 +831,21 @@ static int spmi_regulator_common_get_voltage(struct regulator_dev *rdev)
|
|||
return spmi_hw_selector_to_sw(vreg, voltage_sel, range);
|
||||
}
|
||||
|
||||
static int spmi_regulator_ftsmps426_get_voltage(struct regulator_dev *rdev)
|
||||
{
|
||||
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
|
||||
const struct spmi_voltage_range *range;
|
||||
u8 buf[2];
|
||||
int uV;
|
||||
|
||||
spmi_vreg_read(vreg, SPMI_FTSMPS426_REG_VOLTAGE_LSB, buf, 2);
|
||||
|
||||
uV = (((unsigned int)buf[1] << 8) | (unsigned int)buf[0]) * 1000;
|
||||
range = vreg->set_points->range;
|
||||
|
||||
return (uV - range->set_point_min_uV) / range->step_uV;
|
||||
}
|
||||
|
||||
static int spmi_regulator_single_map_voltage(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV)
|
||||
{
|
||||
|
@ -915,6 +991,23 @@ static unsigned int spmi_regulator_common_get_mode(struct regulator_dev *rdev)
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned int spmi_regulator_ftsmps426_get_mode(struct regulator_dev *rdev)
|
||||
{
|
||||
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
|
||||
u8 reg;
|
||||
|
||||
spmi_vreg_read(vreg, SPMI_COMMON_REG_MODE, ®, 1);
|
||||
|
||||
switch (reg) {
|
||||
case SPMI_FTSMPS426_MODE_HPM_MASK:
|
||||
return REGULATOR_MODE_NORMAL;
|
||||
case SPMI_FTSMPS426_MODE_AUTO_MASK:
|
||||
return REGULATOR_MODE_FAST;
|
||||
default:
|
||||
return REGULATOR_MODE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
spmi_regulator_common_set_mode(struct regulator_dev *rdev, unsigned int mode)
|
||||
{
|
||||
|
@ -937,6 +1030,30 @@ spmi_regulator_common_set_mode(struct regulator_dev *rdev, unsigned int mode)
|
|||
return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_MODE, val, mask);
|
||||
}
|
||||
|
||||
static int
|
||||
spmi_regulator_ftsmps426_set_mode(struct regulator_dev *rdev, unsigned int mode)
|
||||
{
|
||||
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
|
||||
u8 mask = SPMI_FTSMPS426_MODE_MASK;
|
||||
u8 val;
|
||||
|
||||
switch (mode) {
|
||||
case REGULATOR_MODE_NORMAL:
|
||||
val = SPMI_FTSMPS426_MODE_HPM_MASK;
|
||||
break;
|
||||
case REGULATOR_MODE_FAST:
|
||||
val = SPMI_FTSMPS426_MODE_AUTO_MASK;
|
||||
break;
|
||||
case REGULATOR_MODE_IDLE:
|
||||
val = SPMI_FTSMPS426_MODE_LPM_MASK;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -1266,6 +1383,21 @@ static struct regulator_ops spmi_ult_ldo_ops = {
|
|||
.set_soft_start = spmi_regulator_common_set_soft_start,
|
||||
};
|
||||
|
||||
static struct regulator_ops spmi_ftsmps426_ops = {
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.set_voltage_sel = spmi_regulator_ftsmps426_set_voltage,
|
||||
.set_voltage_time_sel = spmi_regulator_set_voltage_time_sel,
|
||||
.get_voltage_sel = spmi_regulator_ftsmps426_get_voltage,
|
||||
.map_voltage = spmi_regulator_single_map_voltage,
|
||||
.list_voltage = spmi_regulator_common_list_voltage,
|
||||
.set_mode = spmi_regulator_ftsmps426_set_mode,
|
||||
.get_mode = spmi_regulator_ftsmps426_get_mode,
|
||||
.set_load = spmi_regulator_common_set_load,
|
||||
.set_pull_down = spmi_regulator_common_set_pull_down,
|
||||
};
|
||||
|
||||
/* Maximum possible digital major revision value */
|
||||
#define INF 0xFF
|
||||
|
||||
|
@ -1301,6 +1433,7 @@ static const struct spmi_regulator_mapping supported_regulators[] = {
|
|||
SPMI_VREG(BOOST, 5V_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(FTS, FTS426_CTL, 0, INF, FTSMPS426, ftsmps426, ftsmps426, 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),
|
||||
|
@ -1438,6 +1571,34 @@ static int spmi_regulator_init_slew_rate(struct spmi_regulator *vreg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int spmi_regulator_init_slew_rate_ftsmps426(struct spmi_regulator *vreg)
|
||||
{
|
||||
int ret;
|
||||
u8 reg = 0;
|
||||
int delay, slew_rate;
|
||||
const struct spmi_voltage_range *range = &vreg->set_points->range[0];
|
||||
|
||||
ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_STEP_CTRL, ®, 1);
|
||||
if (ret) {
|
||||
dev_err(vreg->dev, "spmi read failed, ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
delay = reg & SPMI_FTSMPS426_STEP_CTRL_DELAY_MASK;
|
||||
delay >>= SPMI_FTSMPS426_STEP_CTRL_DELAY_SHIFT;
|
||||
|
||||
/* slew_rate has units of uV/us */
|
||||
slew_rate = SPMI_FTSMPS426_CLOCK_RATE * range->step_uV;
|
||||
slew_rate /= 1000 * (SPMI_FTSMPS426_STEP_DELAY << delay);
|
||||
slew_rate *= SPMI_FTSMPS426_STEP_MARGIN_NUM;
|
||||
slew_rate /= SPMI_FTSMPS426_STEP_MARGIN_DEN;
|
||||
|
||||
/* Ensure that the slew rate is greater than 0 */
|
||||
vreg->slew_rate = max(slew_rate, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spmi_regulator_init_registers(struct spmi_regulator *vreg,
|
||||
const struct spmi_regulator_init_data *data)
|
||||
{
|
||||
|
@ -1577,6 +1738,12 @@ static int spmi_regulator_of_parse(struct device_node *node,
|
|||
ret = spmi_regulator_init_slew_rate(vreg);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS426:
|
||||
ret = spmi_regulator_init_slew_rate_ftsmps426(vreg);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1733,7 +1900,16 @@ static const struct spmi_regulator_data pmi8994_regulators[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
static const struct spmi_regulator_data pm8005_regulators[] = {
|
||||
{ "s1", 0x1400, "vdd_s1", },
|
||||
{ "s2", 0x1700, "vdd_s2", },
|
||||
{ "s3", 0x1a00, "vdd_s3", },
|
||||
{ "s4", 0x1d00, "vdd_s4", },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct of_device_id qcom_spmi_regulator_match[] = {
|
||||
{ .compatible = "qcom,pm8005-regulators", .data = &pm8005_regulators },
|
||||
{ .compatible = "qcom,pm8841-regulators", .data = &pm8841_regulators },
|
||||
{ .compatible = "qcom,pm8916-regulators", .data = &pm8916_regulators },
|
||||
{ .compatible = "qcom,pm8941-regulators", .data = &pm8941_regulators },
|
||||
|
|
Loading…
Reference in a new issue