Merge tag 'regulator-v4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator

Pull regulator updates from Mark Brown:
 "This is a quiet release in terms of code volume but a fairly big one
  in terms of framework changes - we've got one long awaited feature in
  the form of runtime configuration of suspend and the start of coupled
  regulator support too:

   - Support for modifying the voltage and enable configuration devices
     will have in suspend, contributed by Chunyan Zhang.

   - Support for the Spreadtrum SC2731, contributed by Erick Chen.

   - The start of changes to support coupled regulators from Maciej
     Purski, the rest of the series should arrive for v4.17"

* tag 'regulator-v4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator:
  regulator: Fix build error
  regulator: core: Refactor regulator_list_voltage()
  regulator: core: Move of_find_regulator_by_node() to of_regulator.c
  regulator: add PM suspend and resume hooks
  regulator: empty the old suspend functions
  regulator: leave one item to record whether regulator is enabled
  regulator: make regulator voltage be an array to support more states
  regulator: added support for suspend states
  regulator: qcom_spmi: Use regmap helpers for enable/disable/is_enabled callback
  regulator: sc2731: Fix defines for SC2731_WR_UNLOCK and SC2731_PWR_WR_PROT_VALUE
  regulator: fix incorrect indentation of two assignment statements
  regulator: sc2731: Add regulator driver to support Spreadtrum SC2731 PMIC
  regulator: Add Spreadtrum SC2731 regulator documentation
  regulator: Update code examples in documentation
  MAINTAINERS: regulator: Add Documentation/power/regulator/
  regulator: tps65218: Add NULL test for devm_kzalloc call
  regulator: tps65218: Remove unused enum tps65218_regulators
This commit is contained in:
Linus Torvalds
2018-01-29 11:32:44 -08:00
14 changed files with 698 additions and 232 deletions
@@ -42,8 +42,16 @@ Optional properties:
- regulator-state-[mem/disk] node has following common properties:
- regulator-on-in-suspend: regulator should be on in suspend state.
- regulator-off-in-suspend: regulator should be off in suspend state.
- regulator-suspend-microvolt: regulator should be set to this voltage
in suspend.
- regulator-suspend-min-microvolt: minimum voltage may be set in
suspend state.
- regulator-suspend-max-microvolt: maximum voltage may be set in
suspend state.
- regulator-suspend-microvolt: the default voltage which regulator
would be set in suspend. This property is now deprecated, instead
setting voltage for suspend mode via the API which regulator
driver provides is recommended.
- regulator-changeable-in-suspend: whether the default voltage and
the regulator on/off in suspend can be changed in runtime.
- regulator-mode: operating mode in the given suspend state.
The set of possible operating modes depends on the capabilities of
every hardware so the valid modes are documented on each regulator
@@ -0,0 +1,43 @@
Spreadtrum SC2731 Voltage regulators
The SC2731 integrates low-voltage and low quiescent current DCDC/LDO.
14 LDO and 3 DCDCs are designed for external use. All DCDCs/LDOs have
their own bypass (power-down) control signals. External tantalum or MLCC
ceramic capacitors are recommended to use with these LDOs.
Required properties:
- compatible: should be "sprd,sc27xx-regulator".
List of regulators provided by this controller. It is named according to
its regulator type, BUCK_<name> and LDO_<name>. The definition for each
of these nodes is defined using the standard binding for regulators at
Documentation/devicetree/bindings/regulator/regulator.txt.
The valid names for regulators are:
BUCK:
BUCK_CPU0, BUCK_CPU1, BUCK_RF
LDO:
LDO_CAMA0, LDO_CAMA1, LDO_CAMMOT, LDO_VLDO, LDO_EMMCCORE, LDO_SDCORE,
LDO_SDIO, LDO_WIFIPA, LDO_USB33, LDO_CAMD0, LDO_CAMD1, LDO_CON,
LDO_CAMIO, LDO_SRAM
Example:
regulators {
compatible = "sprd,sc27xx-regulator";
vddarm0: BUCK_CPU0 {
regulator-name = "vddarm0";
regulator-min-microvolt = <400000>;
regulator-max-microvolt = <1996875>;
regulator-ramp-delay = <25000>;
regulator-always-on;
};
vddcama0: LDO_CAMA0 {
regulator-name = "vddcama0";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3750000>;
regulator-enable-ramp-delay = <100>;
};
...
};
+16 -20
View File
@@ -23,16 +23,12 @@ struct regulator_consumer_supply {
e.g. for the machine above
static struct regulator_consumer_supply regulator1_consumers[] = {
{
.dev_name = "dev_name(consumer B)",
.supply = "Vcc",
},};
REGULATOR_SUPPLY("Vcc", "consumer B"),
};
static struct regulator_consumer_supply regulator2_consumers[] = {
{
.dev = "dev_name(consumer A"),
.supply = "Vcc",
},};
REGULATOR_SUPPLY("Vcc", "consumer A"),
};
This maps Regulator-1 to the 'Vcc' supply for Consumer B and maps Regulator-2
to the 'Vcc' supply for Consumer A.
@@ -78,20 +74,20 @@ static struct regulator_init_data regulator2_data = {
Finally the regulator devices must be registered in the usual manner.
static struct platform_device regulator_devices[] = {
{
.name = "regulator",
.id = DCDC_1,
.dev = {
.platform_data = &regulator1_data,
{
.name = "regulator",
.id = DCDC_1,
.dev = {
.platform_data = &regulator1_data,
},
},
},
{
.name = "regulator",
.id = DCDC_2,
.dev = {
.platform_data = &regulator2_data,
{
.name = "regulator",
.id = DCDC_2,
.dev = {
.platform_data = &regulator2_data,
},
},
},
};
/* register regulator 1 device */
platform_device_register(&regulator_devices[0]);
+1
View File
@@ -14670,6 +14670,7 @@ W: http://www.slimlogic.co.uk/?p=48
T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git
S: Supported
F: Documentation/devicetree/bindings/regulator/
F: Documentation/power/regulator/
F: drivers/regulator/
F: include/dt-bindings/regulator/
F: include/linux/regulator/
+7
View File
@@ -744,6 +744,13 @@ config REGULATOR_S5M8767
via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
supports DVS mode with 8bits of output voltage control.
config REGULATOR_SC2731
tristate "Spreadtrum SC2731 power regulator driver"
depends on MFD_SC27XX_PMIC || COMPILE_TEST
help
This driver provides support for the voltage regulators on the
SC2731 PMIC.
config REGULATOR_SKY81452
tristate "Skyworks Solutions SKY81452 voltage regulator"
depends on MFD_SKY81452
+1
View File
@@ -95,6 +95,7 @@ obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o
obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o
obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
+245 -140
View File
@@ -58,8 +58,6 @@ static bool has_full_constraints;
static struct dentry *debugfs_root;
static struct class regulator_class;
/*
* struct regulator_map
*
@@ -112,11 +110,6 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
const char *supply_name);
static void _regulator_put(struct regulator *regulator);
static struct regulator_dev *dev_to_rdev(struct device *dev)
{
return container_of(dev, struct regulator_dev, dev);
}
static const char *rdev_get_name(struct regulator_dev *rdev)
{
if (rdev->constraints && rdev->constraints->name)
@@ -236,26 +229,35 @@ static int regulator_check_voltage(struct regulator_dev *rdev,
return 0;
}
/* return 0 if the state is valid */
static int regulator_check_states(suspend_state_t state)
{
return (state > PM_SUSPEND_MAX || state == PM_SUSPEND_TO_IDLE);
}
/* Make sure we select a voltage that suits the needs of all
* regulator consumers
*/
static int regulator_check_consumers(struct regulator_dev *rdev,
int *min_uV, int *max_uV)
int *min_uV, int *max_uV,
suspend_state_t state)
{
struct regulator *regulator;
struct regulator_voltage *voltage;
list_for_each_entry(regulator, &rdev->consumer_list, list) {
voltage = &regulator->voltage[state];
/*
* Assume consumers that didn't say anything are OK
* with anything in the constraint range.
*/
if (!regulator->min_uV && !regulator->max_uV)
if (!voltage->min_uV && !voltage->max_uV)
continue;
if (*max_uV > regulator->max_uV)
*max_uV = regulator->max_uV;
if (*min_uV < regulator->min_uV)
*min_uV = regulator->min_uV;
if (*max_uV > voltage->max_uV)
*max_uV = voltage->max_uV;
if (*min_uV < voltage->min_uV)
*min_uV = voltage->min_uV;
}
if (*min_uV > *max_uV) {
@@ -324,6 +326,24 @@ static int regulator_mode_constrain(struct regulator_dev *rdev,
return -EINVAL;
}
static inline struct regulator_state *
regulator_get_suspend_state(struct regulator_dev *rdev, suspend_state_t state)
{
if (rdev->constraints == NULL)
return NULL;
switch (state) {
case PM_SUSPEND_STANDBY:
return &rdev->constraints->state_standby;
case PM_SUSPEND_MEM:
return &rdev->constraints->state_mem;
case PM_SUSPEND_MAX:
return &rdev->constraints->state_disk;
default:
return NULL;
}
}
static ssize_t regulator_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -731,29 +751,32 @@ static int drms_uA_update(struct regulator_dev *rdev)
}
static int suspend_set_state(struct regulator_dev *rdev,
struct regulator_state *rstate)
suspend_state_t state)
{
int ret = 0;
struct regulator_state *rstate;
rstate = regulator_get_suspend_state(rdev, state);
if (rstate == NULL)
return -EINVAL;
/* If we have no suspend mode configration don't set anything;
* only warn if the driver implements set_suspend_voltage or
* set_suspend_mode callback.
*/
if (!rstate->enabled && !rstate->disabled) {
if (rstate->enabled != ENABLE_IN_SUSPEND &&
rstate->enabled != DISABLE_IN_SUSPEND) {
if (rdev->desc->ops->set_suspend_voltage ||
rdev->desc->ops->set_suspend_mode)
rdev_warn(rdev, "No configuration\n");
return 0;
}
if (rstate->enabled && rstate->disabled) {
rdev_err(rdev, "invalid configuration\n");
return -EINVAL;
}
if (rstate->enabled && rdev->desc->ops->set_suspend_enable)
if (rstate->enabled == ENABLE_IN_SUSPEND &&
rdev->desc->ops->set_suspend_enable)
ret = rdev->desc->ops->set_suspend_enable(rdev);
else if (rstate->disabled && rdev->desc->ops->set_suspend_disable)
else if (rstate->enabled == DISABLE_IN_SUSPEND &&
rdev->desc->ops->set_suspend_disable)
ret = rdev->desc->ops->set_suspend_disable(rdev);
else /* OK if set_suspend_enable or set_suspend_disable is NULL */
ret = 0;
@@ -778,30 +801,10 @@ static int suspend_set_state(struct regulator_dev *rdev,
return ret;
}
}
return ret;
}
/* locks held by caller */
static int suspend_prepare(struct regulator_dev *rdev, suspend_state_t state)
{
if (!rdev->constraints)
return -EINVAL;
switch (state) {
case PM_SUSPEND_STANDBY:
return suspend_set_state(rdev,
&rdev->constraints->state_standby);
case PM_SUSPEND_MEM:
return suspend_set_state(rdev,
&rdev->constraints->state_mem);
case PM_SUSPEND_MAX:
return suspend_set_state(rdev,
&rdev->constraints->state_disk);
default:
return -EINVAL;
}
}
static void print_constraints(struct regulator_dev *rdev)
{
struct regulation_constraints *constraints = rdev->constraints;
@@ -1068,7 +1071,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
/* do we need to setup our suspend state */
if (rdev->constraints->initial_state) {
ret = suspend_prepare(rdev, rdev->constraints->initial_state);
ret = suspend_set_state(rdev, rdev->constraints->initial_state);
if (ret < 0) {
rdev_err(rdev, "failed to set suspend state\n");
return ret;
@@ -1356,9 +1359,9 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
debugfs_create_u32("uA_load", 0444, regulator->debugfs,
&regulator->uA_load);
debugfs_create_u32("min_uV", 0444, regulator->debugfs,
&regulator->min_uV);
&regulator->voltage[PM_SUSPEND_ON].min_uV);
debugfs_create_u32("max_uV", 0444, regulator->debugfs,
&regulator->max_uV);
&regulator->voltage[PM_SUSPEND_ON].max_uV);
debugfs_create_file("constraint_flags", 0444,
regulator->debugfs, regulator,
&constraint_flags_fops);
@@ -1417,20 +1420,6 @@ static void regulator_supply_alias(struct device **dev, const char **supply)
}
}
static int of_node_match(struct device *dev, const void *data)
{
return dev->of_node == data;
}
static struct regulator_dev *of_find_regulator_by_node(struct device_node *np)
{
struct device *dev;
dev = class_find_device(&regulator_class, NULL, np, of_node_match);
return dev ? dev_to_rdev(dev) : NULL;
}
static int regulator_match(struct device *dev, const void *data)
{
struct regulator_dev *r = dev_to_rdev(dev);
@@ -2468,10 +2457,9 @@ static int _regulator_is_enabled(struct regulator_dev *rdev)
return rdev->desc->ops->is_enabled(rdev);
}
static int _regulator_list_voltage(struct regulator *regulator,
unsigned selector, int lock)
static int _regulator_list_voltage(struct regulator_dev *rdev,
unsigned selector, int lock)
{
struct regulator_dev *rdev = regulator->rdev;
const struct regulator_ops *ops = rdev->desc->ops;
int ret;
@@ -2487,7 +2475,8 @@ static int _regulator_list_voltage(struct regulator *regulator,
if (lock)
mutex_unlock(&rdev->mutex);
} else if (rdev->is_switch && rdev->supply) {
ret = _regulator_list_voltage(rdev->supply, selector, lock);
ret = _regulator_list_voltage(rdev->supply->rdev,
selector, lock);
} else {
return -EINVAL;
}
@@ -2563,7 +2552,7 @@ EXPORT_SYMBOL_GPL(regulator_count_voltages);
*/
int regulator_list_voltage(struct regulator *regulator, unsigned selector)
{
return _regulator_list_voltage(regulator, selector, 1);
return _regulator_list_voltage(regulator->rdev, selector, 1);
}
EXPORT_SYMBOL_GPL(regulator_list_voltage);
@@ -2605,8 +2594,8 @@ int regulator_get_hardware_vsel_register(struct regulator *regulator,
if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap)
return -EOPNOTSUPP;
*vsel_reg = rdev->desc->vsel_reg;
*vsel_mask = rdev->desc->vsel_mask;
*vsel_reg = rdev->desc->vsel_reg;
*vsel_mask = rdev->desc->vsel_mask;
return 0;
}
@@ -2897,10 +2886,38 @@ out:
return ret;
}
static int _regulator_do_set_suspend_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV, suspend_state_t state)
{
struct regulator_state *rstate;
int uV, sel;
rstate = regulator_get_suspend_state(rdev, state);
if (rstate == NULL)
return -EINVAL;
if (min_uV < rstate->min_uV)
min_uV = rstate->min_uV;
if (max_uV > rstate->max_uV)
max_uV = rstate->max_uV;
sel = regulator_map_voltage(rdev, min_uV, max_uV);
if (sel < 0)
return sel;
uV = rdev->desc->ops->list_voltage(rdev, sel);
if (uV >= min_uV && uV <= max_uV)
rstate->uV = uV;
return 0;
}
static int regulator_set_voltage_unlocked(struct regulator *regulator,
int min_uV, int max_uV)
int min_uV, int max_uV,
suspend_state_t state)
{
struct regulator_dev *rdev = regulator->rdev;
struct regulator_voltage *voltage = &regulator->voltage[state];
int ret = 0;
int old_min_uV, old_max_uV;
int current_uV;
@@ -2911,7 +2928,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
* should be a noop (some cpufreq implementations use the same
* voltage for multiple frequencies, for example).
*/
if (regulator->min_uV == min_uV && regulator->max_uV == max_uV)
if (voltage->min_uV == min_uV && voltage->max_uV == max_uV)
goto out;
/* If we're trying to set a range that overlaps the current voltage,
@@ -2921,8 +2938,8 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
current_uV = _regulator_get_voltage(rdev);
if (min_uV <= current_uV && current_uV <= max_uV) {
regulator->min_uV = min_uV;
regulator->max_uV = max_uV;
voltage->min_uV = min_uV;
voltage->max_uV = max_uV;
goto out;
}
}
@@ -2940,12 +2957,12 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
goto out;
/* restore original values in case of error */
old_min_uV = regulator->min_uV;
old_max_uV = regulator->max_uV;
regulator->min_uV = min_uV;
regulator->max_uV = max_uV;
old_min_uV = voltage->min_uV;
old_max_uV = voltage->max_uV;
voltage->min_uV = min_uV;
voltage->max_uV = max_uV;
ret = regulator_check_consumers(rdev, &min_uV, &max_uV);
ret = regulator_check_consumers(rdev, &min_uV, &max_uV, state);
if (ret < 0)
goto out2;
@@ -2963,7 +2980,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
goto out2;
}
best_supply_uV = _regulator_list_voltage(regulator, selector, 0);
best_supply_uV = _regulator_list_voltage(rdev, selector, 0);
if (best_supply_uV < 0) {
ret = best_supply_uV;
goto out2;
@@ -2982,7 +2999,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
if (supply_change_uV > 0) {
ret = regulator_set_voltage_unlocked(rdev->supply,
best_supply_uV, INT_MAX);
best_supply_uV, INT_MAX, state);
if (ret) {
dev_err(&rdev->dev, "Failed to increase supply voltage: %d\n",
ret);
@@ -2990,13 +3007,17 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
}
}
ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
if (state == PM_SUSPEND_ON)
ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
else
ret = _regulator_do_set_suspend_voltage(rdev, min_uV,
max_uV, state);
if (ret < 0)
goto out2;
if (supply_change_uV < 0) {
ret = regulator_set_voltage_unlocked(rdev->supply,
best_supply_uV, INT_MAX);
best_supply_uV, INT_MAX, state);
if (ret)
dev_warn(&rdev->dev, "Failed to decrease supply voltage: %d\n",
ret);
@@ -3007,8 +3028,8 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
out:
return ret;
out2:
regulator->min_uV = old_min_uV;
regulator->max_uV = old_max_uV;
voltage->min_uV = old_min_uV;
voltage->max_uV = old_max_uV;
return ret;
}
@@ -3037,7 +3058,8 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
regulator_lock_supply(regulator->rdev);
ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV);
ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV,
PM_SUSPEND_ON);
regulator_unlock_supply(regulator->rdev);
@@ -3045,6 +3067,89 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
}
EXPORT_SYMBOL_GPL(regulator_set_voltage);
static inline int regulator_suspend_toggle(struct regulator_dev *rdev,
suspend_state_t state, bool en)
{
struct regulator_state *rstate;
rstate = regulator_get_suspend_state(rdev, state);
if (rstate == NULL)
return -EINVAL;
if (!rstate->changeable)
return -EPERM;
rstate->enabled = en;
return 0;
}
int regulator_suspend_enable(struct regulator_dev *rdev,
suspend_state_t state)
{
return regulator_suspend_toggle(rdev, state, true);
}
EXPORT_SYMBOL_GPL(regulator_suspend_enable);
int regulator_suspend_disable(struct regulator_dev *rdev,
suspend_state_t state)
{
struct regulator *regulator;
struct regulator_voltage *voltage;
/*
* if any consumer wants this regulator device keeping on in
* suspend states, don't set it as disabled.
*/
list_for_each_entry(regulator, &rdev->consumer_list, list) {
voltage = &regulator->voltage[state];
if (voltage->min_uV || voltage->max_uV)
return 0;
}
return regulator_suspend_toggle(rdev, state, false);
}
EXPORT_SYMBOL_GPL(regulator_suspend_disable);
static int _regulator_set_suspend_voltage(struct regulator *regulator,
int min_uV, int max_uV,
suspend_state_t state)
{
struct regulator_dev *rdev = regulator->rdev;
struct regulator_state *rstate;
rstate = regulator_get_suspend_state(rdev, state);
if (rstate == NULL)
return -EINVAL;
if (rstate->min_uV == rstate->max_uV) {
rdev_err(rdev, "The suspend voltage can't be changed!\n");
return -EPERM;
}
return regulator_set_voltage_unlocked(regulator, min_uV, max_uV, state);
}
int regulator_set_suspend_voltage(struct regulator *regulator, int min_uV,
int max_uV, suspend_state_t state)
{
int ret = 0;
/* PM_SUSPEND_ON is handled by regulator_set_voltage() */
if (regulator_check_states(state) || state == PM_SUSPEND_ON)
return -EINVAL;
regulator_lock_supply(regulator->rdev);
ret = _regulator_set_suspend_voltage(regulator, min_uV,
max_uV, state);
regulator_unlock_supply(regulator->rdev);
return ret;
}
EXPORT_SYMBOL_GPL(regulator_set_suspend_voltage);
/**
* regulator_set_voltage_time - get raise/fall time
* @regulator: regulator source
@@ -3138,6 +3243,7 @@ EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel);
int regulator_sync_voltage(struct regulator *regulator)
{
struct regulator_dev *rdev = regulator->rdev;
struct regulator_voltage *voltage = &regulator->voltage[PM_SUSPEND_ON];
int ret, min_uV, max_uV;
mutex_lock(&rdev->mutex);
@@ -3149,20 +3255,20 @@ int regulator_sync_voltage(struct regulator *regulator)
}
/* This is only going to work if we've had a voltage configured. */
if (!regulator->min_uV && !regulator->max_uV) {
if (!voltage->min_uV && !voltage->max_uV) {
ret = -EINVAL;
goto out;
}
min_uV = regulator->min_uV;
max_uV = regulator->max_uV;
min_uV = voltage->min_uV;
max_uV = voltage->max_uV;
/* This should be a paranoia check... */
ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
if (ret < 0)
goto out;
ret = regulator_check_consumers(rdev, &min_uV, &max_uV);
ret = regulator_check_consumers(rdev, &min_uV, &max_uV, 0);
if (ret < 0)
goto out;
@@ -3918,12 +4024,6 @@ static void regulator_dev_release(struct device *dev)
kfree(rdev);
}
static struct class regulator_class = {
.name = "regulator",
.dev_release = regulator_dev_release,
.dev_groups = regulator_dev_groups,
};
static void rdev_init_debugfs(struct regulator_dev *rdev)
{
struct device *parent = rdev->dev.parent;
@@ -4174,81 +4274,86 @@ void regulator_unregister(struct regulator_dev *rdev)
}
EXPORT_SYMBOL_GPL(regulator_unregister);
static int _regulator_suspend_prepare(struct device *dev, void *data)
#ifdef CONFIG_SUSPEND
static int _regulator_suspend_late(struct device *dev, void *data)
{
struct regulator_dev *rdev = dev_to_rdev(dev);
const suspend_state_t *state = data;
suspend_state_t *state = data;
int ret;
mutex_lock(&rdev->mutex);
ret = suspend_prepare(rdev, *state);
ret = suspend_set_state(rdev, *state);
mutex_unlock(&rdev->mutex);
return ret;
}
/**
* regulator_suspend_prepare - prepare regulators for system wide suspend
* regulator_suspend_late - prepare regulators for system wide suspend
* @state: system suspend state
*
* Configure each regulator with it's suspend operating parameters for state.
* This will usually be called by machine suspend code prior to supending.
*/
int regulator_suspend_prepare(suspend_state_t state)
static int regulator_suspend_late(struct device *dev)
{
/* ON is handled by regulator active state */
if (state == PM_SUSPEND_ON)
return -EINVAL;
suspend_state_t state = pm_suspend_target_state;
return class_for_each_device(&regulator_class, NULL, &state,
_regulator_suspend_prepare);
_regulator_suspend_late);
}
EXPORT_SYMBOL_GPL(regulator_suspend_prepare);
static int _regulator_suspend_finish(struct device *dev, void *data)
static int _regulator_resume_early(struct device *dev, void *data)
{
int ret = 0;
struct regulator_dev *rdev = dev_to_rdev(dev);
int ret;
suspend_state_t *state = data;
struct regulator_state *rstate;
rstate = regulator_get_suspend_state(rdev, *state);
if (rstate == NULL)
return -EINVAL;
mutex_lock(&rdev->mutex);
if (rdev->use_count > 0 || rdev->constraints->always_on) {
if (!_regulator_is_enabled(rdev)) {
ret = _regulator_do_enable(rdev);
if (ret)
dev_err(dev,
"Failed to resume regulator %d\n",
ret);
}
} else {
if (!have_full_constraints())
goto unlock;
if (!_regulator_is_enabled(rdev))
goto unlock;
ret = _regulator_do_disable(rdev);
if (ret)
dev_err(dev, "Failed to suspend regulator %d\n", ret);
}
unlock:
if (rdev->desc->ops->resume_early &&
(rstate->enabled == ENABLE_IN_SUSPEND ||
rstate->enabled == DISABLE_IN_SUSPEND))
ret = rdev->desc->ops->resume_early(rdev);
mutex_unlock(&rdev->mutex);
/* Keep processing regulators in spite of any errors */
return 0;
return ret;
}
/**
* regulator_suspend_finish - resume regulators from system wide suspend
*
* Turn on regulators that might be turned off by regulator_suspend_prepare
* and that should be turned on according to the regulators properties.
*/
int regulator_suspend_finish(void)
static int regulator_resume_early(struct device *dev)
{
return class_for_each_device(&regulator_class, NULL, NULL,
_regulator_suspend_finish);
}
EXPORT_SYMBOL_GPL(regulator_suspend_finish);
suspend_state_t state = pm_suspend_target_state;
return class_for_each_device(&regulator_class, NULL, &state,
_regulator_resume_early);
}
#else /* !CONFIG_SUSPEND */
#define regulator_suspend_late NULL
#define regulator_resume_early NULL
#endif /* !CONFIG_SUSPEND */
#ifdef CONFIG_PM
static const struct dev_pm_ops __maybe_unused regulator_pm_ops = {
.suspend_late = regulator_suspend_late,
.resume_early = regulator_resume_early,
};
#endif
struct class regulator_class = {
.name = "regulator",
.dev_release = regulator_dev_release,
.dev_groups = regulator_dev_groups,
#ifdef CONFIG_PM
.pm = &regulator_pm_ops,
#endif
};
/**
* regulator_has_full_constraints - the system has fully specified constraints
*
@@ -4424,8 +4529,8 @@ static void regulator_summary_show_subtree(struct seq_file *s,
switch (rdev->desc->type) {
case REGULATOR_VOLTAGE:
seq_printf(s, "%37dmV %5dmV",
consumer->min_uV / 1000,
consumer->max_uV / 1000);
consumer->voltage[PM_SUSPEND_ON].min_uV / 1000,
consumer->voltage[PM_SUSPEND_ON].max_uV / 1000);
break;
case REGULATOR_CURRENT:
break;
+25 -2
View File
@@ -16,10 +16,25 @@
#ifndef __REGULATOR_INTERNAL_H
#define __REGULATOR_INTERNAL_H
#include <linux/suspend.h>
#define REGULATOR_STATES_NUM (PM_SUSPEND_MAX + 1)
struct regulator_voltage {
int min_uV;
int max_uV;
};
/*
* struct regulator
*
* One for each consumer device.
* @voltage - a voltage array for each state of runtime, i.e.:
* PM_SUSPEND_ON
* PM_SUSPEND_TO_IDLE
* PM_SUSPEND_STANDBY
* PM_SUSPEND_MEM
* PM_SUSPEND_MAX
*/
struct regulator {
struct device *dev;
@@ -27,14 +42,22 @@ struct regulator {
unsigned int always_on:1;
unsigned int bypass:1;
int uA_load;
int min_uV;
int max_uV;
struct regulator_voltage voltage[REGULATOR_STATES_NUM];
const char *supply_name;
struct device_attribute dev_attr;
struct regulator_dev *rdev;
struct dentry *debugfs;
};
extern struct class regulator_class;
static inline struct regulator_dev *dev_to_rdev(struct device *dev)
{
return container_of(dev, struct regulator_dev, dev);
}
struct regulator_dev *of_find_regulator_by_node(struct device_node *np);
#ifdef CONFIG_OF
struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
const struct regulator_desc *desc,
+32 -2
View File
@@ -177,14 +177,30 @@ static void of_get_regulation_constraints(struct device_node *np,
if (of_property_read_bool(suspend_np,
"regulator-on-in-suspend"))
suspend_state->enabled = true;
suspend_state->enabled = ENABLE_IN_SUSPEND;
else if (of_property_read_bool(suspend_np,
"regulator-off-in-suspend"))
suspend_state->disabled = true;
suspend_state->enabled = DISABLE_IN_SUSPEND;
else
suspend_state->enabled = DO_NOTHING_IN_SUSPEND;
if (!of_property_read_u32(np, "regulator-suspend-min-microvolt",
&pval))
suspend_state->min_uV = pval;
if (!of_property_read_u32(np, "regulator-suspend-max-microvolt",
&pval))
suspend_state->max_uV = pval;
if (!of_property_read_u32(suspend_np,
"regulator-suspend-microvolt", &pval))
suspend_state->uV = pval;
else /* otherwise use min_uV as default suspend voltage */
suspend_state->uV = suspend_state->min_uV;
if (of_property_read_bool(suspend_np,
"regulator-changeable-in-suspend"))
suspend_state->changeable = true;
if (i == PM_SUSPEND_MEM)
constraints->initial_state = PM_SUSPEND_MEM;
@@ -376,3 +392,17 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
return init_data;
}
static int of_node_match(struct device *dev, const void *data)
{
return dev->of_node == data;
}
struct regulator_dev *of_find_regulator_by_node(struct device_node *np)
{
struct device *dev;
dev = class_find_device(&regulator_class, NULL, np, of_node_match);
return dev ? dev_to_rdev(dev) : NULL;
}
+31 -53
View File
@@ -486,24 +486,6 @@ static int spmi_vreg_update_bits(struct spmi_regulator *vreg, u16 addr, u8 val,
return regmap_update_bits(vreg->regmap, vreg->base + addr, mask, val);
}
static int spmi_regulator_common_is_enabled(struct regulator_dev *rdev)
{
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
u8 reg;
spmi_vreg_read(vreg, SPMI_COMMON_REG_ENABLE, &reg, 1);
return (reg & SPMI_COMMON_ENABLE_MASK) == SPMI_COMMON_ENABLE;
}
static int spmi_regulator_common_enable(struct regulator_dev *rdev)
{
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_ENABLE,
SPMI_COMMON_ENABLE, SPMI_COMMON_ENABLE_MASK);
}
static int spmi_regulator_vs_enable(struct regulator_dev *rdev)
{
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
@@ -513,7 +495,7 @@ static int spmi_regulator_vs_enable(struct regulator_dev *rdev)
vreg->vs_enable_time = ktime_get();
}
return spmi_regulator_common_enable(rdev);
return regulator_enable_regmap(rdev);
}
static int spmi_regulator_vs_ocp(struct regulator_dev *rdev)
@@ -524,14 +506,6 @@ static int spmi_regulator_vs_ocp(struct regulator_dev *rdev)
return spmi_vreg_write(vreg, SPMI_VS_REG_OCP, &reg, 1);
}
static int spmi_regulator_common_disable(struct regulator_dev *rdev)
{
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_ENABLE,
SPMI_COMMON_DISABLE, SPMI_COMMON_ENABLE_MASK);
}
static int spmi_regulator_select_voltage(struct spmi_regulator *vreg,
int min_uV, int max_uV)
{
@@ -1062,9 +1036,9 @@ static irqreturn_t spmi_regulator_vs_ocp_isr(int irq, void *data)
}
static struct regulator_ops spmi_smps_ops = {
.enable = spmi_regulator_common_enable,
.disable = spmi_regulator_common_disable,
.is_enabled = spmi_regulator_common_is_enabled,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_voltage_sel = spmi_regulator_common_set_voltage,
.set_voltage_time_sel = spmi_regulator_set_voltage_time_sel,
.get_voltage_sel = spmi_regulator_common_get_voltage,
@@ -1077,9 +1051,9 @@ static struct regulator_ops spmi_smps_ops = {
};
static struct regulator_ops spmi_ldo_ops = {
.enable = spmi_regulator_common_enable,
.disable = spmi_regulator_common_disable,
.is_enabled = spmi_regulator_common_is_enabled,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_voltage_sel = spmi_regulator_common_set_voltage,
.get_voltage_sel = spmi_regulator_common_get_voltage,
.map_voltage = spmi_regulator_common_map_voltage,
@@ -1094,9 +1068,9 @@ static struct regulator_ops spmi_ldo_ops = {
};
static struct regulator_ops spmi_ln_ldo_ops = {
.enable = spmi_regulator_common_enable,
.disable = spmi_regulator_common_disable,
.is_enabled = spmi_regulator_common_is_enabled,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_voltage_sel = spmi_regulator_common_set_voltage,
.get_voltage_sel = spmi_regulator_common_get_voltage,
.map_voltage = spmi_regulator_common_map_voltage,
@@ -1107,8 +1081,8 @@ static struct regulator_ops spmi_ln_ldo_ops = {
static struct regulator_ops spmi_vs_ops = {
.enable = spmi_regulator_vs_enable,
.disable = spmi_regulator_common_disable,
.is_enabled = spmi_regulator_common_is_enabled,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_pull_down = spmi_regulator_common_set_pull_down,
.set_soft_start = spmi_regulator_common_set_soft_start,
.set_over_current_protection = spmi_regulator_vs_ocp,
@@ -1117,9 +1091,9 @@ static struct regulator_ops spmi_vs_ops = {
};
static struct regulator_ops spmi_boost_ops = {
.enable = spmi_regulator_common_enable,
.disable = spmi_regulator_common_disable,
.is_enabled = spmi_regulator_common_is_enabled,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.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,
@@ -1128,9 +1102,9 @@ static struct regulator_ops spmi_boost_ops = {
};
static struct regulator_ops spmi_ftsmps_ops = {
.enable = spmi_regulator_common_enable,
.disable = spmi_regulator_common_disable,
.is_enabled = spmi_regulator_common_is_enabled,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_voltage_sel = spmi_regulator_common_set_voltage,
.set_voltage_time_sel = spmi_regulator_set_voltage_time_sel,
.get_voltage_sel = spmi_regulator_common_get_voltage,
@@ -1143,9 +1117,9 @@ static struct regulator_ops spmi_ftsmps_ops = {
};
static struct regulator_ops spmi_ult_lo_smps_ops = {
.enable = spmi_regulator_common_enable,
.disable = spmi_regulator_common_disable,
.is_enabled = spmi_regulator_common_is_enabled,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_voltage_sel = spmi_regulator_ult_lo_smps_set_voltage,
.set_voltage_time_sel = spmi_regulator_set_voltage_time_sel,
.get_voltage_sel = spmi_regulator_ult_lo_smps_get_voltage,
@@ -1157,9 +1131,9 @@ static struct regulator_ops spmi_ult_lo_smps_ops = {
};
static struct regulator_ops spmi_ult_ho_smps_ops = {
.enable = spmi_regulator_common_enable,
.disable = spmi_regulator_common_disable,
.is_enabled = spmi_regulator_common_is_enabled,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_voltage_sel = spmi_regulator_single_range_set_voltage,
.set_voltage_time_sel = spmi_regulator_set_voltage_time_sel,
.get_voltage_sel = spmi_regulator_single_range_get_voltage,
@@ -1172,9 +1146,9 @@ static struct regulator_ops spmi_ult_ho_smps_ops = {
};
static struct regulator_ops spmi_ult_ldo_ops = {
.enable = spmi_regulator_common_enable,
.disable = spmi_regulator_common_disable,
.is_enabled = spmi_regulator_common_is_enabled,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.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,
@@ -1711,6 +1685,9 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
vreg->desc.id = -1;
vreg->desc.owner = THIS_MODULE;
vreg->desc.type = REGULATOR_VOLTAGE;
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;
vreg->desc.name = name = reg->name;
vreg->desc.supply_name = reg->supply;
vreg->desc.of_match = reg->name;
@@ -1723,6 +1700,7 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev)
config.dev = dev;
config.driver_data = vreg;
config.regmap = regmap;
rdev = devm_regulator_register(dev, &vreg->desc, &config);
if (IS_ERR(rdev)) {
dev_err(dev, "failed to register %s\n", name);
+256
View File
@@ -0,0 +1,256 @@
//SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2017 Spreadtrum Communications Inc.
*/
#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/of_regulator.h>
/*
* SC2731 regulator lock register
*/
#define SC2731_PWR_WR_PROT 0xf0c
#define SC2731_WR_UNLOCK_VALUE 0x6e7f
/*
* SC2731 enable register
*/
#define SC2731_POWER_PD_SW 0xc28
#define SC2731_LDO_CAMA0_PD 0xcfc
#define SC2731_LDO_CAMA1_PD 0xd04
#define SC2731_LDO_CAMMOT_PD 0xd0c
#define SC2731_LDO_VLDO_PD 0xd6c
#define SC2731_LDO_EMMCCORE_PD 0xd2c
#define SC2731_LDO_SDCORE_PD 0xd74
#define SC2731_LDO_SDIO_PD 0xd70
#define SC2731_LDO_WIFIPA_PD 0xd4c
#define SC2731_LDO_USB33_PD 0xd5c
#define SC2731_LDO_CAMD0_PD 0xd7c
#define SC2731_LDO_CAMD1_PD 0xd84
#define SC2731_LDO_CON_PD 0xd8c
#define SC2731_LDO_CAMIO_PD 0xd94
#define SC2731_LDO_SRAM_PD 0xd78
/*
* SC2731 enable mask
*/
#define SC2731_DCDC_CPU0_PD_MASK BIT(4)
#define SC2731_DCDC_CPU1_PD_MASK BIT(3)
#define SC2731_DCDC_RF_PD_MASK BIT(11)
#define SC2731_LDO_CAMA0_PD_MASK BIT(0)
#define SC2731_LDO_CAMA1_PD_MASK BIT(0)
#define SC2731_LDO_CAMMOT_PD_MASK BIT(0)
#define SC2731_LDO_VLDO_PD_MASK BIT(0)
#define SC2731_LDO_EMMCCORE_PD_MASK BIT(0)
#define SC2731_LDO_SDCORE_PD_MASK BIT(0)
#define SC2731_LDO_SDIO_PD_MASK BIT(0)
#define SC2731_LDO_WIFIPA_PD_MASK BIT(0)
#define SC2731_LDO_USB33_PD_MASK BIT(0)
#define SC2731_LDO_CAMD0_PD_MASK BIT(0)
#define SC2731_LDO_CAMD1_PD_MASK BIT(0)
#define SC2731_LDO_CON_PD_MASK BIT(0)
#define SC2731_LDO_CAMIO_PD_MASK BIT(0)
#define SC2731_LDO_SRAM_PD_MASK BIT(0)
/*
* SC2731 vsel register
*/
#define SC2731_DCDC_CPU0_VOL 0xc54
#define SC2731_DCDC_CPU1_VOL 0xc64
#define SC2731_DCDC_RF_VOL 0xcb8
#define SC2731_LDO_CAMA0_VOL 0xd00
#define SC2731_LDO_CAMA1_VOL 0xd08
#define SC2731_LDO_CAMMOT_VOL 0xd10
#define SC2731_LDO_VLDO_VOL 0xd28
#define SC2731_LDO_EMMCCORE_VOL 0xd30
#define SC2731_LDO_SDCORE_VOL 0xd38
#define SC2731_LDO_SDIO_VOL 0xd40
#define SC2731_LDO_WIFIPA_VOL 0xd50
#define SC2731_LDO_USB33_VOL 0xd60
#define SC2731_LDO_CAMD0_VOL 0xd80
#define SC2731_LDO_CAMD1_VOL 0xd88
#define SC2731_LDO_CON_VOL 0xd90
#define SC2731_LDO_CAMIO_VOL 0xd98
#define SC2731_LDO_SRAM_VOL 0xdB0
/*
* SC2731 vsel register mask
*/
#define SC2731_DCDC_CPU0_VOL_MASK GENMASK(8, 0)
#define SC2731_DCDC_CPU1_VOL_MASK GENMASK(8, 0)
#define SC2731_DCDC_RF_VOL_MASK GENMASK(8, 0)
#define SC2731_LDO_CAMA0_VOL_MASK GENMASK(7, 0)
#define SC2731_LDO_CAMA1_VOL_MASK GENMASK(7, 0)
#define SC2731_LDO_CAMMOT_VOL_MASK GENMASK(7, 0)
#define SC2731_LDO_VLDO_VOL_MASK GENMASK(7, 0)
#define SC2731_LDO_EMMCCORE_VOL_MASK GENMASK(7, 0)
#define SC2731_LDO_SDCORE_VOL_MASK GENMASK(7, 0)
#define SC2731_LDO_SDIO_VOL_MASK GENMASK(7, 0)
#define SC2731_LDO_WIFIPA_VOL_MASK GENMASK(7, 0)
#define SC2731_LDO_USB33_VOL_MASK GENMASK(7, 0)
#define SC2731_LDO_CAMD0_VOL_MASK GENMASK(6, 0)
#define SC2731_LDO_CAMD1_VOL_MASK GENMASK(6, 0)
#define SC2731_LDO_CON_VOL_MASK GENMASK(6, 0)
#define SC2731_LDO_CAMIO_VOL_MASK GENMASK(6, 0)
#define SC2731_LDO_SRAM_VOL_MASK GENMASK(6, 0)
enum sc2731_regulator_id {
SC2731_BUCK_CPU0,
SC2731_BUCK_CPU1,
SC2731_BUCK_RF,
SC2731_LDO_CAMA0,
SC2731_LDO_CAMA1,
SC2731_LDO_CAMMOT,
SC2731_LDO_VLDO,
SC2731_LDO_EMMCCORE,
SC2731_LDO_SDCORE,
SC2731_LDO_SDIO,
SC2731_LDO_WIFIPA,
SC2731_LDO_USB33,
SC2731_LDO_CAMD0,
SC2731_LDO_CAMD1,
SC2731_LDO_CON,
SC2731_LDO_CAMIO,
SC2731_LDO_SRAM,
};
static const struct regulator_ops sc2731_regu_linear_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
};
#define SC2731_REGU_LINEAR(_id, en_reg, en_mask, vreg, vmask, \
vstep, vmin, vmax) { \
.name = #_id, \
.of_match = of_match_ptr(#_id), \
.ops = &sc2731_regu_linear_ops, \
.type = REGULATOR_VOLTAGE, \
.id = SC2731_##_id, \
.owner = THIS_MODULE, \
.min_uV = vmin, \
.n_voltages = ((vmax) - (vmin)) / (vstep) + 1, \
.uV_step = vstep, \
.enable_is_inverted = true, \
.enable_val = 0, \
.enable_reg = en_reg, \
.enable_mask = en_mask, \
.vsel_reg = vreg, \
.vsel_mask = vmask, \
}
static struct regulator_desc regulators[] = {
SC2731_REGU_LINEAR(BUCK_CPU0, SC2731_POWER_PD_SW,
SC2731_DCDC_CPU0_PD_MASK, SC2731_DCDC_CPU0_VOL,
SC2731_DCDC_CPU0_VOL_MASK, 3125, 400000, 1996875),
SC2731_REGU_LINEAR(BUCK_CPU1, SC2731_POWER_PD_SW,
SC2731_DCDC_CPU1_PD_MASK, SC2731_DCDC_CPU1_VOL,
SC2731_DCDC_CPU1_VOL_MASK, 3125, 400000, 1996875),
SC2731_REGU_LINEAR(BUCK_RF, SC2731_POWER_PD_SW, SC2731_DCDC_RF_PD_MASK,
SC2731_DCDC_RF_VOL, SC2731_DCDC_RF_VOL_MASK,
3125, 600000, 2196875),
SC2731_REGU_LINEAR(LDO_CAMA0, SC2731_LDO_CAMA0_PD,
SC2731_LDO_CAMA0_PD_MASK, SC2731_LDO_CAMA0_VOL,
SC2731_LDO_CAMA0_VOL_MASK, 10000, 1200000, 3750000),
SC2731_REGU_LINEAR(LDO_CAMA1, SC2731_LDO_CAMA1_PD,
SC2731_LDO_CAMA1_PD_MASK, SC2731_LDO_CAMA1_VOL,
SC2731_LDO_CAMA1_VOL_MASK, 10000, 1200000, 3750000),
SC2731_REGU_LINEAR(LDO_CAMMOT, SC2731_LDO_CAMMOT_PD,
SC2731_LDO_CAMMOT_PD_MASK, SC2731_LDO_CAMMOT_VOL,
SC2731_LDO_CAMMOT_VOL_MASK, 10000, 1200000, 3750000),
SC2731_REGU_LINEAR(LDO_VLDO, SC2731_LDO_VLDO_PD,
SC2731_LDO_VLDO_PD_MASK, SC2731_LDO_VLDO_VOL,
SC2731_LDO_VLDO_VOL_MASK, 10000, 1200000, 3750000),
SC2731_REGU_LINEAR(LDO_EMMCCORE, SC2731_LDO_EMMCCORE_PD,
SC2731_LDO_EMMCCORE_PD_MASK, SC2731_LDO_EMMCCORE_VOL,
SC2731_LDO_EMMCCORE_VOL_MASK, 10000, 1200000,
3750000),
SC2731_REGU_LINEAR(LDO_SDCORE, SC2731_LDO_SDCORE_PD,
SC2731_LDO_SDCORE_PD_MASK, SC2731_LDO_SDCORE_VOL,
SC2731_LDO_SDCORE_VOL_MASK, 10000, 1200000, 3750000),
SC2731_REGU_LINEAR(LDO_SDIO, SC2731_LDO_SDIO_PD,
SC2731_LDO_SDIO_PD_MASK, SC2731_LDO_SDIO_VOL,
SC2731_LDO_SDIO_VOL_MASK, 10000, 1200000, 3750000),
SC2731_REGU_LINEAR(LDO_WIFIPA, SC2731_LDO_WIFIPA_PD,
SC2731_LDO_WIFIPA_PD_MASK, SC2731_LDO_WIFIPA_VOL,
SC2731_LDO_WIFIPA_VOL_MASK, 10000, 1200000, 3750000),
SC2731_REGU_LINEAR(LDO_USB33, SC2731_LDO_USB33_PD,
SC2731_LDO_USB33_PD_MASK, SC2731_LDO_USB33_VOL,
SC2731_LDO_USB33_VOL_MASK, 10000, 1200000, 3750000),
SC2731_REGU_LINEAR(LDO_CAMD0, SC2731_LDO_CAMD0_PD,
SC2731_LDO_CAMD0_PD_MASK, SC2731_LDO_CAMD0_VOL,
SC2731_LDO_CAMD0_VOL_MASK, 6250, 1000000, 1793750),
SC2731_REGU_LINEAR(LDO_CAMD1, SC2731_LDO_CAMD1_PD,
SC2731_LDO_CAMD1_PD_MASK, SC2731_LDO_CAMD1_VOL,
SC2731_LDO_CAMD1_VOL_MASK, 6250, 1000000, 1793750),
SC2731_REGU_LINEAR(LDO_CON, SC2731_LDO_CON_PD,
SC2731_LDO_CON_PD_MASK, SC2731_LDO_CON_VOL,
SC2731_LDO_CON_VOL_MASK, 6250, 1000000, 1793750),
SC2731_REGU_LINEAR(LDO_CAMIO, SC2731_LDO_CAMIO_PD,
SC2731_LDO_CAMIO_PD_MASK, SC2731_LDO_CAMIO_VOL,
SC2731_LDO_CAMIO_VOL_MASK, 6250, 1000000, 1793750),
SC2731_REGU_LINEAR(LDO_SRAM, SC2731_LDO_SRAM_PD,
SC2731_LDO_SRAM_PD_MASK, SC2731_LDO_SRAM_VOL,
SC2731_LDO_SRAM_VOL_MASK, 6250, 1000000, 1793750),
};
static int sc2731_regulator_unlock(struct regmap *regmap)
{
return regmap_write(regmap, SC2731_PWR_WR_PROT,
SC2731_WR_UNLOCK_VALUE);
}
static int sc2731_regulator_probe(struct platform_device *pdev)
{
int i, ret;
struct regmap *regmap;
struct regulator_config config = { };
struct regulator_dev *rdev;
regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!regmap) {
dev_err(&pdev->dev, "failed to get regmap.\n");
return -ENODEV;
}
ret = sc2731_regulator_unlock(regmap);
if (ret) {
dev_err(&pdev->dev, "failed to release regulator lock\n");
return ret;
}
config.dev = &pdev->dev;
config.regmap = regmap;
for (i = 0; i < ARRAY_SIZE(regulators); i++) {
rdev = devm_regulator_register(&pdev->dev, &regulators[i],
&config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
regulators[i].name);
return PTR_ERR(rdev);
}
}
return 0;
}
static struct platform_driver sc2731_regulator_driver = {
.driver = {
.name = "sc27xx-regulator",
},
.probe = sc2731_regulator_probe,
};
module_platform_driver(sc2731_regulator_driver);
MODULE_AUTHOR("Chen Junhui <erick.chen@spreadtrum.com>");
MODULE_DESCRIPTION("Spreadtrum SC2731 regulator driver");
MODULE_LICENSE("GPL v2");
+2 -3
View File
@@ -28,9 +28,6 @@
#include <linux/regulator/machine.h>
#include <linux/mfd/tps65218.h>
enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4,
DCDC5, DCDC6, LDO1, LS3 };
#define TPS65218_REGULATOR(_name, _of, _id, _type, _ops, _n, _vr, _vm, _er, \
_em, _cr, _cm, _lr, _nlr, _delay, _fuv, _sr, _sm) \
{ \
@@ -329,6 +326,8 @@ static int tps65218_regulator_probe(struct platform_device *pdev)
/* Allocate memory for strobes */
tps->strobes = devm_kzalloc(&pdev->dev, sizeof(u8) *
TPS65218_NUM_REGULATOR, GFP_KERNEL);
if (!tps->strobes)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(regulators); i++) {
rdev = devm_regulator_register(&pdev->dev, &regulators[i],
+2
View File
@@ -214,6 +214,8 @@ struct regulator_ops {
/* set regulator suspend operating mode (defined in consumer.h) */
int (*set_suspend_mode) (struct regulator_dev *, unsigned int mode);
int (*resume_early)(struct regulator_dev *rdev);
int (*set_pull_down) (struct regulator_dev *);
};
+27 -10
View File
@@ -42,6 +42,16 @@ struct regulator;
#define REGULATOR_CHANGE_DRMS 0x10
#define REGULATOR_CHANGE_BYPASS 0x20
/*
* operations in suspend mode
* DO_NOTHING_IN_SUSPEND - the default value
* DISABLE_IN_SUSPEND - turn off regulator in suspend states
* ENABLE_IN_SUSPEND - keep regulator on in suspend states
*/
#define DO_NOTHING_IN_SUSPEND (-1)
#define DISABLE_IN_SUSPEND 0
#define ENABLE_IN_SUSPEND 1
/* Regulator active discharge flags */
enum regulator_active_discharge {
REGULATOR_ACTIVE_DISCHARGE_DEFAULT,
@@ -56,16 +66,24 @@ enum regulator_active_discharge {
* state. One of enabled or disabled must be set for the
* configuration to be applied.
*
* @uV: Operating voltage during suspend.
* @uV: Default operating voltage during suspend, it can be adjusted
* among <min_uV, max_uV>.
* @min_uV: Minimum suspend voltage may be set.
* @max_uV: Maximum suspend voltage may be set.
* @mode: Operating mode during suspend.
* @enabled: Enabled during suspend.
* @disabled: Disabled during suspend.
* @enabled: operations during suspend.
* - DO_NOTHING_IN_SUSPEND
* - DISABLE_IN_SUSPEND
* - ENABLE_IN_SUSPEND
* @changeable: Is this state can be switched between enabled/disabled,
*/
struct regulator_state {
int uV; /* suspend voltage */
unsigned int mode; /* suspend regulator operating mode */
int enabled; /* is regulator enabled in this suspend state */
int disabled; /* is the regulator disabled in this suspend state */
int uV;
int min_uV;
int max_uV;
unsigned int mode;
int enabled;
bool changeable;
};
/**
@@ -225,12 +243,12 @@ struct regulator_init_data {
#ifdef CONFIG_REGULATOR
void regulator_has_full_constraints(void);
int regulator_suspend_prepare(suspend_state_t state);
int regulator_suspend_finish(void);
#else
static inline void regulator_has_full_constraints(void)
{
}
#endif
static inline int regulator_suspend_prepare(suspend_state_t state)
{
return 0;
@@ -239,6 +257,5 @@ static inline int regulator_suspend_finish(void)
{
return 0;
}
#endif
#endif