linux/drivers/regulator/bd71828-regulator.c
Matti Vaittinen 0f9f7c63c4
regulator: bd71828: Don't overwrite runtime voltages
Some of the regulators on the BD71828 have common voltage setting for
RUN/SUSPEND/IDLE/LPSR states. The enable control can be set for each
state though.

The driver allows setting the voltage values for these states via
device-tree. As a side effect, setting the voltages for
SUSPEND/IDLE/LPSR will also change the RUN level voltage which is not
desired and can break the system.

The comment in code reflects this behaviour, but it is likely to not
make people any happier. The right thing to do is to allow setting the
enable/disable state at SUSPEND/IDLE/LPSR via device-tree, but to
disallow setting state specific voltages for those regulators.

BUCK1 is a bit different. It only shares the SUSPEND and LPSR state
voltages. The former behaviour of allowing to silently overwrite the
SUSPEND state voltage by LPSR state voltage is also changed here so that
the SUSPEND voltage is prioritized over LPSR voltage.

Prevent setting PMIC state specific voltages for regulators which do not
support it.

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>
Fixes: 522498f8cb ("regulator: bd71828: Basic support for ROHM bd71828 PMIC regulators")
Link: https://msgid.link/r/e1883ae1e3ae5668f1030455d4750923561f3d68.1715848512.git.mazziesaccount@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2024-05-16 13:36:41 +01:00

731 lines
22 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2019 ROHM Semiconductors
// bd71828-regulator.c ROHM BD71828GW-DS1 regulator driver
//
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/rohm-bd71828.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
struct reg_init {
unsigned int reg;
unsigned int mask;
unsigned int val;
};
struct bd71828_regulator_data {
struct regulator_desc desc;
const struct rohm_dvs_config dvs;
const struct reg_init *reg_inits;
int reg_init_amnt;
};
static const struct reg_init buck1_inits[] = {
/*
* DVS Buck voltages can be changed by register values or via GPIO.
* Use register accesses by default.
*/
{
.reg = BD71828_REG_PS_CTRL_1,
.mask = BD71828_MASK_DVS_BUCK1_CTRL,
.val = BD71828_DVS_BUCK1_CTRL_I2C,
},
};
static const struct reg_init buck2_inits[] = {
{
.reg = BD71828_REG_PS_CTRL_1,
.mask = BD71828_MASK_DVS_BUCK2_CTRL,
.val = BD71828_DVS_BUCK2_CTRL_I2C,
},
};
static const struct reg_init buck6_inits[] = {
{
.reg = BD71828_REG_PS_CTRL_1,
.mask = BD71828_MASK_DVS_BUCK6_CTRL,
.val = BD71828_DVS_BUCK6_CTRL_I2C,
},
};
static const struct reg_init buck7_inits[] = {
{
.reg = BD71828_REG_PS_CTRL_1,
.mask = BD71828_MASK_DVS_BUCK7_CTRL,
.val = BD71828_DVS_BUCK7_CTRL_I2C,
},
};
static const struct linear_range bd71828_buck1267_volts[] = {
REGULATOR_LINEAR_RANGE(500000, 0x00, 0xef, 6250),
REGULATOR_LINEAR_RANGE(2000000, 0xf0, 0xff, 0),
};
static const struct linear_range bd71828_buck3_volts[] = {
REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x0f, 50000),
REGULATOR_LINEAR_RANGE(2000000, 0x10, 0x1f, 0),
};
static const struct linear_range bd71828_buck4_volts[] = {
REGULATOR_LINEAR_RANGE(1000000, 0x00, 0x1f, 25000),
REGULATOR_LINEAR_RANGE(1800000, 0x20, 0x3f, 0),
};
static const struct linear_range bd71828_buck5_volts[] = {
REGULATOR_LINEAR_RANGE(2500000, 0x00, 0x0f, 50000),
REGULATOR_LINEAR_RANGE(3300000, 0x10, 0x1f, 0),
};
static const struct linear_range bd71828_ldo_volts[] = {
REGULATOR_LINEAR_RANGE(800000, 0x00, 0x31, 50000),
REGULATOR_LINEAR_RANGE(3300000, 0x32, 0x3f, 0),
};
static const unsigned int bd71828_ramp_delay[] = { 2500, 5000, 10000, 20000 };
static int buck_set_hw_dvs_levels(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *cfg)
{
struct bd71828_regulator_data *data;
data = container_of(desc, struct bd71828_regulator_data, desc);
return rohm_regulator_set_dvs_levels(&data->dvs, np, desc, cfg->regmap);
}
static int ldo6_parse_dt(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *cfg)
{
int ret, i;
uint32_t uv = 0;
unsigned int en;
struct regmap *regmap = cfg->regmap;
static const char * const props[] = { "rohm,dvs-run-voltage",
"rohm,dvs-idle-voltage",
"rohm,dvs-suspend-voltage",
"rohm,dvs-lpsr-voltage" };
unsigned int mask[] = { BD71828_MASK_RUN_EN, BD71828_MASK_IDLE_EN,
BD71828_MASK_SUSP_EN, BD71828_MASK_LPSR_EN };
for (i = 0; i < ARRAY_SIZE(props); i++) {
ret = of_property_read_u32(np, props[i], &uv);
if (ret) {
if (ret != -EINVAL)
return ret;
continue;
}
if (uv)
en = 0xffffffff;
else
en = 0;
ret = regmap_update_bits(regmap, desc->enable_reg, mask[i], en);
if (ret)
return ret;
}
return 0;
}
static const struct regulator_ops bd71828_buck_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear_range,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
};
static const struct regulator_ops bd71828_dvs_buck_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear_range,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_ramp_delay = regulator_set_ramp_delay_regmap,
};
static const struct regulator_ops bd71828_ldo_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear_range,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
};
static const struct regulator_ops bd71828_ldo6_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
};
static const struct bd71828_regulator_data bd71828_rdata[] = {
{
.desc = {
.name = "buck1",
.of_match = of_match_ptr("BUCK1"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71828_BUCK1,
.ops = &bd71828_dvs_buck_ops,
.type = REGULATOR_VOLTAGE,
.linear_ranges = bd71828_buck1267_volts,
.n_linear_ranges = ARRAY_SIZE(bd71828_buck1267_volts),
.n_voltages = BD71828_BUCK1267_VOLTS,
.enable_reg = BD71828_REG_BUCK1_EN,
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK1_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
.ramp_delay_table = bd71828_ramp_delay,
.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
.ramp_reg = BD71828_REG_BUCK1_MODE,
.ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND |
ROHM_DVS_LEVEL_LPSR,
.run_reg = BD71828_REG_BUCK1_VOLT,
.run_mask = BD71828_MASK_BUCK1267_VOLT,
.idle_reg = BD71828_REG_BUCK1_IDLE_VOLT,
.idle_mask = BD71828_MASK_BUCK1267_VOLT,
.idle_on_mask = BD71828_MASK_IDLE_EN,
.suspend_reg = BD71828_REG_BUCK1_SUSP_VOLT,
.suspend_mask = BD71828_MASK_BUCK1267_VOLT,
.suspend_on_mask = BD71828_MASK_SUSP_EN,
/*
* LPSR voltage is same as SUSPEND voltage. Allow
* only enabling/disabling regulator for LPSR state
*/
.lpsr_on_mask = BD71828_MASK_LPSR_EN,
},
.reg_inits = buck1_inits,
.reg_init_amnt = ARRAY_SIZE(buck1_inits),
},
{
.desc = {
.name = "buck2",
.of_match = of_match_ptr("BUCK2"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71828_BUCK2,
.ops = &bd71828_dvs_buck_ops,
.type = REGULATOR_VOLTAGE,
.linear_ranges = bd71828_buck1267_volts,
.n_linear_ranges = ARRAY_SIZE(bd71828_buck1267_volts),
.n_voltages = BD71828_BUCK1267_VOLTS,
.enable_reg = BD71828_REG_BUCK2_EN,
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK2_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
.ramp_delay_table = bd71828_ramp_delay,
.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
.ramp_reg = BD71828_REG_BUCK2_MODE,
.ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND |
ROHM_DVS_LEVEL_LPSR,
.run_reg = BD71828_REG_BUCK2_VOLT,
.run_mask = BD71828_MASK_BUCK1267_VOLT,
.idle_reg = BD71828_REG_BUCK2_IDLE_VOLT,
.idle_mask = BD71828_MASK_BUCK1267_VOLT,
.idle_on_mask = BD71828_MASK_IDLE_EN,
.suspend_reg = BD71828_REG_BUCK2_SUSP_VOLT,
.suspend_mask = BD71828_MASK_BUCK1267_VOLT,
.suspend_on_mask = BD71828_MASK_SUSP_EN,
.lpsr_on_mask = BD71828_MASK_LPSR_EN,
.lpsr_reg = BD71828_REG_BUCK2_SUSP_VOLT,
.lpsr_mask = BD71828_MASK_BUCK1267_VOLT,
},
.reg_inits = buck2_inits,
.reg_init_amnt = ARRAY_SIZE(buck2_inits),
},
{
.desc = {
.name = "buck3",
.of_match = of_match_ptr("BUCK3"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71828_BUCK3,
.ops = &bd71828_buck_ops,
.type = REGULATOR_VOLTAGE,
.linear_ranges = bd71828_buck3_volts,
.n_linear_ranges = ARRAY_SIZE(bd71828_buck3_volts),
.n_voltages = BD71828_BUCK3_VOLTS,
.enable_reg = BD71828_REG_BUCK3_EN,
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK3_VOLT,
.vsel_mask = BD71828_MASK_BUCK3_VOLT,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
/*
* BUCK3 only supports single voltage for all states.
* voltage can be individually enabled for each state
* though => allow setting all states to support
* enabling power rail on different states.
*/
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND |
ROHM_DVS_LEVEL_LPSR,
.run_reg = BD71828_REG_BUCK3_VOLT,
.run_mask = BD71828_MASK_BUCK3_VOLT,
.idle_on_mask = BD71828_MASK_IDLE_EN,
.suspend_on_mask = BD71828_MASK_SUSP_EN,
.lpsr_on_mask = BD71828_MASK_LPSR_EN,
},
},
{
.desc = {
.name = "buck4",
.of_match = of_match_ptr("BUCK4"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71828_BUCK4,
.ops = &bd71828_buck_ops,
.type = REGULATOR_VOLTAGE,
.linear_ranges = bd71828_buck4_volts,
.n_linear_ranges = ARRAY_SIZE(bd71828_buck4_volts),
.n_voltages = BD71828_BUCK4_VOLTS,
.enable_reg = BD71828_REG_BUCK4_EN,
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK4_VOLT,
.vsel_mask = BD71828_MASK_BUCK4_VOLT,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
/*
* BUCK4 only supports single voltage for all states.
* voltage can be individually enabled for each state
* though => allow setting all states to support
* enabling power rail on different states.
*/
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND |
ROHM_DVS_LEVEL_LPSR,
.run_reg = BD71828_REG_BUCK4_VOLT,
.run_mask = BD71828_MASK_BUCK4_VOLT,
.idle_on_mask = BD71828_MASK_IDLE_EN,
.suspend_on_mask = BD71828_MASK_SUSP_EN,
.lpsr_on_mask = BD71828_MASK_LPSR_EN,
},
},
{
.desc = {
.name = "buck5",
.of_match = of_match_ptr("BUCK5"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71828_BUCK5,
.ops = &bd71828_buck_ops,
.type = REGULATOR_VOLTAGE,
.linear_ranges = bd71828_buck5_volts,
.n_linear_ranges = ARRAY_SIZE(bd71828_buck5_volts),
.n_voltages = BD71828_BUCK5_VOLTS,
.enable_reg = BD71828_REG_BUCK5_EN,
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK5_VOLT,
.vsel_mask = BD71828_MASK_BUCK5_VOLT,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
/*
* BUCK5 only supports single voltage for all states.
* voltage can be individually enabled for each state
* though => allow setting all states to support
* enabling power rail on different states.
*/
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND |
ROHM_DVS_LEVEL_LPSR,
.run_reg = BD71828_REG_BUCK5_VOLT,
.run_mask = BD71828_MASK_BUCK5_VOLT,
.idle_on_mask = BD71828_MASK_IDLE_EN,
.suspend_on_mask = BD71828_MASK_SUSP_EN,
.lpsr_on_mask = BD71828_MASK_LPSR_EN,
},
},
{
.desc = {
.name = "buck6",
.of_match = of_match_ptr("BUCK6"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71828_BUCK6,
.ops = &bd71828_dvs_buck_ops,
.type = REGULATOR_VOLTAGE,
.linear_ranges = bd71828_buck1267_volts,
.n_linear_ranges = ARRAY_SIZE(bd71828_buck1267_volts),
.n_voltages = BD71828_BUCK1267_VOLTS,
.enable_reg = BD71828_REG_BUCK6_EN,
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK6_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
.ramp_delay_table = bd71828_ramp_delay,
.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
.ramp_reg = BD71828_REG_BUCK6_MODE,
.ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND |
ROHM_DVS_LEVEL_LPSR,
.run_reg = BD71828_REG_BUCK6_VOLT,
.run_mask = BD71828_MASK_BUCK1267_VOLT,
.idle_reg = BD71828_REG_BUCK6_IDLE_VOLT,
.idle_mask = BD71828_MASK_BUCK1267_VOLT,
.idle_on_mask = BD71828_MASK_IDLE_EN,
.suspend_reg = BD71828_REG_BUCK6_SUSP_VOLT,
.suspend_mask = BD71828_MASK_BUCK1267_VOLT,
.suspend_on_mask = BD71828_MASK_SUSP_EN,
.lpsr_on_mask = BD71828_MASK_LPSR_EN,
.lpsr_reg = BD71828_REG_BUCK6_SUSP_VOLT,
.lpsr_mask = BD71828_MASK_BUCK1267_VOLT,
},
.reg_inits = buck6_inits,
.reg_init_amnt = ARRAY_SIZE(buck6_inits),
},
{
.desc = {
.name = "buck7",
.of_match = of_match_ptr("BUCK7"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71828_BUCK7,
.ops = &bd71828_dvs_buck_ops,
.type = REGULATOR_VOLTAGE,
.linear_ranges = bd71828_buck1267_volts,
.n_linear_ranges = ARRAY_SIZE(bd71828_buck1267_volts),
.n_voltages = BD71828_BUCK1267_VOLTS,
.enable_reg = BD71828_REG_BUCK7_EN,
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK7_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
.ramp_delay_table = bd71828_ramp_delay,
.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
.ramp_reg = BD71828_REG_BUCK7_MODE,
.ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND |
ROHM_DVS_LEVEL_LPSR,
.run_reg = BD71828_REG_BUCK7_VOLT,
.run_mask = BD71828_MASK_BUCK1267_VOLT,
.idle_reg = BD71828_REG_BUCK7_IDLE_VOLT,
.idle_mask = BD71828_MASK_BUCK1267_VOLT,
.idle_on_mask = BD71828_MASK_IDLE_EN,
.suspend_reg = BD71828_REG_BUCK7_SUSP_VOLT,
.suspend_mask = BD71828_MASK_BUCK1267_VOLT,
.suspend_on_mask = BD71828_MASK_SUSP_EN,
.lpsr_on_mask = BD71828_MASK_LPSR_EN,
.lpsr_reg = BD71828_REG_BUCK7_SUSP_VOLT,
.lpsr_mask = BD71828_MASK_BUCK1267_VOLT,
},
.reg_inits = buck7_inits,
.reg_init_amnt = ARRAY_SIZE(buck7_inits),
},
{
.desc = {
.name = "ldo1",
.of_match = of_match_ptr("LDO1"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71828_LDO1,
.ops = &bd71828_ldo_ops,
.type = REGULATOR_VOLTAGE,
.linear_ranges = bd71828_ldo_volts,
.n_linear_ranges = ARRAY_SIZE(bd71828_ldo_volts),
.n_voltages = BD71828_LDO_VOLTS,
.enable_reg = BD71828_REG_LDO1_EN,
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_LDO1_VOLT,
.vsel_mask = BD71828_MASK_LDO_VOLT,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
/*
* LDO1 only supports single voltage for all states.
* voltage can be individually enabled for each state
* though => allow setting all states to support
* enabling power rail on different states.
*/
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND |
ROHM_DVS_LEVEL_LPSR,
.run_reg = BD71828_REG_LDO1_VOLT,
.run_mask = BD71828_MASK_LDO_VOLT,
.idle_on_mask = BD71828_MASK_IDLE_EN,
.suspend_on_mask = BD71828_MASK_SUSP_EN,
.lpsr_on_mask = BD71828_MASK_LPSR_EN,
},
}, {
.desc = {
.name = "ldo2",
.of_match = of_match_ptr("LDO2"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71828_LDO2,
.ops = &bd71828_ldo_ops,
.type = REGULATOR_VOLTAGE,
.linear_ranges = bd71828_ldo_volts,
.n_linear_ranges = ARRAY_SIZE(bd71828_ldo_volts),
.n_voltages = BD71828_LDO_VOLTS,
.enable_reg = BD71828_REG_LDO2_EN,
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_LDO2_VOLT,
.vsel_mask = BD71828_MASK_LDO_VOLT,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
/*
* LDO2 only supports single voltage for all states.
* voltage can be individually enabled for each state
* though => allow setting all states to support
* enabling power rail on different states.
*/
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND |
ROHM_DVS_LEVEL_LPSR,
.run_reg = BD71828_REG_LDO2_VOLT,
.run_mask = BD71828_MASK_LDO_VOLT,
.idle_on_mask = BD71828_MASK_IDLE_EN,
.suspend_on_mask = BD71828_MASK_SUSP_EN,
.lpsr_on_mask = BD71828_MASK_LPSR_EN,
},
}, {
.desc = {
.name = "ldo3",
.of_match = of_match_ptr("LDO3"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71828_LDO3,
.ops = &bd71828_ldo_ops,
.type = REGULATOR_VOLTAGE,
.linear_ranges = bd71828_ldo_volts,
.n_linear_ranges = ARRAY_SIZE(bd71828_ldo_volts),
.n_voltages = BD71828_LDO_VOLTS,
.enable_reg = BD71828_REG_LDO3_EN,
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_LDO3_VOLT,
.vsel_mask = BD71828_MASK_LDO_VOLT,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
/*
* LDO3 only supports single voltage for all states.
* voltage can be individually enabled for each state
* though => allow setting all states to support
* enabling power rail on different states.
*/
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND |
ROHM_DVS_LEVEL_LPSR,
.run_reg = BD71828_REG_LDO3_VOLT,
.run_mask = BD71828_MASK_LDO_VOLT,
.idle_on_mask = BD71828_MASK_IDLE_EN,
.suspend_on_mask = BD71828_MASK_SUSP_EN,
.lpsr_on_mask = BD71828_MASK_LPSR_EN,
},
}, {
.desc = {
.name = "ldo4",
.of_match = of_match_ptr("LDO4"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71828_LDO4,
.ops = &bd71828_ldo_ops,
.type = REGULATOR_VOLTAGE,
.linear_ranges = bd71828_ldo_volts,
.n_linear_ranges = ARRAY_SIZE(bd71828_ldo_volts),
.n_voltages = BD71828_LDO_VOLTS,
.enable_reg = BD71828_REG_LDO4_EN,
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_LDO4_VOLT,
.vsel_mask = BD71828_MASK_LDO_VOLT,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
/*
* LDO1 only supports single voltage for all states.
* voltage can be individually enabled for each state
* though => allow setting all states to support
* enabling power rail on different states.
*/
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND |
ROHM_DVS_LEVEL_LPSR,
.run_reg = BD71828_REG_LDO4_VOLT,
.run_mask = BD71828_MASK_LDO_VOLT,
.idle_on_mask = BD71828_MASK_IDLE_EN,
.suspend_on_mask = BD71828_MASK_SUSP_EN,
.lpsr_on_mask = BD71828_MASK_LPSR_EN,
},
}, {
.desc = {
.name = "ldo5",
.of_match = of_match_ptr("LDO5"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71828_LDO5,
.ops = &bd71828_ldo_ops,
.type = REGULATOR_VOLTAGE,
.linear_ranges = bd71828_ldo_volts,
.n_linear_ranges = ARRAY_SIZE(bd71828_ldo_volts),
.n_voltages = BD71828_LDO_VOLTS,
.enable_reg = BD71828_REG_LDO5_EN,
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_LDO5_VOLT,
.vsel_mask = BD71828_MASK_LDO_VOLT,
.of_parse_cb = buck_set_hw_dvs_levels,
.owner = THIS_MODULE,
},
/*
* LDO5 is special. It can choose vsel settings to be configured
* from 2 different registers (by GPIO).
*
* This driver supports only configuration where
* BD71828_REG_LDO5_VOLT_L is used.
*/
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND |
ROHM_DVS_LEVEL_LPSR,
.run_reg = BD71828_REG_LDO5_VOLT,
.run_mask = BD71828_MASK_LDO_VOLT,
.idle_on_mask = BD71828_MASK_IDLE_EN,
.suspend_on_mask = BD71828_MASK_SUSP_EN,
.lpsr_on_mask = BD71828_MASK_LPSR_EN,
},
}, {
.desc = {
.name = "ldo6",
.of_match = of_match_ptr("LDO6"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71828_LDO6,
.ops = &bd71828_ldo6_ops,
.type = REGULATOR_VOLTAGE,
.fixed_uV = BD71828_LDO_6_VOLTAGE,
.n_voltages = 1,
.enable_reg = BD71828_REG_LDO6_EN,
.enable_mask = BD71828_MASK_RUN_EN,
.owner = THIS_MODULE,
/*
* LDO6 only supports enable/disable for all states.
* Voltage for LDO6 is fixed.
*/
.of_parse_cb = ldo6_parse_dt,
},
}, {
.desc = {
/* SNVS LDO in data-sheet */
.name = "ldo7",
.of_match = of_match_ptr("LDO7"),
.regulators_node = of_match_ptr("regulators"),
.id = BD71828_LDO_SNVS,
.ops = &bd71828_ldo_ops,
.type = REGULATOR_VOLTAGE,
.linear_ranges = bd71828_ldo_volts,
.n_linear_ranges = ARRAY_SIZE(bd71828_ldo_volts),
.n_voltages = BD71828_LDO_VOLTS,
.enable_reg = BD71828_REG_LDO7_EN,
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_LDO7_VOLT,
.vsel_mask = BD71828_MASK_LDO_VOLT,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
/*
* LDO7 only supports single voltage for all states.
* voltage can be individually enabled for each state
* though => allow setting all states to support
* enabling power rail on different states.
*/
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND |
ROHM_DVS_LEVEL_LPSR,
.run_reg = BD71828_REG_LDO7_VOLT,
.idle_reg = BD71828_REG_LDO7_VOLT,
.suspend_reg = BD71828_REG_LDO7_VOLT,
.lpsr_reg = BD71828_REG_LDO7_VOLT,
.run_mask = BD71828_MASK_LDO_VOLT,
.idle_on_mask = BD71828_MASK_IDLE_EN,
.suspend_on_mask = BD71828_MASK_SUSP_EN,
.lpsr_on_mask = BD71828_MASK_LPSR_EN,
},
},
};
static int bd71828_probe(struct platform_device *pdev)
{
int i, j, ret;
struct regulator_config config = {
.dev = pdev->dev.parent,
};
config.regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!config.regmap)
return -ENODEV;
for (i = 0; i < ARRAY_SIZE(bd71828_rdata); i++) {
struct regulator_dev *rdev;
const struct bd71828_regulator_data *rd;
rd = &bd71828_rdata[i];
rdev = devm_regulator_register(&pdev->dev,
&rd->desc, &config);
if (IS_ERR(rdev))
return dev_err_probe(&pdev->dev, PTR_ERR(rdev),
"failed to register %s regulator\n",
rd->desc.name);
for (j = 0; j < rd->reg_init_amnt; j++) {
ret = regmap_update_bits(config.regmap,
rd->reg_inits[j].reg,
rd->reg_inits[j].mask,
rd->reg_inits[j].val);
if (ret)
return dev_err_probe(&pdev->dev, ret,
"regulator %s init failed\n",
rd->desc.name);
}
}
return 0;
}
static struct platform_driver bd71828_regulator = {
.driver = {
.name = "bd71828-pmic",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = bd71828_probe,
};
module_platform_driver(bd71828_regulator);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("BD71828 voltage regulator driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:bd71828-pmic");