summaryrefslogtreecommitdiffstats
path: root/drivers/regulator
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/88pm800-regulator.c (renamed from drivers/regulator/88pm800.c)0
-rw-r--r--drivers/regulator/Kconfig37
-rw-r--r--drivers/regulator/Makefile4
-rw-r--r--drivers/regulator/arizona-ldo1.c83
-rw-r--r--drivers/regulator/arizona-micsupp.c72
-rw-r--r--drivers/regulator/bd70528-regulator.c1
-rw-r--r--drivers/regulator/bd718x7-regulator.c1
-rw-r--r--drivers/regulator/core.c278
-rw-r--r--drivers/regulator/cpcap-regulator.c2
-rw-r--r--drivers/regulator/da9062-regulator.c40
-rw-r--r--drivers/regulator/da9063-regulator.c61
-rw-r--r--drivers/regulator/da9211-regulator.c2
-rw-r--r--drivers/regulator/helpers.c11
-rw-r--r--drivers/regulator/max77620-regulator.c28
-rw-r--r--drivers/regulator/max77650-regulator.c170
-rw-r--r--drivers/regulator/max77802-regulator.c2
-rw-r--r--drivers/regulator/max8952.c64
-rw-r--r--drivers/regulator/of_regulator.c63
-rw-r--r--drivers/regulator/qcom_spmi-regulator.c252
-rw-r--r--drivers/regulator/s2mps11.c255
-rw-r--r--drivers/regulator/s5m8767.c4
-rw-r--r--drivers/regulator/slg51000-regulator.c523
-rw-r--r--drivers/regulator/slg51000-regulator.h505
-rw-r--r--drivers/regulator/stm32-booster.c132
-rw-r--r--drivers/regulator/tps65090-regulator.c7
-rw-r--r--drivers/regulator/wm831x-dcdc.c29
26 files changed, 2173 insertions, 453 deletions
diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800-regulator.c
index 69ae25886181..69ae25886181 100644
--- a/drivers/regulator/88pm800.c
+++ b/drivers/regulator/88pm800-regulator.c
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index b5d0e07a62d7..7928960563e6 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -136,19 +136,20 @@ config REGULATOR_AB8500
signal AB8500 PMIC
config REGULATOR_ARIZONA_LDO1
- tristate "Wolfson Arizona class devices LDO1"
- depends on MFD_ARIZONA
+ tristate "Cirrus Madera and Wolfson Arizona class devices LDO1"
+ depends on MFD_ARIZONA || MFD_MADERA
depends on SND_SOC
help
- Support for the LDO1 regulators found on Wolfson Arizona class
- devices.
+ Support for the LDO1 regulators found on Cirrus Logic Madera codecs
+ and Wolfson Microelectronic Arizona codecs.
config REGULATOR_ARIZONA_MICSUPP
- tristate "Wolfson Arizona class devices MICSUPP"
- depends on MFD_ARIZONA
+ tristate "Cirrus Madera and Wolfson Arizona class devices MICSUPP"
+ depends on MFD_ARIZONA || MFD_MADERA
depends on SND_SOC
help
- Support for the MICSUPP regulators found on Wolfson Arizona class
+ Support for the MICSUPP regulators found on Cirrus Logic Madera codecs
+ and Wolfson Microelectronic Arizona codecs
devices.
config REGULATOR_AS3711
@@ -258,7 +259,7 @@ config REGULATOR_DA9062
config REGULATOR_DA9063
tristate "Dialog Semiconductor DA9063 regulators"
- depends on MFD_DA9063
+ depends on MFD_DA9063 && OF
help
Say y here to support the BUCKs and LDOs regulators found on
DA9063 PMICs.
@@ -829,6 +830,26 @@ config REGULATOR_SKY81452
This driver can also be built as a module. If so, the module
will be called sky81452-regulator.
+config REGULATOR_SLG51000
+ tristate "Dialog Semiconductor SLG51000 regulators"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say y here to support for the Dialog Semiconductor SLG51000.
+ The SLG51000 is seven compact and customizable low dropout
+ regulators.
+
+config REGULATOR_STM32_BOOSTER
+ tristate "STMicroelectronics STM32 BOOSTER"
+ depends on ARCH_STM32 || COMPILE_TEST
+ help
+ This driver supports internal booster (3V3) embedded in some
+ STMicroelectronics STM32 chips. It can be used to supply ADC analog
+ input switches when vdda supply is below 2.7V.
+
+ This driver can also be built as a module. If so, the module
+ will be called stm32-booster.
+
config REGULATOR_STM32_VREFBUF
tristate "STMicroelectronics STM32 VREFBUF"
depends on ARCH_STM32 || COMPILE_TEST
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 93f53840e8f1..eef73b5a35a4 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
obj-$(CONFIG_REGULATOR_88PG86X) += 88pg86x.o
-obj-$(CONFIG_REGULATOR_88PM800) += 88pm800.o
+obj-$(CONFIG_REGULATOR_88PM800) += 88pm800-regulator.o
obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
obj-$(CONFIG_REGULATOR_CPCAP) += cpcap-regulator.o
obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
@@ -104,6 +104,8 @@ 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_SLG51000) += slg51000-regulator.o
+obj-$(CONFIG_REGULATOR_STM32_BOOSTER) += stm32-booster.o
obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o
obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
index e4bc7b1e5ccd..1a3d7b720f5e 100644
--- a/drivers/regulator/arizona-ldo1.c
+++ b/drivers/regulator/arizona-ldo1.c
@@ -25,6 +25,10 @@
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>
+#include <linux/mfd/madera/core.h>
+#include <linux/mfd/madera/pdata.h>
+#include <linux/mfd/madera/registers.h>
+
struct arizona_ldo1 {
struct regulator_dev *regulator;
struct regmap *regmap;
@@ -158,6 +162,31 @@ static const struct regulator_init_data arizona_ldo1_wm5110 = {
.num_consumer_supplies = 1,
};
+static const struct regulator_desc madera_ldo1 = {
+ .name = "LDO1",
+ .supply_name = "LDOVDD",
+ .type = REGULATOR_VOLTAGE,
+ .ops = &arizona_ldo1_ops,
+
+ .vsel_reg = MADERA_LDO1_CONTROL_1,
+ .vsel_mask = MADERA_LDO1_VSEL_MASK,
+ .min_uV = 900000,
+ .uV_step = 25000,
+ .n_voltages = 13,
+ .enable_time = 3000,
+
+ .owner = THIS_MODULE,
+};
+
+static const struct regulator_init_data madera_ldo1_default = {
+ .constraints = {
+ .min_uV = 1200000,
+ .max_uV = 1200000,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+};
+
static int arizona_ldo1_of_get_pdata(struct arizona_ldo1_pdata *pdata,
struct regulator_config *config,
const struct regulator_desc *desc,
@@ -320,6 +349,32 @@ static int arizona_ldo1_remove(struct platform_device *pdev)
return 0;
}
+static int madera_ldo1_probe(struct platform_device *pdev)
+{
+ struct madera *madera = dev_get_drvdata(pdev->dev.parent);
+ struct arizona_ldo1 *ldo1;
+ bool external_dcvdd;
+ int ret;
+
+ ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
+ if (!ldo1)
+ return -ENOMEM;
+
+ ldo1->regmap = madera->regmap;
+
+ ldo1->init_data = madera_ldo1_default;
+
+ ret = arizona_ldo1_common_init(pdev, ldo1, &madera_ldo1,
+ &madera->pdata.ldo1,
+ &external_dcvdd);
+ if (ret)
+ return ret;
+
+ madera->internal_dcvdd = !external_dcvdd;
+
+ return 0;
+}
+
static struct platform_driver arizona_ldo1_driver = {
.probe = arizona_ldo1_probe,
.remove = arizona_ldo1_remove,
@@ -328,10 +383,36 @@ static struct platform_driver arizona_ldo1_driver = {
},
};
-module_platform_driver(arizona_ldo1_driver);
+static struct platform_driver madera_ldo1_driver = {
+ .probe = madera_ldo1_probe,
+ .remove = arizona_ldo1_remove,
+ .driver = {
+ .name = "madera-ldo1",
+ },
+};
+
+static struct platform_driver * const madera_ldo1_drivers[] = {
+ &arizona_ldo1_driver,
+ &madera_ldo1_driver,
+};
+
+static int __init arizona_ldo1_init(void)
+{
+ return platform_register_drivers(madera_ldo1_drivers,
+ ARRAY_SIZE(madera_ldo1_drivers));
+}
+module_init(arizona_ldo1_init);
+
+static void __exit madera_ldo1_exit(void)
+{
+ platform_unregister_drivers(madera_ldo1_drivers,
+ ARRAY_SIZE(madera_ldo1_drivers));
+}
+module_exit(madera_ldo1_exit);
/* Module information */
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("Arizona LDO1 driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:arizona-ldo1");
+MODULE_ALIAS("platform:madera-ldo1");
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c
index be0d46da51a1..ae1a5de3e57d 100644
--- a/drivers/regulator/arizona-micsupp.c
+++ b/drivers/regulator/arizona-micsupp.c
@@ -16,7 +16,6 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
-#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <sound/soc.h>
@@ -25,6 +24,10 @@
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>
+#include <linux/mfd/madera/core.h>
+#include <linux/mfd/madera/pdata.h>
+#include <linux/mfd/madera/registers.h>
+
#include <linux/regulator/arizona-micsupp.h>
struct arizona_micsupp {
@@ -200,6 +203,28 @@ static const struct regulator_init_data arizona_micsupp_ext_default = {
.num_consumer_supplies = 1,
};
+static const struct regulator_desc madera_micsupp = {
+ .name = "MICVDD",
+ .supply_name = "CPVDD1",
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = 40,
+ .ops = &arizona_micsupp_ops,
+
+ .vsel_reg = MADERA_LDO2_CONTROL_1,
+ .vsel_mask = MADERA_LDO2_VSEL_MASK,
+ .enable_reg = MADERA_MIC_CHARGE_PUMP_1,
+ .enable_mask = MADERA_CPMIC_ENA,
+ .bypass_reg = MADERA_MIC_CHARGE_PUMP_1,
+ .bypass_mask = MADERA_CPMIC_BYPASS,
+
+ .linear_ranges = arizona_micsupp_ext_ranges,
+ .n_linear_ranges = ARRAY_SIZE(arizona_micsupp_ext_ranges),
+
+ .enable_time = 3000,
+
+ .owner = THIS_MODULE,
+};
+
static int arizona_micsupp_of_get_pdata(struct arizona_micsupp_pdata *pdata,
struct regulator_config *config,
const struct regulator_desc *desc)
@@ -316,6 +341,24 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
&arizona->pdata.micvdd);
}
+static int madera_micsupp_probe(struct platform_device *pdev)
+{
+ struct madera *madera = dev_get_drvdata(pdev->dev.parent);
+ struct arizona_micsupp *micsupp;
+
+ micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
+ if (!micsupp)
+ return -ENOMEM;
+
+ micsupp->regmap = madera->regmap;
+ micsupp->dapm = &madera->dapm;
+ micsupp->dev = madera->dev;
+ micsupp->init_data = arizona_micsupp_ext_default;
+
+ return arizona_micsupp_common_init(pdev, micsupp, &madera_micsupp,
+ &madera->pdata.micvdd);
+}
+
static struct platform_driver arizona_micsupp_driver = {
.probe = arizona_micsupp_probe,
.driver = {
@@ -323,10 +366,35 @@ static struct platform_driver arizona_micsupp_driver = {
},
};
-module_platform_driver(arizona_micsupp_driver);
+static struct platform_driver madera_micsupp_driver = {
+ .probe = madera_micsupp_probe,
+ .driver = {
+ .name = "madera-micsupp",
+ },
+};
+
+static struct platform_driver * const arizona_micsupp_drivers[] = {
+ &arizona_micsupp_driver,
+ &madera_micsupp_driver,
+};
+
+static int __init arizona_micsupp_init(void)
+{
+ return platform_register_drivers(arizona_micsupp_drivers,
+ ARRAY_SIZE(arizona_micsupp_drivers));
+}
+module_init(arizona_micsupp_init);
+
+static void __exit arizona_micsupp_exit(void)
+{
+ platform_unregister_drivers(arizona_micsupp_drivers,
+ ARRAY_SIZE(arizona_micsupp_drivers));
+}
+module_exit(arizona_micsupp_exit);
/* Module information */
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("Arizona microphone supply driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:arizona-micsupp");
+MODULE_ALIAS("platform:madera-micsupp");
diff --git a/drivers/regulator/bd70528-regulator.c b/drivers/regulator/bd70528-regulator.c
index 30e3ed430a8a..0248a61f1006 100644
--- a/drivers/regulator/bd70528-regulator.c
+++ b/drivers/regulator/bd70528-regulator.c
@@ -4,7 +4,6 @@
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/rohm-bd70528.h>
diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c
index fde4264da6ff..8c22cfb76173 100644
--- a/drivers/regulator/bd718x7-regulator.c
+++ b/drivers/regulator/bd718x7-regulator.c
@@ -4,7 +4,6 @@
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/rohm-bd718x7.h>
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index c894cf0d8a28..86ae1825cec1 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1,12 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * core.c -- Voltage/Current Regulator framework.
- *
- * Copyright 2007, 2008 Wolfson Microelectronics PLC.
- * Copyright 2008 SlimLogic Ltd.
- *
- * Author: Liam Girdwood <lrg@slimlogic.co.uk>
- */
+//
+// core.c -- Voltage/Current Regulator framework.
+//
+// Copyright 2007, 2008 Wolfson Microelectronics PLC.
+// Copyright 2008 SlimLogic Ltd.
+//
+// Author: Liam Girdwood <lrg@slimlogic.co.uk>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -23,6 +22,7 @@
#include <linux/regmap.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/consumer.h>
+#include <linux/regulator/coupler.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/module.h>
@@ -50,6 +50,7 @@ static DEFINE_MUTEX(regulator_list_mutex);
static LIST_HEAD(regulator_map_list);
static LIST_HEAD(regulator_ena_gpio_list);
static LIST_HEAD(regulator_supply_alias_list);
+static LIST_HEAD(regulator_coupler_list);
static bool has_full_constraints;
static struct dentry *debugfs_root;
@@ -93,7 +94,6 @@ struct regulator_supply_alias {
static int _regulator_is_enabled(struct regulator_dev *rdev);
static int _regulator_disable(struct regulator *regulator);
-static int _regulator_get_voltage(struct regulator_dev *rdev);
static int _regulator_get_current_limit(struct regulator_dev *rdev);
static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
static int _notifier_call_chain(struct regulator_dev *rdev,
@@ -102,15 +102,12 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV);
static int regulator_balance_voltage(struct regulator_dev *rdev,
suspend_state_t state);
-static int regulator_set_voltage_rdev(struct regulator_dev *rdev,
- int min_uV, int max_uV,
- suspend_state_t state);
static struct regulator *create_regulator(struct regulator_dev *rdev,
struct device *dev,
const char *supply_name);
static void _regulator_put(struct regulator *regulator);
-static const char *rdev_get_name(struct regulator_dev *rdev)
+const char *rdev_get_name(struct regulator_dev *rdev)
{
if (rdev->constraints && rdev->constraints->name)
return rdev->constraints->name;
@@ -424,8 +421,8 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp
}
/* Platform voltage constraint check */
-static int regulator_check_voltage(struct regulator_dev *rdev,
- int *min_uV, int *max_uV)
+int regulator_check_voltage(struct regulator_dev *rdev,
+ int *min_uV, int *max_uV)
{
BUG_ON(*min_uV > *max_uV);
@@ -457,9 +454,9 @@ static int regulator_check_states(suspend_state_t state)
/* 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,
- suspend_state_t state)
+int regulator_check_consumers(struct regulator_dev *rdev,
+ int *min_uV, int *max_uV,
+ suspend_state_t state)
{
struct regulator *regulator;
struct regulator_voltage *voltage;
@@ -570,7 +567,7 @@ static ssize_t regulator_uV_show(struct device *dev,
ssize_t ret;
regulator_lock(rdev);
- ret = sprintf(buf, "%d\n", _regulator_get_voltage(rdev));
+ ret = sprintf(buf, "%d\n", regulator_get_voltage_rdev(rdev));
regulator_unlock(rdev);
return ret;
@@ -941,7 +938,7 @@ static int drms_uA_update(struct regulator_dev *rdev)
rdev_err(rdev, "failed to set load %d\n", current_uA);
} else {
/* get output voltage */
- output_uV = _regulator_get_voltage(rdev);
+ output_uV = regulator_get_voltage_rdev(rdev);
if (output_uV <= 0) {
rdev_err(rdev, "invalid output voltage found\n");
return -EINVAL;
@@ -1054,7 +1051,7 @@ static void print_constraints(struct regulator_dev *rdev)
if (!constraints->min_uV ||
constraints->min_uV != constraints->max_uV) {
- ret = _regulator_get_voltage(rdev);
+ ret = regulator_get_voltage_rdev(rdev);
if (ret > 0)
count += scnprintf(buf + count, len - count,
"at %d mV ", ret / 1000);
@@ -1113,7 +1110,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
if (rdev->constraints->apply_uV &&
rdev->constraints->min_uV && rdev->constraints->max_uV) {
int target_min, target_max;
- int current_uV = _regulator_get_voltage(rdev);
+ int current_uV = regulator_get_voltage_rdev(rdev);
if (current_uV == -ENOTRECOVERABLE) {
/* This regulator can't be read and must be initialized */
@@ -1123,7 +1120,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
_regulator_do_set_voltage(rdev,
rdev->constraints->min_uV,
rdev->constraints->max_uV);
- current_uV = _regulator_get_voltage(rdev);
+ current_uV = regulator_get_voltage_rdev(rdev);
}
if (current_uV < 0) {
@@ -1645,9 +1642,9 @@ static int _regulator_get_enable_time(struct regulator_dev *rdev)
{
if (rdev->constraints && rdev->constraints->enable_time)
return rdev->constraints->enable_time;
- if (!rdev->desc->ops->enable_time)
- return rdev->desc->enable_time;
- return rdev->desc->ops->enable_time(rdev);
+ if (rdev->desc->ops->enable_time)
+ return rdev->desc->ops->enable_time(rdev);
+ return rdev->desc->enable_time;
}
static struct regulator_supply_alias *regulator_find_supply_alias(
@@ -3065,7 +3062,7 @@ static int _regulator_call_set_voltage(struct regulator_dev *rdev,
struct pre_voltage_change_data data;
int ret;
- data.old_uV = _regulator_get_voltage(rdev);
+ data.old_uV = regulator_get_voltage_rdev(rdev);
data.min_uV = min_uV;
data.max_uV = max_uV;
ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE,
@@ -3089,7 +3086,7 @@ static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev,
struct pre_voltage_change_data data;
int ret;
- data.old_uV = _regulator_get_voltage(rdev);
+ data.old_uV = regulator_get_voltage_rdev(rdev);
data.min_uV = uV;
data.max_uV = uV;
ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE,
@@ -3107,6 +3104,66 @@ static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev,
return ret;
}
+static int _regulator_set_voltage_sel_step(struct regulator_dev *rdev,
+ int uV, int new_selector)
+{
+ const struct regulator_ops *ops = rdev->desc->ops;
+ int diff, old_sel, curr_sel, ret;
+
+ /* Stepping is only needed if the regulator is enabled. */
+ if (!_regulator_is_enabled(rdev))
+ goto final_set;
+
+ if (!ops->get_voltage_sel)
+ return -EINVAL;
+
+ old_sel = ops->get_voltage_sel(rdev);
+ if (old_sel < 0)
+ return old_sel;
+
+ diff = new_selector - old_sel;
+ if (diff == 0)
+ return 0; /* No change needed. */
+
+ if (diff > 0) {
+ /* Stepping up. */
+ for (curr_sel = old_sel + rdev->desc->vsel_step;
+ curr_sel < new_selector;
+ curr_sel += rdev->desc->vsel_step) {
+ /*
+ * Call the callback directly instead of using
+ * _regulator_call_set_voltage_sel() as we don't
+ * want to notify anyone yet. Same in the branch
+ * below.
+ */
+ ret = ops->set_voltage_sel(rdev, curr_sel);
+ if (ret)
+ goto try_revert;
+ }
+ } else {
+ /* Stepping down. */
+ for (curr_sel = old_sel - rdev->desc->vsel_step;
+ curr_sel > new_selector;
+ curr_sel -= rdev->desc->vsel_step) {
+ ret = ops->set_voltage_sel(rdev, curr_sel);
+ if (ret)
+ goto try_revert;
+ }
+ }
+
+final_set:
+ /* The final selector will trigger the notifiers. */
+ return _regulator_call_set_voltage_sel(rdev, uV, new_selector);
+
+try_revert:
+ /*
+ * At least try to return to the previous voltage if setting a new
+ * one failed.
+ */
+ (void)ops->set_voltage_sel(rdev, old_sel);
+ return ret;
+}
+
static int _regulator_set_voltage_time(struct regulator_dev *rdev,
int old_uV, int new_uV)
{
@@ -3142,7 +3199,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
unsigned int selector;
int old_selector = -1;
const struct regulator_ops *ops = rdev->desc->ops;
- int old_uV = _regulator_get_voltage(rdev);
+ int old_uV = regulator_get_voltage_rdev(rdev);
trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV);
@@ -3169,7 +3226,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
best_val = ops->list_voltage(rdev,
selector);
else
- best_val = _regulator_get_voltage(rdev);
+ best_val = regulator_get_voltage_rdev(rdev);
}
} else if (ops->set_voltage_sel) {
@@ -3180,6 +3237,9 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
selector = ret;
if (old_selector == selector)
ret = 0;
+ else if (rdev->desc->vsel_step)
+ ret = _regulator_set_voltage_sel_step(
+ rdev, best_val, selector);
else
ret = _regulator_call_set_voltage_sel(
rdev, best_val, selector);
@@ -3288,7 +3348,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
* changing the voltage.
*/
if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) {
- current_uV = _regulator_get_voltage(rdev);
+ current_uV = regulator_get_voltage_rdev(rdev);
if (min_uV <= current_uV && current_uV <= max_uV) {
voltage->min_uV = min_uV;
voltage->max_uV = max_uV;
@@ -3325,8 +3385,8 @@ out:
return ret;
}
-static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV,
- int max_uV, suspend_state_t state)
+int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV,
+ int max_uV, suspend_state_t state)
{
int best_supply_uV = 0;
int supply_change_uV = 0;
@@ -3354,7 +3414,7 @@ static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV,
best_supply_uV += rdev->desc->min_dropout_uV;
- current_supply_uV = _regulator_get_voltage(rdev->supply->rdev);
+ current_supply_uV = regulator_get_voltage_rdev(rdev->supply->rdev);
if (current_supply_uV < 0) {
ret = current_supply_uV;
goto out;
@@ -3405,7 +3465,7 @@ static int regulator_limit_voltage_step(struct regulator_dev *rdev,
return 1;
if (*current_uV < 0) {
- *current_uV = _regulator_get_voltage(rdev);
+ *current_uV = regulator_get_voltage_rdev(rdev);
if (*current_uV < 0)
return *current_uV;
@@ -3434,11 +3494,10 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
struct coupling_desc *c_desc = &rdev->coupling_desc;
struct regulator_dev **c_rdevs = c_desc->coupled_rdevs;
struct regulation_constraints *constraints = rdev->constraints;
- int max_spread = constraints->max_spread;
int desired_min_uV = 0, desired_max_uV = INT_MAX;
int max_current_uV = 0, min_current_uV = INT_MAX;
int highest_min_uV = 0, target_uV, possible_uV;
- int i, ret;
+ int i, ret, max_spread;
bool done;
*current_uV = -1;
@@ -3492,6 +3551,8 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
}
}
+ max_spread = constraints->max_spread[0];
+
/*
* Let target_uV be equal to the desired one if possible.
* If not, set it to minimum voltage, allowed by other coupled
@@ -3509,7 +3570,7 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
if (!_regulator_is_enabled(c_rdevs[i]))
continue;
- tmp_act = _regulator_get_voltage(c_rdevs[i]);
+ tmp_act = regulator_get_voltage_rdev(c_rdevs[i]);
if (tmp_act < 0)
return tmp_act;
@@ -3551,7 +3612,7 @@ finish:
if (n_coupled > 1 && *current_uV == -1) {
if (_regulator_is_enabled(rdev)) {
- ret = _regulator_get_voltage(rdev);
+ ret = regulator_get_voltage_rdev(rdev);
if (ret < 0)
return ret;
@@ -3573,9 +3634,11 @@ static int regulator_balance_voltage(struct regulator_dev *rdev,
struct regulator_dev **c_rdevs;
struct regulator_dev *best_rdev;
struct coupling_desc *c_desc = &rdev->coupling_desc;
+ struct regulator_coupler *coupler = c_desc->coupler;
int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev;
- bool best_c_rdev_done, c_rdev_done[MAX_COUPLED];
unsigned int delta, best_delta;
+ unsigned long c_rdev_done = 0;
+ bool best_c_rdev_done;
c_rdevs = c_desc->coupled_rdevs;
n_coupled = c_desc->n_coupled;
@@ -3592,8 +3655,9 @@ static int regulator_balance_voltage(struct regulator_dev *rdev,
return -EPERM;
}
- for (i = 0; i < n_coupled; i++)
- c_rdev_done[i] = false;
+ /* Invoke custom balancer for customized couplers */
+ if (coupler && coupler->balance_voltage)
+ return coupler->balance_voltage(coupler, rdev, state);
/*
* Find the best possible voltage change on each loop. Leave the loop
@@ -3620,7 +3684,7 @@ static int regulator_balance_voltage(struct regulator_dev *rdev,
*/
int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0;
- if (c_rdev_done[i])
+ if (test_bit(i, &c_rdev_done))
continue;
ret = regulator_get_optimal_voltage(c_rdevs[i],
@@ -3655,7 +3719,8 @@ static int regulator_balance_voltage(struct regulator_dev *rdev,
if (ret < 0)
goto out;
- c_rdev_done[best_c_rdev] = best_c_rdev_done;
+ if (best_c_rdev_done)
+ set_bit(best_c_rdev, &c_rdev_done);
} while (n_coupled > 1);
@@ -3911,7 +3976,7 @@ out:
}
EXPORT_SYMBOL_GPL(regulator_sync_voltage);
-static int _regulator_get_voltage(struct regulator_dev *rdev)
+int regulator_get_voltage_rdev(struct regulator_dev *rdev)
{
int sel, ret;
bool bypassed;
@@ -3928,7 +3993,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev)
return -EPROBE_DEFER;
}
- return _regulator_get_voltage(rdev->supply->rdev);
+ return regulator_get_voltage_rdev(rdev->supply->rdev);
}
}
@@ -3944,7 +4009,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev)
} else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) {
ret = rdev->desc->fixed_uV;
} else if (rdev->supply) {
- ret = _regulator_get_voltage(rdev->supply->rdev);
+ ret = regulator_get_voltage_rdev(rdev->supply->rdev);
} else {
return -EINVAL;
}
@@ -3969,7 +4034,7 @@ int regulator_get_voltage(struct regulator *regulator)
int ret;
regulator_lock_dependent(regulator->rdev, &ww_ctx);
- ret = _regulator_get_voltage(regulator->rdev);
+ ret = regulator_get_voltage_rdev(regulator->rdev);
regulator_unlock_dependent(regulator->rdev, &ww_ctx);
return ret;
@@ -4707,8 +4772,60 @@ static int regulator_register_resolve_supply(struct device *dev, void *data)
return 0;
}
+int regulator_coupler_register(struct regulator_coupler *coupler)
+{
+ mutex_lock(&regulator_list_mutex);
+ list_add_tail(&coupler->list, &regulator_coupler_list);
+ mutex_unlock(&regulator_list_mutex);
+
+ return 0;
+}
+
+static struct regulator_coupler *
+regulator_find_coupler(struct regulator_dev *rdev)
+{
+ struct regulator_coupler *coupler;
+ int err;
+
+ /*
+ * Note that regulators are appended to the list and the generic
+ * coupler is registered first, hence it will be attached at last
+ * if nobody cared.
+ */
+ list_for_each_entry_reverse(coupler, &regulator_coupler_list, list) {
+ err = coupler->attach_regulator(coupler, rdev);
+ if (!err) {
+ if (!coupler->balance_voltage &&
+ rdev->coupling_desc.n_coupled > 2)
+ goto err_unsupported;
+
+ return coupler;
+ }
+
+ if (err < 0)
+ return ERR_PTR(err);
+
+ if (err == 1)
+ continue;
+
+ break;
+ }
+
+ return ERR_PTR(-EINVAL);
+
+err_unsupported:
+ if (coupler->detach_regulator)
+ coupler->detach_regulator(coupler, rdev);
+
+ rdev_err(rdev,
+ "Voltage balancing for multiple regulator couples is unimplemented\n");
+
+ return ERR_PTR(-EPERM);
+}
+
static void regulator_resolve_coupling(struct regulator_dev *rdev)
{
+ struct regulator_coupler *coupler = rdev->coupling_desc.coupler;
struct coupling_desc *c_desc = &rdev->coupling_desc;
int n_coupled = c_desc->n_coupled;
struct regulator_dev *c_rdev;
@@ -4724,6 +4841,12 @@ static void regulator_resolve_coupling(struct regulator_dev *rdev)
if (!c_rdev)
continue;
+ if (c_rdev->coupling_desc.coupler != coupler) {
+ rdev_err(rdev, "coupler mismatch with %s\n",
+ rdev_get_name(c_rdev));