diff options
Diffstat (limited to 'drivers/regulator')
38 files changed, 1497 insertions, 379 deletions
diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c index 3459f60dcfd1..d333f7eac106 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800.c @@ -141,18 +141,14 @@ struct pm800_regulators { /* Ranges are sorted in ascending order. */ static const struct regulator_linear_range buck1_volt_range[] = { - { .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f, - .uV_step = 12500 }, - { .min_uV = 1600000, .max_uV = 1800000, .min_sel = 0x50, - .max_sel = 0x54, .uV_step = 50000 }, + REGULATOR_LINEAR_RANGE(600000, 0, 0x4f, 12500), + REGULATOR_LINEAR_RANGE(1600000, 0x50, 0x54, 50000), }; /* BUCK 2~5 have same ranges. */ static const struct regulator_linear_range buck2_5_volt_range[] = { - { .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f, - .uV_step = 12500 }, - { .min_uV = 1600000, .max_uV = 3300000, .min_sel = 0x50, - .max_sel = 0x72, .uV_step = 50000 }, + REGULATOR_LINEAR_RANGE(600000, 0, 0x4f, 12500), + REGULATOR_LINEAR_RANGE(1600000, 0x50, 0x72, 50000), }; static const unsigned int ldo1_volt_table[] = { diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index dfe58096b374..75c04b8b3ec2 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -28,16 +28,6 @@ config REGULATOR_DEBUG help Say yes here to enable debugging support. -config REGULATOR_DUMMY - bool "Provide a dummy regulator if regulator lookups fail" - help - If this option is enabled then when a regulator lookup fails - and the board has not specified that it has provided full - constraints the regulator core will provide an always - enabled dummy regulator, allowing consumer drivers to continue. - - A warning will be generated when this substitution is done. - config REGULATOR_FIXED_VOLTAGE tristate "Fixed voltage regulator support" help @@ -133,6 +123,14 @@ config REGULATOR_AS3711 This driver provides support for the voltage regulators on the AS3711 PMIC +config REGULATOR_AS3722 + tristate "AMS AS3722 PMIC Regulators" + depends on MFD_AS3722 + help + This driver provides support for the voltage regulators on the + AS3722 PMIC. This will enable support for all the software + controllable DCDC/LDO regulators. + config REGULATOR_DA903X tristate "Dialog Semiconductor DA9030/DA9034 regulators" depends on PMIC_DA903X diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 69db4c8bb5c9..828c6054960f 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o +obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index 7d5eaa874b2d..77b46d0b37a6 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -535,7 +535,7 @@ static int ab3100_regulator_register(struct platform_device *pdev, config.dev = &pdev->dev; config.driver_data = reg; - rdev = regulator_register(desc, &config); + rdev = devm_regulator_register(&pdev->dev, desc, &config); if (IS_ERR(rdev)) { err = PTR_ERR(rdev); dev_err(&pdev->dev, @@ -616,7 +616,6 @@ static int ab3100_regulators_remove(struct platform_device *pdev) for (i = 0; i < AB3100_NUM_REGULATORS; i++) { struct ab3100_regulator *reg = &ab3100_regulators[i]; - regulator_unregister(reg->rdev); reg->rdev = NULL; } return 0; diff --git a/drivers/regulator/ab8500-ext.c b/drivers/regulator/ab8500-ext.c index 02ff691cdb8b..29c0faaf8eba 100644 --- a/drivers/regulator/ab8500-ext.c +++ b/drivers/regulator/ab8500-ext.c @@ -413,16 +413,12 @@ static int ab8500_ext_regulator_probe(struct platform_device *pdev) &pdata->ext_regulator[i]; /* register regulator with framework */ - info->rdev = regulator_register(&info->desc, &config); + info->rdev = devm_regulator_register(&pdev->dev, &info->desc, + &config); if (IS_ERR(info->rdev)) { err = PTR_ERR(info->rdev); dev_err(&pdev->dev, "failed to register regulator %s\n", info->desc.name); - /* when we fail, un-register all earlier regulators */ - while (--i >= 0) { - info = &ab8500_ext_regulator_info[i]; - regulator_unregister(info->rdev); - } return err; } @@ -433,26 +429,8 @@ static int ab8500_ext_regulator_probe(struct platform_device *pdev) return 0; } -static int ab8500_ext_regulator_remove(struct platform_device *pdev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) { - struct ab8500_ext_regulator_info *info = NULL; - info = &ab8500_ext_regulator_info[i]; - - dev_vdbg(rdev_get_dev(info->rdev), - "%s-remove\n", info->desc.name); - - regulator_unregister(info->rdev); - } - - return 0; -} - static struct platform_driver ab8500_ext_regulator_driver = { .probe = ab8500_ext_regulator_probe, - .remove = ab8500_ext_regulator_remove, .driver = { .name = "ab8500-ext-regulator", .owner = THIS_MODULE, diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index e42bfd17562a..c734d0980826 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -255,7 +255,7 @@ static void __exit anatop_regulator_exit(void) } module_exit(anatop_regulator_exit); -MODULE_AUTHOR("Nancy Chen <Nancy.Chen@freescale.com>, " - "Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>"); +MODULE_AUTHOR("Nancy Chen <Nancy.Chen@freescale.com>"); +MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>"); MODULE_DESCRIPTION("ANATOP Regulator driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c index fb27e6c8887c..c77a58478cca 100644 --- a/drivers/regulator/as3711-regulator.c +++ b/drivers/regulator/as3711-regulator.c @@ -117,26 +117,19 @@ static struct regulator_ops as3711_dldo_ops = { }; static const struct regulator_linear_range as3711_sd_ranges[] = { - { .min_uV = 612500, .max_uV = 1400000, - .min_sel = 0x1, .max_sel = 0x40, .uV_step = 12500 }, - { .min_uV = 1425000, .max_uV = 2600000, - .min_sel = 0x41, .max_sel = 0x70, .uV_step = 25000 }, - { .min_uV = 2650000, .max_uV = 3350000, - .min_sel = 0x71, .max_sel = 0x7f, .uV_step = 50000 }, + REGULATOR_LINEAR_RANGE(612500, 0x1, 0x40, 12500), + REGULATOR_LINEAR_RANGE(1425000, 0x41, 0x70, 25000), + REGULATOR_LINEAR_RANGE(2650000, 0x71, 0x7f, 50000), }; static const struct regulator_linear_range as3711_aldo_ranges[] = { - { .min_uV = 1200000, .max_uV = 1950000, - .min_sel = 0, .max_sel = 0xf, .uV_step = 50000 }, - { .min_uV = 1800000, .max_uV = 3300000, - .min_sel = 0x10, .max_sel = 0x1f, .uV_step = 100000 }, + REGULATOR_LINEAR_RANGE(1200000, 0, 0xf, 50000), + REGULATOR_LINEAR_RANGE(1800000, 0x10, 0x1f, 100000), }; static const struct regulator_linear_range as3711_dldo_ranges[] = { - { .min_uV = 900000, .max_uV = 1700000, - .min_sel = 0, .max_sel = 0x10, .uV_step = 50000 }, - { .min_uV = 1750000, .max_uV = 3300000, - .min_sel = 0x20, .max_sel = 0x3f, .uV_step = 50000 }, + REGULATOR_LINEAR_RANGE(900000, 0, 0x10, 50000), + REGULATOR_LINEAR_RANGE(1750000, 0x20, 0x3f, 50000), }; #define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _vshift, _min_uV, _max_uV, _sfx) \ diff --git a/drivers/regulator/as3722-regulator.c b/drivers/regulator/as3722-regulator.c new file mode 100644 index 000000000000..5917fe3dc983 --- /dev/null +++ b/drivers/regulator/as3722-regulator.c @@ -0,0 +1,908 @@ +/* + * Voltage regulator support for AMS AS3722 PMIC + * + * Copyright (C) 2013 ams + * + * Author: Florian Lobmaier <florian.lobmaier@ams.com> + * Author: Laxman Dewangan <ldewangan@nvidia.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mfd/as3722.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/slab.h> + +/* Regulator IDs */ +enum as3722_regulators_id { + AS3722_REGULATOR_ID_SD0, + AS3722_REGULATOR_ID_SD1, + AS3722_REGULATOR_ID_SD2, + AS3722_REGULATOR_ID_SD3, + AS3722_REGULATOR_ID_SD4, + AS3722_REGULATOR_ID_SD5, + AS3722_REGULATOR_ID_SD6, + AS3722_REGULATOR_ID_LDO0, + AS3722_REGULATOR_ID_LDO1, + AS3722_REGULATOR_ID_LDO2, + AS3722_REGULATOR_ID_LDO3, + AS3722_REGULATOR_ID_LDO4, + AS3722_REGULATOR_ID_LDO5, + AS3722_REGULATOR_ID_LDO6, + AS3722_REGULATOR_ID_LDO7, + AS3722_REGULATOR_ID_LDO9, + AS3722_REGULATOR_ID_LDO10, + AS3722_REGULATOR_ID_LDO11, + AS3722_REGULATOR_ID_MAX, +}; + +struct as3722_register_mapping { + u8 regulator_id; + const char *name; + const char *sname; + u8 vsel_reg; + u8 vsel_mask; + int n_voltages; + u32 enable_reg; + u8 enable_mask; + u32 control_reg; + u8 mode_mask; + u32 sleep_ctrl_reg; + u8 sleep_ctrl_mask; +}; + +struct as3722_regulator_config_data { + struct regulator_init_data *reg_init; + bool enable_tracking; + int ext_control; +}; + +struct as3722_regulators { + struct device *dev; + struct as3722 *as3722; + struct regulator_dev *rdevs[AS3722_REGULATOR_ID_MAX]; + struct regulator_desc desc[AS3722_REGULATOR_ID_MAX]; + struct as3722_regulator_config_data + reg_config_data[AS3722_REGULATOR_ID_MAX]; +}; + +static const struct as3722_register_mapping as3722_reg_lookup[] = { + { + .regulator_id = AS3722_REGULATOR_ID_SD0, + .name = "as3722-sd0", + .vsel_reg = AS3722_SD0_VOLTAGE_REG, + .vsel_mask = AS3722_SD_VSEL_MASK, + .enable_reg = AS3722_SD_CONTROL_REG, + .enable_mask = AS3722_SDn_CTRL(0), + .sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, + .sleep_ctrl_mask = AS3722_SD0_EXT_ENABLE_MASK, + .control_reg = AS3722_SD0_CONTROL_REG, + .mode_mask = AS3722_SD0_MODE_FAST, + .n_voltages = AS3722_SD0_VSEL_MAX + 1, + }, + { + .regulator_id = AS3722_REGULATOR_ID_SD1, + .name = "as3722-sd1", + .vsel_reg = AS3722_SD1_VOLTAGE_REG, + .vsel_mask = AS3722_SD_VSEL_MASK, + .enable_reg = AS3722_SD_CONTROL_REG, + .enable_mask = AS3722_SDn_CTRL(1), + .sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, + .sleep_ctrl_mask = AS3722_SD1_EXT_ENABLE_MASK, + .control_reg = AS3722_SD1_CONTROL_REG, + .mode_mask = AS3722_SD1_MODE_FAST, + .n_voltages = AS3722_SD0_VSEL_MAX + 1, + }, + { + .regulator_id = AS3722_REGULATOR_ID_SD2, + .name = "as3722-sd2", + .sname = "vsup-sd2", + .vsel_reg = AS3722_SD2_VOLTAGE_REG, + .vsel_mask = AS3722_SD_VSEL_MASK, + .enable_reg = AS3722_SD_CONTROL_REG, + .enable_mask = AS3722_SDn_CTRL(2), + .sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, + .sleep_ctrl_mask = AS3722_SD2_EXT_ENABLE_MASK, + .control_reg = AS3722_SD23_CONTROL_REG, + .mode_mask = AS3722_SD2_MODE_FAST, + .n_voltages = AS3722_SD2_VSEL_MAX + 1, + }, + { + .regulator_id = AS3722_REGULATOR_ID_SD3, + .name = "as3722-sd3", + .sname = "vsup-sd3", + .vsel_reg = AS3722_SD3_VOLTAGE_REG, + .vsel_mask = AS3722_SD_VSEL_MASK, + .enable_reg = AS3722_SD_CONTROL_REG, + .enable_mask = AS3722_SDn_CTRL(3), + .sleep_ctrl_reg = AS3722_ENABLE_CTRL1_REG, + .sleep_ctrl_mask = AS3722_SD3_EXT_ENABLE_MASK, + .control_reg = AS3722_SD23_CONTROL_REG, + .mode_mask = AS3722_SD3_MODE_FAST, + .n_voltages = AS3722_SD2_VSEL_MAX + 1, + }, + { + .regulator_id = AS3722_REGULATOR_ID_SD4, + .name = "as3722-sd4", + .sname = "vsup-sd4", + .vsel_reg = AS3722_SD4_VOLTAGE_REG, + .vsel_mask = AS3722_SD_VSEL_MASK, + .enable_reg = AS3722_SD_CONTROL_REG, + .enable_mask = AS3722_SDn_CTRL(4), + .sleep_ctrl_reg = AS3722_ENABLE_CTRL2_REG, + .sleep_ctrl_mask = AS3722_SD4_EXT_ENABLE_MASK, + .control_reg = AS3722_SD4_CONTROL_REG, + .mode_mask = AS3722_SD4_MODE_FAST, + .n_voltages = AS3722_SD2_VSEL_MAX + 1, + }, + { + .regulator_id = AS3722_REGULATOR_ID_SD5, + .name = "as3722-sd5", + .sname = "vsup-sd5", + .vsel_reg = AS3722_SD5_VOLTAGE_REG, + .vsel_mask = AS3722_SD_VSEL_MASK, + .enable_reg = AS3722_SD_CONTROL_REG, + .enable_mask = AS3722_SDn_CTRL(5), + .sleep_ctrl_reg = AS3722_ENABLE_CTRL2_REG, + .sleep_ctrl_mask = AS3722_SD5_EXT_ENABLE_MASK, + .control_reg = AS3722_SD5_CONTROL_REG, + .mode_mask = AS3722_SD5_MODE_FAST, + .n_voltages = AS3722_SD2_VSEL_MAX + 1, + }, + { + .regulator_id = AS3722_REGULATOR_ID_SD6, + .name = "as3722-sd6", + .vsel_reg = AS3722_SD6_VOLTAGE_REG, + .vsel_mask = AS3722_SD_VSEL_MASK, + .enable_reg = AS3722_SD_CONTROL_REG, + .enable_mask = AS3722_SDn_CTRL(6), + .sleep_ctrl_reg = AS3722_ENABLE_CTRL2_REG, + .sleep_ctrl_mask = AS3722_SD6_EXT_ENABLE_MASK, + .control_reg = AS3722_SD6_CONTROL_REG, + .mode_mask = AS3722_SD6_MODE_FAST, + .n_voltages = AS3722_SD0_VSEL_MAX + 1, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO0, + .name = "as3722-ldo0", + .sname = "vin-ldo0", + .vsel_reg = AS3722_LDO0_VOLTAGE_REG, + .vsel_mask = AS3722_LDO0_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO0_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, + .sleep_ctrl_mask = AS3722_LDO0_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO0_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO1, + .name = "as3722-ldo1", + .sname = "vin-ldo1-6", + .vsel_reg = AS3722_LDO1_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO1_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, + .sleep_ctrl_mask = AS3722_LDO1_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO2, + .name = "as3722-ldo2", + .sname = "vin-ldo2-5-7", + .vsel_reg = AS3722_LDO2_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO2_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, + .sleep_ctrl_mask = AS3722_LDO2_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO3, + .name = "as3722-ldo3", + .name = "vin-ldo3-4", + .vsel_reg = AS3722_LDO3_VOLTAGE_REG, + .vsel_mask = AS3722_LDO3_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO3_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL3_REG, + .sleep_ctrl_mask = AS3722_LDO3_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO3_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO4, + .name = "as3722-ldo4", + .name = "vin-ldo3-4", + .vsel_reg = AS3722_LDO4_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO4_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, + .sleep_ctrl_mask = AS3722_LDO4_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO5, + .name = "as3722-ldo5", + .sname = "vin-ldo2-5-7", + .vsel_reg = AS3722_LDO5_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO5_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, + .sleep_ctrl_mask = AS3722_LDO5_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO6, + .name = "as3722-ldo6", + .sname = "vin-ldo1-6", + .vsel_reg = AS3722_LDO6_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO6_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, + .sleep_ctrl_mask = AS3722_LDO6_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO7, + .name = "as3722-ldo7", + .sname = "vin-ldo2-5-7", + .vsel_reg = AS3722_LDO7_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL0_REG, + .enable_mask = AS3722_LDO7_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL4_REG, + .sleep_ctrl_mask = AS3722_LDO7_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO9, + .name = "as3722-ldo9", + .sname = "vin-ldo9-10", + .vsel_reg = AS3722_LDO9_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL1_REG, + .enable_mask = AS3722_LDO9_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL5_REG, + .sleep_ctrl_mask = AS3722_LDO9_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO10, + .name = "as3722-ldo10", + .sname = "vin-ldo9-10", + .vsel_reg = AS3722_LDO10_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL1_REG, + .enable_mask = AS3722_LDO10_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL5_REG, + .sleep_ctrl_mask = AS3722_LDO10_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, + { + .regulator_id = AS3722_REGULATOR_ID_LDO11, + .name = "as3722-ldo11", + .sname = "vin-ldo11", + .vsel_reg = AS3722_LDO11_VOLTAGE_REG, + .vsel_mask = AS3722_LDO_VSEL_MASK, + .enable_reg = AS3722_LDOCONTROL1_REG, + .enable_mask = AS3722_LDO11_CTRL, + .sleep_ctrl_reg = AS3722_ENABLE_CTRL5_REG, + .sleep_ctrl_mask = AS3722_LDO11_EXT_ENABLE_MASK, + .n_voltages = AS3722_LDO_NUM_VOLT, + }, +}; + + +static const int as3722_ldo_current[] = { 150000, 300000 }; +static const int as3722_sd016_current[] = { 2500000, 3000000, 3500000 }; + +static int as3722_current_to_index(int min_uA, int max_uA, + const int *curr_table, int n_currents) +{ + int i; + + for (i = n_currents - 1; i >= 0; i--) { + if ((min_uA <= curr_table[i]) && (curr_table[i] <= max_uA)) + return i; + } + return -EINVAL; +} + +static int as3722_ldo_get_current_limit(struct regulator_dev *rdev) +{ + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); + struct as3722 *as3722 = as3722_regs->as3722; + int id = rdev_get_id(rdev); + u32 val; + int ret; + + ret = as3722_read(as3722, as3722_reg_lookup[id].vsel_reg, &val); + if (ret < 0) { + dev_err(as3722_regs->dev, "Reg 0x%02x read failed: %d\n", + as3722_reg_lookup[id].vsel_reg, ret); + return ret; + } + if (val & AS3722_LDO_ILIMIT_MASK) + return 300000; + return 150000; +} + +static int as3722_ldo_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); + struct as3722 *as3722 = as3722_regs->as3722; + int id = rdev_get_id(rdev); + int ret; + u32 reg = 0; + + ret = as3722_current_to_index(min_uA, max_uA, as3722_ldo_current, + ARRAY_SIZE(as3722_ldo_current)); + if (ret < 0) { + dev_err(as3722_regs->dev, + "Current range min:max = %d:%d does not support\n", + min_uA, max_uA); + return ret; + } + if (ret) + reg = AS3722_LDO_ILIMIT_BIT; + return as3722_update_bits(as3722, as3722_reg_lookup[id].vsel_reg, + AS3722_LDO_ILIMIT_MASK, reg); +} + +static struct regulator_ops as3722_ldo0_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_current_limit = as3722_ldo_get_current_limit, + .set_current_limit = as3722_ldo_set_current_limit, +}; + +static struct regulator_ops as3722_ldo0_extcntrl_ops = { + .list_voltage = regulator_list_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_current_limit = as3722_ldo_get_current_limit, + .set_current_limit = as3722_ldo_set_current_limit, +}; + +static int as3722_ldo3_set_tracking_mode(struct as3722_regulators *as3722_reg, + int id, u8 mode) +{ + struct as3722 *as3722 = as3722_reg->as3722; + + switch (mode) { + case AS3722_LDO3_MODE_PMOS: + case AS3722_LDO3_MODE_PMOS_TRACKING: + case AS3722_LDO3_MODE_NMOS: + case AS3722_LDO3_MODE_SWITCH: + return as3722_update_bits(as3722, + as3722_reg_lookup[id].vsel_reg, + AS3722_LDO3_MODE_MASK, mode); + + default: + return -EINVAL; + } +} + +static int as3722_ldo3_get_current_limit(struct regulator_dev *rdev) +{ + return 150000; +} + +static struct regulator_ops as3722_ldo3_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_current_limit = as3722_ldo3_get_current_limit, +}; + +static struct regulator_ops as3722_ldo3_extcntrl_ops = { + .list_voltage = regulator_list_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_current_limit = as3722_ldo3_get_current_limit, +}; + +static const struct regulator_linear_range as3722_ldo_ranges[] = { + REGULATOR_LINEAR_RANGE(825000, 0x01, 0x24, 25000), + REGULATOR_LINEAR_RANGE(1725000, 0x40, 0x7F, 25000), +}; + +static struct regulator_ops as3722_ldo_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .get_current_limit = as3722_ldo_get_current_limit, + .set_current_limit = as3722_ldo_set_current_limit, +}; + +static struct regulator_ops as3722_ldo_extcntrl_ops = { + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .get_current_limit = as3722_ldo_get_current_limit, + .set_current_limit = as3722_ldo_set_current_limit, +}; + +static unsigned int as3722_sd_get_mode(struct regulator_dev *rdev) +{ + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); + struct as3722 *as3722 = as3722_regs->as3722; + int id = rdev_get_id(rdev); + u32 val; + int ret; + + if (!as3722_reg_lookup[id].control_reg) + return -ENOTSUPP; + + ret = as3722_read(as3722, as3722_reg_lookup[id].control_reg, &val); + if (ret < 0) { + dev_err(as3722_regs->dev, "Reg 0x%02x read failed: %d\n", + as3722_reg_lookup[id].control_reg, ret); + return ret; + } + + if (val & as3722_reg_lookup[id].mode_mask) + return REGULATOR_MODE_FAST; + else + return REGULATOR_MODE_NORMAL; +} + +static int as3722_sd_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); + struct as3722 *as3722 = as3722_regs->as3722; + u8 id = rdev_get_id(rdev); + u8 val = 0; + int ret; + + if (!as3722_reg_lookup[id].control_reg) + return -ERANGE; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = as3722_reg_lookup[id].mode_mask; + case REGULATOR_MODE_NORMAL: /* fall down */ + break; + default: + return -EINVAL; + } + + ret = as3722_update_bits(as3722, as3722_reg_lookup[id].control_reg, + as3722_reg_lookup[id].mode_mask, val); + if (ret < 0) { + dev_err(as3722_regs->dev, "Reg 0x%02x update failed: %d\n", + as3722_reg_lookup[id].control_reg, ret); + return ret; + } + return ret; +} + +static int as3722_sd016_get_current_limit(struct regulator_dev *rdev) +{ + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); + struct as3722 *as3722 = as3722_regs->as3722; + int id = rdev_get_id(rdev); + u32 val, reg; + int mask; + int ret; + + switch (id) { + case AS3722_REGULATOR_ID_SD0: + reg = AS3722_OVCURRENT_REG; + mask = AS3722_OVCURRENT_SD0_TRIP_MASK; + break; + case AS3722_REGULATOR_ID_SD1: + reg = AS3722_OVCURRENT_REG; + mask = AS3722_OVCURRENT_SD1_TRIP_MASK; + break; + case AS3722_REGULATOR_ID_SD6: + reg = AS3722_OVCURRENT_DEB_REG; + mask = AS3722_OVCURRENT_SD6_TRIP_MASK; + break; + default: + return -EINVAL; + } + ret = as3722_read(as3722, reg, &val); + if (ret < 0) { + dev_err(as3722_regs->dev, "Reg 0x%02x read failed: %d\n", + reg, ret); + return ret; + } + val &= mask; + val >>= ffs(mask) - 1; + if (val == 3) + return -EINVAL; + return as3722_sd016_current[val]; +} + +static int as3722_sd016_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + struct as3722_regulators *as3722_regs = rdev_get_drvdata(rdev); + struct as3722 *as3722 = as3722_regs->as3722; + int id = rdev_get_id(rdev); + int ret; + int val; + int mask; + u32 reg; + + ret = as3722_current_to_index(min_uA, max_uA, as3722_sd016_current, + ARRAY_SIZE(as3722_sd016_current)); + if (ret < 0) { + dev_err(as3722_regs->dev, + "Current range min:max = %d:%d does not support\n", + min_uA, max_uA); + return ret; + } + + switch (id) { + case AS3722_REGULATOR_ID_SD0: + reg = AS3722_OVCURRENT_REG; + mask = AS3722_OVCURRENT_SD0_TRIP_MASK; + break; + case AS3722_REGULATOR_ID_SD1: + reg = AS3722_OVCURRENT_REG; + mask = AS3722_OVCURRENT_SD1_TRIP_MASK; + break; + case AS3722_REGULATOR_ID_SD6: + reg = AS3722_OVCURRENT_DEB_REG; + mask = AS3722_OVCURRENT_SD6_TRIP_MASK; + break; + default: + return -EINVAL; + } + val = ret & mask; + val <<= ffs(mask) - 1; + return as3722_update_bits(as3722, reg, mask, val); +} + +static const struct regulator_linear_range as3722_sd2345_ranges[] = { + REGULATOR_LINEAR_RANGE(612500, 0x01, 0x40, 12500), + REGULATOR_LINEAR_RANGE(1425000, 0x41, 0x70, 25000), + REGULATOR_LINEAR_RANGE(2650000, 0x71, 0x7F, 50000), +}; + +static struct regulator_ops as3722_sd016_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_current_limit = as3722_sd016_get_current_limit, + .set_current_limit = as3722_sd016_set_current_limit, + .get_mode = as3722_sd_get_mode, + .set_mode = as3722_sd_set_mode, +}; + +static struct regulator_ops as3722_sd016_extcntrl_ops = { + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_current_limit = as3722_sd016_get_current_limit, + .set_current_limit = as3722_sd016_set_current_limit, + .get_mode = as3722_sd_get_mode, + .set_mode = as3722_sd_set_mode, +}; + +static struct regulator_ops as3722_sd2345_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .get_mode = as3722_sd_get_mode, + .set_mode = as3722_sd_set_mode, +}; + +static struct regulator_ops as3722_sd2345_extcntrl_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .get_mode = as3722_sd_get_mode, + .set_mode = as3722_sd_set_mode, +}; + +static int as3722_extreg_init(struct as3722_regulators *as3722_regs, int id, + int ext_pwr_ctrl) +{ + int ret; + unsigned int val; + + if ((ext_pwr_ctrl < AS3722_EXT_CONTROL_ENABLE1) || + (ext_pwr_ctrl > AS3722_EXT_CONTROL_ENABLE3)) + return -EINVAL; + + val = ext_pwr_ctrl << (ffs(as3722_reg_lookup[id].sleep_ctrl_mask) - 1); + ret = as3722_update_bits(as3722_regs->as3722, + as3722_reg_lookup[id].sleep_ctrl_reg, + as3722_reg_lookup[id].sleep_ctrl_mask, val); + if (ret < 0) + dev_err(as3722_regs->dev, "Reg 0x%02x update failed: %d\n", + as3722_reg_lookup[id].sleep_ctrl_reg, ret); + return ret; +} + +static struct of_regulator_match as3722_regulator_matches[] = { + { .name = "sd0", }, + { .name = "sd1", }, + { .name = "sd2", }, + { .name = "sd3", }, + { .name = "sd4", }, + { .name = "sd5", }, + { .name = "sd6", }, + { .name = "ldo0", }, + { .name = "ldo1", }, + { .name = "ldo2", }, + { .name = "ldo3", }, + { .name = "ldo4", }, + { .name = "ldo5", }, + { .name = "ldo6", }, + { .name = "ldo7", }, + { .name = "ldo9", }, + { .name = "ldo10", }, + { .name = "ldo11", }, +}; + +static int as3722_get_regulator_dt_data(struct platform_device *pdev, + struct as3722_regulators *as3722_regs) +{ + struct device_node *np; + struct as3722_regulator_config_data *reg_config; + u32 prop; + int id; + int ret; + + np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators"); + if (!np) { + dev_err(&pdev->dev, "Device is not having regulators node\n"); + return -ENODEV; + } + pdev->dev.of_node = np; + + ret = of_regulator_match(&pdev->dev, np, as3722_regulator_matches, + ARRAY_SIZE(as3722_regulator_matches)); + if (ret < 0) { + dev_err(&pdev->dev, "Parsing of regulator node failed: %d\n", + ret); + return ret; + } + + for (id = 0; id < ARRAY_SIZE(as3722_regulator_matches); ++id) { + struct device_node *reg_node; + + reg_config = &as3722_regs->reg_config_data[id]; + reg_config->reg_init = as3722_regulator_matches[id].init_data; + reg_node = as3722_regulator_matches[id].of_node; + + if (!reg_config->reg_init || !reg_node) + continue; + + ret = of_property_read_u32(reg_node, "ams,ext-control", &prop); + if (!ret) { + if (prop < 3) + reg_config->ext_control = prop; + else + dev_warn(&pdev->dev, + "ext-control have invalid option: %u\n", + prop); + } + reg_config->enable_tracking = + of_property_read_bool(reg_node, "ams,enable-tracking"); + } + return 0; +} + +static int as3722_regulator_probe(struct platform_device *pdev) +{ + struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent); + struct as3722_regulators *as3722_regs; + struct as3722_regulator_config_data *reg_config; + struct regulator_dev *rdev; + struct regulator_config config = { }; + struct regulator_ops *ops; + int id; + int ret; + + as3722_regs = devm_kzalloc(&pdev->dev, sizeof(*as3722_regs), + GFP_KERNEL); + if (!as3722_regs) + return -ENOMEM; + + as3722_regs->dev = &pdev->dev; + as3722_regs->as3722 = as3722; + platform_set_drvdata(pdev, as3722_regs); + + ret = as3722_get_regulator_dt_data(pdev, as3722_regs); + if (ret < 0) + return ret; + + config.dev = &pdev->dev; + config.driver_data = as3722_regs; + config.regmap = as3722->regmap; + + for (id = 0; id < AS3722_REGULATOR_ID_MAX; id++) { + reg_config = &as3722_regs->reg_config_data[id]; + + as3722_regs->desc[id].name = as3722_reg_lookup[id].name; + as3722_regs->desc[id].supply_name = as3722_reg_lookup[id].sname; + as3722_regs->desc[id].id = as3722_reg_lookup[id].regulator_id; + as3722_regs->desc[id].n_voltages = + as3722_reg_lookup[id].n_voltages; + as3722_regs->desc[id].type = REGULATOR_VOLTAGE; + as3722_regs->desc[id].owner = THIS_MODULE; + as3722_regs->desc[id].enable_reg = + as3722_reg_lookup[id].enable_reg; + as3722_regs->desc[id].enable_mask = + as3722_reg_lookup[id].enable_mask; + as3722_regs->desc[id].vsel_reg = as3722_reg_lookup[id].vsel_reg; + as3722_regs->desc[id].vsel_mask = + as3722_reg_lookup[id].vsel_mask; + switch (id) { + case AS3722_REGULATOR_ID_LDO0: + if (reg_config->ext_control) + ops = &as3722_ldo0_extcntrl_ops; + else + ops = &as3722_ldo0_ops; + as3722_regs->desc[id].min_uV = 825000; + as3722_regs->desc[id].uV_step = 25000; + as3722_regs->desc[id].linear_min_sel = 1; + as3722_regs->desc[id].enable_time = 500; + break; + case AS3722_REGULATOR_ID_LDO3: + if (reg_config->ext_control) + ops = &as3722_ldo3_extcntrl_ops; + else + ops = &as3722_ldo3_ops; + as3722_regs->desc[id].min_uV = 620000; + as3722_regs->desc[id].uV_step = 20000; + as3722_regs->desc[id].linear_min_sel = 1; + as3722_regs->desc[id].enable_time = 500; + if (reg_config->enable_tracking) { + ret = as3722_ldo3_set_tracking_mode(as3722_regs, + id, AS3722_LDO3_MODE_PMOS_TRACKING); + if (ret < 0) { + dev_err(&pdev->dev, + "LDO3 tracking failed: %d\n", + ret); + return ret; + } + } + break; + case AS3722_REGULATOR_ID_SD0: + case AS3722_REGULATOR_ID_SD1: + case AS3722_REGULATOR_ID_SD6: + if (reg_config->ext_control) + ops = &as3722_sd016_extcntrl_ops; + else + ops = &as3722_sd016_ops; + as3722_regs->desc[id].min_uV = 610000; + as3722_regs->desc[id].uV_step = 10000; + as3722_regs->desc[id].linear_min_sel = 1; + break; + case AS3722_REGULATOR_ID_SD2: + case AS3722_REGULATOR_ID_SD3: + case AS3722_REGULATOR_ID_SD4: + case AS3722_REGULATOR_ID_SD5: + if (reg_config->ext_control) + ops = &as3722_sd2345_extcntrl_ops; + else + ops = &as3722_sd2345_ops; + as3722_regs->desc[id].linear_ranges = + as3722_sd2345_ranges; + as3722_regs->desc[id].n_linear_ranges = + ARRAY_SIZE(as3722_sd2345_ranges); + break; + default: + if (reg_config->ext_control) + ops = &as3722_ldo_extcntrl_ops; + else + ops = &as3722_ldo_ops; + as3722_regs->desc[id].min_uV = 825000; + as3722_regs->desc[id].uV_step = 25000; + as3722_regs->desc[id].linear_min_sel = 1; + as3722_regs->desc[id].enable_time = 500; + as3722_regs->desc[id].linear_ranges = as3722_ldo_ranges; + as3722_regs->desc[id].n_linear_ranges = + ARRAY_SIZE(as3722_ldo_ranges); + break; + } + as3722_regs->desc[id].ops = ops; + config.init_data = reg_config->reg_init; + config.of_node = as3722_regulator_matches[id].of_node; + rdev = devm_regulator_register(&pdev->dev, + &as3722_regs->desc[id], &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(&pdev->dev, "regulator %d register failed %d\n", + id, ret); + return ret; + } + + as3722_regs->rdevs[id] = rdev; + if (reg_config->ext_control) { + ret = regulator_enable_regmap(rdev); + if (ret < 0) { + dev_err(&pdev->dev, + "Regulator %d enable failed: %d\n", + id, ret); + return ret; + } + ret = as3722_extreg_init(as3722_regs, id, + reg_config->ext_control); + if (ret < 0) { + dev_err(&pdev->dev, + "AS3722 ext control failed: %d", ret); + return ret; + } + } + } + return 0; +} + +static const struct of_device_id of_as3722_regulator_match[] = { + { .compatible = "ams,as3722-regulator", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_as3722_regulator_match); + +static struct platform_driver as3722_regulator_driver = { + .driver = { + .name = "as3722-regulator", + .owner = THIS_MODULE, + .of_match_table = of_as3722_regulator_match, + }, + .probe = as3722_regulator_probe, +}; + +module_platform_driver(as3722_regulator_driver); + +MODULE_ALIAS("platform:as3722-regulator"); +MODULE_DESCRIPTION("AS3722 regulator driver"); +MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>"); +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 906deb7354ed..6382f0af353b 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -53,8 +53,8 @@ static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); static LIST_HEAD(regulator_ena_gpio_list); +static LIST_HEAD(regulator_supply_alias_list); static bool has_full_constraints; -static bool board_wants_dummy_regulator; static struct dentry *debugfs_root; @@ -83,6 +83,19 @@ struct regulator_enable_gpio { unsigned int ena_gpio_invert:1; }; +/* + * struct regulator_supply_alias + * + * Used to map lookups for a supply onto an alternative device. + */ +struct regulator_supply_alias { + struct list_head list; + struct device *src_dev; + const char *src_supply; + struct device *alias_dev; + const char *alias_supply; +}; + static int _regulator_is_enabled(struct regulator_dev *rdev); static int _regulator_disable(struct regulator_dev *rdev); static int _regulator_get_voltage(struct regulator_dev *rdev); @@ -905,6 +918,36 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, return 0; } +static int machine_constraints_current(struct regulator_dev *rdev, + struct regulation_constraints *constraints) +{ + struct regulator_ops *ops = rdev->desc->ops; + int ret; + + if (!constraints->min_uA && !constraints->max_uA) + return 0; + + if (constraints->min_uA > constraints->max_uA) { + rdev_err(rdev, "Invalid current constraints\n"); + return -EINVAL; + } + + if (!ops->set_current_limit || !ops->get_current_limit) { + rdev_warn(rdev, "Operation of current configuration missing\n"); + return 0; + } + + /* Set regulator current in constraints range */ + ret = ops->set_current_limit(rdev, constraints->min_uA, + constraints->max_uA); + if (ret < 0) { + rdev_err(rdev, "Failed to set current constraint, %d\n", ret); + return ret; + } + + return 0; +} + /** * set_machine_constraints - sets regulator constraints * @rdev: regulator source @@ -935,6 +978,10 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (ret != 0) goto out; + ret = machine_constraints_current(rdev, rdev->constraints); + if (ret != 0) + goto out; + /* do we need to setup our suspend state */ if (rdev->constraints->initial_state) { ret = suspend_prepare(rdev, rdev->constraints->initial_state); @@ -1168,11 +1215,39 @@ overflow_err: 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); } +static struct regulator_supply_alias *regulator_find_supply_alias( + struct device *dev, const char *supply) +{ + struct regulator_supply_alias *map; + + list_for_each_entry(map, ®ulator_supply_alias_list, list) + if (map->src_dev == dev && strcmp(map->src_supply, supply) == 0) + return map; + + return NULL; +} + +static void regulator_supply_alias(struct device **dev, const char **supply) +{ + struct regulator_supply_alias *map; + + map = regulator_find_supply_alias(*dev, *supply); + if (map) { + dev_dbg(*dev, "Mapping supply %s to %s,%s\n", + *supply, map->alias_supply, + dev_name(map->alias_dev)); + *dev = map->alias_dev; + *supply = map->alias_supply; + } +} + static struct regulator_dev *regulator_dev_lookup(struct device *dev, const char *supply, int *ret) @@ -1182,6 +1257,8 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, struct regulator_map *map; const char *devname = NULL; + regulator_supply_alias(&dev, &supply); + /* first do a dt based lookup */ if (dev && dev->of_node) { node = of_get_regulator(dev, supply); @@ -1225,16 +1302,16 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, /* Internal regulator request function */ static struct regulator *_regulator_get(struct device *dev, const char *id, - bool exclusive) + bool exclusive, bool allow_dummy) { struct regulator_dev *rdev; struct regulator *regulator = ERR_PTR(-EPROBE_DEFER); const char *devname = NULL; - int ret = 0; + int ret = -EPROBE_DEFER; if (id == NULL) { pr_err("get() with no identifier\n"); - return regulator; + return ERR_PTR(-EINVAL); } if (dev) @@ -1246,34 +1323,32 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, if (rdev) goto found; + regulator = ERR_PTR(ret); + /* * If we have return value from dev_lookup fail, we do not expect to * succeed, so, quit with appropriate error value */ - if (ret) { - regulator = ERR_PTR(ret); + if (ret && ret != -ENODEV) { goto out; } - if (board_wants_dummy_regulator) { - rdev = dummy_regulator_rdev; - goto found; - } - -#ifdef CONFIG_REGULATOR_DUMMY if (!devname) devname = "deviceless"; - /* If the board didn't flag that it was fully constrained then - * substitute in a dummy regulator so consumers can continue. + /* + * Assume that a regulator is physically present and enabled + * even if it isn't hooked up and just provide a dummy. */ - if (!has_full_constraints) { + if (has_full_constraints && allow_dummy) { pr_warn("%s supply %s not found, using dummy regulator\n", devname, id); + rdev = dummy_regulator_rdev; goto found; + } else { + dev_err(dev, "dummy supplies not allowed\n"); } -#endif mutex_unlock(®ulator_list_mutex); return regulator; @@ -1331,7 +1406,7 @@ out: */ struct regulator *regulator_get(struct device *dev, const char *id) { - return _regulator_get(dev, id, false); + return _regulator_get(dev, id, false, true); } EXPORT_SYMBOL_GPL(regulator_get); @@ -1358,7 +1433,7 @@ EXPORT_SYMBOL_GPL(regulator_get); */ struct regulator *regulator_get_exclusive(struct device *dev, const char *id) { - return _regulator_get(dev, id, true); + return _regulator_get(dev, id, true, false); } EXPORT_SYMBOL_GPL(regulator_get_exclusive); @@ -1387,7 +1462,7 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive); */ struct regulator *regulator_get_optional(struct device *dev, const char *id) { - return _regulator_get(dev, id, 0); + return _regulator_get(dev, id, false, false); } EXPORT_SYMBOL_GPL(regulator_get_optional); @@ -1432,6 +1507,134 @@ void regulator_put(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_put); +/** + * regulator_register_supply_alias - Provide device alias for supply lookup + * + * @dev: device that will be given as the regulator "consumer" + * @id: Supply name or regulator ID + * @alias_dev: device that should be used to lookup the supply + * @alias_id: Supply name or regulator ID that should be used to lookup the + * supply + * + * All lookups for id on dev will instead be conducted for alias_id on + * alias_dev. + */ +int regulator_register_supply_alias(struct device *dev, const char *id, + struct device *alias_dev, + const char *alias_id) +{ + struct regulator_supply_alias *map; + + map = regulator_find_supply_alias(dev, id); + if (map) + return -EEXIST; + + map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL); + if (!map) + return -ENOMEM; + + map->src_dev = dev; + map->src_supply = id; + map->alias_dev = alias_dev; + map->alias_supply = alias_id; + + list_add(&map->list, ®ulator_supply_alias_list); + + pr_info("Adding alias for supply %s,%s -> %s,%s\n", + id, dev_name(dev), alias_id, dev_name(alias_dev)); + + return 0; +} +EXPORT_SYMBOL_GPL(regulator_register_supply_alias); + +/** + * regulator_unregister_supply_alias - Remove device alias + * + * @dev: device that will be given as the regulator "consumer" + * @id: Supply name or regulator ID + * + * Remove a lookup alias if one exists for id on dev. + */ +void regulator_unregister_supply_alias(struct device *dev, const char *id) +{ + struct regulator_supply_alias *map; + + map = regulator_find_supply_alias(dev, id); + if (map) { + list_del(&map->list); + kfree(map); + } +} +EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias); + +/** + * regulator_bulk_register_supply_alias - register multiple aliases + * + * @dev: device that will be given as the regulator "consumer" + * @id: List of supply names or regulator IDs + * @alias_dev: device that should be used to lookup the supply + * @alias_id: List of supply names or regulator IDs that should be used to + * lookup the supply + * @num_id: Number of aliases to register + * + * @return 0 on success, an errno on failure. + * + * This helper function allows drivers to register several supply + * aliases in one operation. If any of the aliases cannot be + * registered any aliases that were registered will be removed + * before returning to the caller. + */ +int regulator_bulk_register_supply_alias(struct device *dev, const char **id, + struct device *alias_dev, + const char **alias_id, + int num_id) +{ + int i; + int ret; + + for (i = 0; i < num_id; ++i) { + ret = regulator_register_supply_alias(dev, id[i], alias_dev, + alias_id[i]); + if (ret < 0) + goto err; + } + + return 0; + +err: + dev_err(dev, + "Failed to create supply alias %s,%s -> %s,%s\n", + id[i], dev_name(dev), alias_id[i], dev_name(alias_dev)); + + while (--i >= 0) + regulator_unregister_supply_alias(dev, id[i]); + + return ret; +} +EXPORT_SYMBOL_GPL(regulator_bulk_register_supply_alias); + +/** + * regulator_bulk_unregister_supply_alias - unregister multiple aliases + * + * @dev: device that will be given as the regulator "consumer" + * @id: List of supply names or regulator IDs + * @num_id: Number of aliases to unregister + * + * This helper function allows drivers to unregister several supply + * aliases in one operation. + */ +void regulator_bulk_unregister_supply_alias(struct device *dev, + const char **id, + int num_id) +{ + int i; + + for (i = 0; i < num_id; ++i) + regulator_unregister_supply_alias(dev, id[i]); +} +EXPORT_SYMBOL_GPL(regulator_bulk_unregister_supply_alias); + + /* Manage enable GPIO list. Same GPIO pin can be shared among regulators */ static int regulator_ena_gpio_request(struct regulator_dev *rdev, const struct regulator_config *config) @@ -1563,11 +1766,39 @@ static int _regulator_do_enable(struct regulator_dev *rdev) * together. */ trace_regulator_enable_delay(rdev_get_name(rdev)); - if (delay >= 1000) { - mdelay(delay / 1000); - udelay(delay % 1000); - } else if (delay) { - udelay(delay); + /* + * Delay for the requested amount of time as per the guidelines in: + * + * Documentation/timers/timers-howto.txt + * + * The assumption here is that regulators will never be enabled in + * atomic context and therefore sleeping functions can be used. + */ + if (delay) { + unsigned int ms = delay / 1000; + unsigned int us = delay % 1000; + + if (ms > 0) { + /* + * For small enough values, handle super-millisecond + * delays in the usleep_range() call below. + */ + if (ms < 20) + us += ms * 1000; + else + msleep(ms); + } + + /* + * Give the scheduler some room to coalesce with any other + * wakeup sources. For delays shorter than 10 us, don't even + * bother setting up high-resolution timers and just busy- + * loop. + */ + if (us >= 10) + usleep_range(us, us + 100); + else + udelay(us); } trace_regulator_enable_complete(rdev_get_name(rdev)); @@ -2348,6 +2579,8 @@ static int _regulator_get_voltage(struct regulator_dev *rdev) ret = rdev->desc->ops->get_voltage(rdev); } else if (rdev->desc->ops->list_voltage) { ret = rdev->desc->ops->list_voltage(rdev, 0); + } else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) { + ret = rdev->desc->fixed_uV; } else { return -EINVAL; } @@ -2983,7 +3216,8 @@ static int add_regulator_attributes(struct regulator_dev *rdev) /* some attributes need specific methods to be displayed */ if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) || - (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0)) { + (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) || + (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1))) { status = device_create_file(dev, &dev_attr_microvolts); if (status < 0) return status; @@ -3427,22 +3661,6 @@ void regulator_has_full_constraints(void) EXPORT_SYMBOL_GPL(regulator_has_full_constraints); /** - * regulator_use_dummy_regulator - Provide a dummy regulator when none is found - * - * Calling this function will cause the regulator API to provide a - * dummy regulator to consumers if no physical regulator is found, - * allowing most consumers to proceed as though a regulator were - * configured. This allows systems such as those with software - * controllable regulators for the CPU core only to be brought up more - * readily. - */ -void regulator_use_dummy_regulator(void) -{ - board_wants_dummy_regulator = true; -} -EXPORT_SYMBOL_GPL(regulator_use_dummy_regulator); - -/** * rdev_get_drvdata - get rdev regulator driver data * @rdev: regulator * diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index c61d96e9d925..b431ae357fcd 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -253,10 +253,8 @@ static int da9034_set_dvc_voltage_sel(struct regulator_dev *rdev, } static const struct regulator_linear_range da9034_ldo12_ranges[] = { - { .min_uV = 1700000, .max_uV = 2050000, .min_sel = 0, .max_sel = 7, - .uV_step = 50000 }, - { .min_uV = 2700000, .max_uV = 3050000, .min_sel = 8, .max_sel = 15, - .uV_step = 50000 }, + REGULATOR_LINEAR_RANGE(1700000, 0, 7, 50000), + REGULATOR_LINEAR_RANGE(2700000, 8, 15, 50000), }; static struct regulator_ops da903x_regulator_ldo_ops = { diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index c427e42472e8..3adeaeffc485 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -70,6 +70,7 @@ struct da9052_regulator_info { int step_uV; int min_uV; int max_uV; + unsigned char activate_bit; }; struct da9052_regulator { @@ -209,6 +210,36 @@ static int da9052_map_voltage(struct regulator_dev *rdev, return sel; } +static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int id = rdev_get_id(rdev); + int ret; + + ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, selector); + if (ret < 0) + return ret; + + /* Some LDOs and DCDCs are DVC controlled which requires enabling of + * the activate bit to implment the changes on the output. + */ + switch (id) { + case DA9052_ID_BUCK1: + case DA9052_ID_BUCK2: + case DA9052_ID_BUCK3: + case DA9052_ID_LDO2: + case DA9052_ID_LDO3: + ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, + info->activate_bit, info->activate_bit); + break; + } + + return ret; +} + static struct regulator_ops da9052_dcdc_ops = { .get_current_limit = da9052_dcdc_get_current_limit, .set_current_limit = da9052_dcdc_set_current_limit, @@ -216,7 +247,7 @@ static struct regulator_ops da9052_dcdc_ops = { .list_voltage = da9052_list_voltage, .map_voltage = da9052_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_sel = da9052_regulator_set_voltage_sel, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -226,7 +257,7 @@ static struct regulator_ops da9052_ldo_ops = { .list_voltage = da9052_list_voltage, .map_voltage = da9052_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, + .set_voltage_sel = da9052_regulator_set_voltage_sel, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -243,14 +274,13 @@ static struct regulator_ops da9052_ldo_ops = { .owner = THIS_MODULE,\ .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .vsel_mask = (1 << (sbits)) - 1,\ - .apply_reg = DA9052_SUPPLY_REG, \ - .apply_bit = (abits), \ .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .enable_mask = 1 << (ebits),\ },\ .min_uV = (min) * 1000,\ .max_uV = (max) * 1000,\ .step_uV = (step) * 1000,\ + .activate_bit = (abits),\ } #define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \ @@ -264,14 +294,13 @@ static struct regulator_ops da9052_ldo_ops = { .owner = THIS_MODULE,\ .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .vsel_mask = (1 << (sbits)) - 1,\ - .apply_reg = DA9052_SUPPLY_REG, \ - .apply_bit = (abits), \ .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .enable_mask = 1 << (ebits),\ },\ .min_uV = (min) * 1000,\ .max_uV = (max) * 1000,\ .step_uV = (step) * 1000,\ + .activate_bit = (abits),\ } static struct da9052_regulator_info da9052_regulator_info[] = { diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 1a7816390773..56727eb745df 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -709,7 +709,7 @@ static struct da9063_regulators_pdata *da9063_parse_regulators_dt( struct of_regulator_match **da9063_reg_matches) { da9063_reg_matches = NULL; - return PTR_ERR(-ENODEV); + return ERR_PTR(-ENODEV); } #endif @@ -717,7 +717,7 @@ static int da9063_regulator_probe(struct platform_device *pdev) { struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); struct da9063_pdata *da9063_pdata = dev_get_platdata(da9063->dev); - struct of_regulator_match *da9063_reg_matches; + struct of_regulator_match *da9063_reg_matches = NULL; struct da9063_regulators_pdata *regl_pdata; const struct da9063_dev_model *model; struct da9063_regulators *regulators; @@ -847,13 +847,13 @@ static int da9063_regulator_probe(struct platform_device *pdev) if (da9063_reg_matches) config.of_node = da9063_reg_matches[id].of_node; config.regmap = da9063->regmap; - regl->rdev = regulator_register(®l->desc, &config); + regl->rdev = devm_regulator_register(&pdev->dev, ®l->desc, + &config); if (IS_ERR(regl->rdev)) { dev_err(&pdev->dev, "Failed to register %s regulator\n", regl->desc.name); - ret = PTR_ERR(regl->rdev); - goto err; + return PTR_ERR(regl->rdev); } id++; n++; @@ -862,9 +862,8 @@ static int da9063_regulator_probe(struct platform_device *pdev) /* LDOs overcurrent event support */ irq = platform_get_irq_byname(pdev, "LDO_LIM"); if (irq < 0) { - ret = irq; dev_err(&pdev->dev, "Failed to get IRQ.\n"); - goto err; + return irq; } regulators->irq_ldo_lim = regmap_irq_get_virq(da9063->regmap_irq, irq); @@ -881,27 +880,15 @@ static int da9063_regulator_probe(struct platform_device *pdev) } return 0; - -err: - /* Wind back regulators registeration */ - while (--n >= 0) - regulator_unregister(regulators->regulator[n].rdev); - - return ret; } static int da9063_regulator_remove(struct platform_device *pdev) { struct da9063_regulators *regulators = platform_get_drvdata(pdev); - struct da9063_regulator *regl; free_irq(regulators->irq_ldo_lim, regulators); free_irq(regulators->irq_uvov, regulators); - for (regl = ®ulators->regulator[regulators->n_regulators - 1]; - regl >= ®ulators->regulator[0]; regl--) - regulator_unregister(regl->rdev); - return 0; } diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index f0fe54b38977..6f5ecbe1132e 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -25,6 +25,7 @@ #include <linux/slab.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> #include <linux/regmap.h> #include "da9210-regulator.h" @@ -126,7 +127,8 @@ static int da9210_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct da9210 *chip; - struct da9210_pdata *pdata = i2c->dev.platform_data; + struct device *dev = &i2c->dev; + struct da9210_pdata *pdata = dev_get_platdata(dev); struct regulator_dev *rdev = NULL; struct regulator_config config = { }; int error; @@ -147,12 +149,13 @@ static int da9210_i2c_probe(struct i2c_client *i2c, } config.dev = &i2c->dev; - if (pdata) - config.init_data = &pdata->da9210_constraints; + config.init_data = pdata ? &pdata->da9210_constraints : + of_get_regulator_init_data(dev, dev->of_node); config.driver_data = chip; config.regmap = chip->regmap; + config.of_node = dev->of_node; - rdev = regulator_register(&da9210_reg, &config); + rdev = devm_regulator_register(&i2c->dev, &da9210_reg, &config); if (IS_ERR(rdev)) { dev_err(&i2c->dev, "Failed to register DA9210 regulator\n"); return PTR_ERR(rdev); @@ -165,13 +168,6 @@ static int da9210_i2c_probe(struct i2c_client *i2c, return 0; } -static int da9210_i2c_remove(struct i2c_client *i2c) -{ - struct da9210 *chip = i2c_get_clientdata(i2c); - regulator_unregister(chip->rdev); - return 0; -} - static const struct i2c_device_id da9210_i2c_id[] = { {"da9210", 0}, {}, @@ -185,7 +181,6 @@ static struct i2c_driver da9210_regulator_driver = { .owner = THIS_MODULE, }, .probe = da9210_i2c_probe, - .remove = da9210_i2c_remove, .id_table = da9210_i2c_id, }; diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c index 2672a029fa25..f44818b838dc 100644 --- a/drivers/regulator/devres.c +++ b/drivers/regulator/devres.c @@ -250,3 +250,166 @@ void devm_regulator_unregister(struct device *dev, struct regulator_dev *rdev) WARN_ON(rc); } EXPORT_SYMBOL_GPL(devm_regulator_unregister); + +struct regulator_supply_alias_match { + struct device *dev; + const char *id; +}; + +static int devm_regulator_match_supply_alias(struct device *dev, void *res, + void *data) +{ + struct regulator_supply_alias_match *match = res; + struct regulator_supply_alias_match *target = data; + + return match->dev == target->dev && strcmp(match->id, target->id) == 0; +} + +static void devm_regulator_destroy_supply_alias(struct device *dev, void *res) +{ + struct regulator_supply_alias_match *match = res; + + regulator_unregister_supply_alias(match->dev, match->id); +} + +/** + * devm_regulator_register_supply_alias - Resource managed + * regulator_register_supply_alias() + * + * @dev: device that will be given as the regulator "consumer" + * @id: Supply name or regulator ID + * @alias_dev: device that should be used to lookup the supply + * @alias_id: Supply name or regulator ID that should be used to lookup the + * supply + * + * The supply alias will automatically be unregistered when the source + * device is unbound. + */ +int devm_regulator_register_supply_alias(struct device *dev, const char *id, + struct device *alias_dev, + const char *alias_id) +{ + struct regulator_supply_alias_match *match; + int ret; + + match = devres_alloc(devm_regulator_destroy_supply_alias, + sizeof(struct regulator_supply_alias_match), + GFP_KERNEL); + if (!match) + return -ENOMEM; + + match->dev = dev; + match->id = id; + + ret = regulator_register_supply_alias(dev, id, alias_dev, alias_id); + if (ret < 0) { + devres_free(match); + return ret; + } + + devres_add(dev, match); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_regulator_register_supply_alias); + +/** + * devm_regulator_unregister_supply_alias - Resource managed + * regulator_unregister_supply_alias() + * + * @dev: device that will be given as the regulator "consumer" + * @id: Supply name or regulator ID + * + * Unregister an alias registered with + * devm_regulator_register_supply_alias(). Normally this function + * will not need to be called and the resource management code + * will ensure that the resource is freed. + */ +void devm_regulator_unregister_supply_alias(struct device *dev, const char *id) +{ + struct regulator_supply_alias_match match; + int rc; + + match.dev = dev; + match.id = id; + + rc = devres_release(dev, devm_regulator_destroy_supply_alias, + devm_regulator_match_supply_alias, &match); + if (rc != 0) + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_regulator_unregister_supply_alias); + +/** + * devm_regulator_bulk_register_supply_alias - Managed register + * multiple aliases + * + * @dev: device that will be given as the regulator "consumer" + * @id: List of supply names or regulator IDs + * @alias_dev: device that should be used to lookup the supply + * @alias_id: List of supply names or regulator IDs that should be used to + * lookup the supply + * @num_id: Number of aliases to register + * + * @return 0 on success, an errno on failure. + * + * This helper function allows drivers to register several supply + * aliases in one operation, the aliases will be automatically + * unregisters when the source device is unbound. If any of the + * aliases cannot be registered any aliases that were registered + * will be removed before returning to the caller. + */ +int devm_regulator_bulk_register_supply_alias(struct device *dev, + const char **id, + struct device *alias_dev, + const char **alias_id, + int num_id) +{ + int i; + int ret; + + for (i = 0; i < num_id; ++i) { + ret = devm_regulator_register_supply_alias(dev, id[i], + alias_dev, + alias_id[i]); + if (ret < 0) + goto err; + } + + return 0; + +err: + dev_err(dev, + "Failed to create supply alias %s,%s -> %s,%s\n", + id[i], dev_name(dev), alias_id[i], dev_name(alias_dev)); + + while (--i >= 0) + devm_regulator_unregister_supply_alias(dev, id[i]); + + return ret; +} +EXPORT_SYMBOL_GPL(devm_regulator_bulk_register_supply_alias); + +/** + * devm_regulator_bulk_unregister_supply_alias - Managed unregister + * multiple aliases + * + * @dev: device that will be given as the regulator "consumer" + * @id: List of supply names or regulator IDs + * @num_id: Number of aliases to unregister + * + * Unregister aliases registered with + * devm_regulator_bulk_register_supply_alias(). Normally this function + * will not need to be called and the resource management code + * will ensure that the resource is freed. + */ +void devm_regulator_bulk_unregister_supply_alias(struct device *dev, + const char **id, + int num_id) +{ + int i; + + for (i = 0; i < num_id; ++i) + devm_regulator_unregister_supply_alias(dev, id[i]); +} +EXPORT_SYMBOL_GPL(devm_regulator_bulk_unregister_supply_alias); diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 7610920014d7..5ea64b94341c 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -34,7 +34,6 @@ struct fixed_voltage_data { struct regulator_desc desc; struct regulator_dev *dev; - int microvolts; }; @@ -108,30 +107,7 @@ of_get_fixed_voltage_config(struct device *dev) return config; } -static int fixed_voltage_get_voltage(struct regulator_dev *dev) -{ - struct fixed_voltage_data *data = rdev_get_drvdata(dev); - - if (data->microvolts) - return data->microvolts; - else - return -EINVAL; -} - -static int fixed_voltage_list_voltage(struct regulator_dev *dev, - unsigned selector) -{ - struct fixed_voltage_data *data = rdev_get_drvdata(dev); - - if (selector != 0) - return -EINVAL; - - return data->microvolts; -} - static struct regulator_ops fixed_voltage_ops = { - .get_voltage = fixed_voltage_get_voltage, - .list_voltage = fixed_voltage_list_voltage, }; static int reg_fixed_voltage_probe(struct platform_device *pdev) @@ -186,23 +162,21 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) if (config->microvolts) drvdata->desc.n_voltages = 1; - drvdata->microvolts = config->microvolts; + drvdata->desc.fixed_uV = config->microvolts; if (config->gpio >= 0) cfg.ena_gpio = config->gpio; cfg.ena_gpio_invert = !config->enable_high; if (config->enabled_at_boot) { - if (config->enable_high) { + if (config->enable_high) cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; - } else { + else cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; - } } else { - if (config->enable_high) { + if (config->enable_high) cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; - } else { + else cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; - } } if (config->gpio_is_open_drain) cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN; @@ -222,7 +196,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) platform_set_drvdata(pdev, drvdata); dev_dbg(&pdev->dev, "%s supplying %duV\n", drvdata->desc.name, - drvdata->microvolts); + drvdata->desc.fixed_uV); return 0; diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index 98a98ffa7fe0..04406a918c04 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -283,7 +283,6 @@ static int gpio_regulator_probe(struct platform_device *pdev) dev_err(&pdev->dev, "No regulator type set\n"); ret = -EINVAL; goto err_memgpio; - break; } drvdata->nr_gpios = config->nr_gpios; diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index 6e30df14714b..e221a271ba56 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -284,9 +284,13 @@ int regulator_map_voltage_linear_range(struct regulator_dev *rdev, } for (i = 0; i < rdev->desc->n_linear_ranges; i++) { + int linear_max_uV; + range = &rdev->desc->linear_ranges[i]; + linear_max_uV = range->min_uV + + (range->max_sel - range->min_sel) * range->uV_step; - if (!(min_uV <= range->max_uV && max_uV >= range->min_uV)) + if (!(min_uV <= linear_max_uV && max_uV >= range->min_uV)) continue; if (min_uV <= range->min_uV) diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 5a4604ee5ea5..947c05ffe0ab 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -474,8 +474,8 @@ static int lp3971_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id lp3971_i2c_id[] = { - { "lp3971", 0 }, - { } + { "lp3971", 0 }, + { } }; MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id); diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 2b84b727a3c4..2e4734ff79fc 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -785,7 +785,7 @@ static int lp872x_regulator_register(struct lp872x *lp) struct regulator_desc *desc; struct regulator_config cfg = { }; struct regulator_dev *rdev; - int i, ret; + int i; for (i = 0; i < lp->num_regulators; i++) { desc = (lp->chipid == LP8720) ? &lp8720_regulator_desc[i] : @@ -796,34 +796,16 @@ static int lp872x_regulator_register(struct lp872x *lp) cfg.driver_data = lp; cfg.regmap = lp->regmap; - rdev = regulator_register(desc, &cfg); + rdev = devm_regulator_register(lp->dev, desc, &cfg); if (IS_ERR(rdev)) { dev_err(lp->dev, "regulator register err"); - ret = PTR_ERR(rdev); - goto err; + return PTR_ERR(rdev); } *(lp->regulators + i) = rdev; } return 0; -err: - while (--i >= 0) { - rdev = *(lp->regulators + i); - regulator_unregister(rdev); - } - return ret; -} - -static void lp872x_regulator_unregister(struct lp872x *lp) -{ - struct regulator_dev *rdev; - int i; - - for (i = 0; i < lp->num_regulators; i++) { - rdev = *(lp->regulators + i); - regulator_unregister(rdev); - } } static const struct regmap_config lp872x_regmap_config = { @@ -979,14 +961,6 @@ err_dev: return ret; } -static int lp872x_remove(struct i2c_client *cl) -{ - struct lp872x *lp = i2c_get_clientdata(cl); - - lp872x_regulator_unregister(lp); - return 0; -} - static const struct of_device_id lp872x_dt_ids[] = { { .compatible = "ti,lp8720", }, { .compatible = "ti,lp8725", }, @@ -1008,7 +982,6 @@ static struct i2c_driver lp872x_driver = { .of_match_table = of_match_ptr(lp872x_dt_ids), }, .probe = lp872x_probe, - .remove = lp872x_remove, .id_table = lp872x_ids, }; diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c index 0b015f2a7fd9..948afc249e29 100644 --- a/drivers/regulator/lp8788-buck.c +++ b/drivers/regulator/lp8788-buck.c @@ -515,7 +515,7 @@ static int lp8788_buck_probe(struct platform_device *pdev) cfg.driver_data = buck; cfg.regmap = lp->regmap; - rdev = regulator_register(&lp8788_buck_desc[id], &cfg); + rdev = devm_regulator_register(&pdev->dev, &lp8788_buck_desc[id], &cfg); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); dev_err(&pdev->dev, "BUCK%d regulator register err = %d\n", @@ -529,18 +529,8 @@ static int lp8788_buck_probe(struct platform_device *pdev) return 0; } -static int lp8788_buck_remove(struct platform_device *pdev) -{ - struct lp8788_buck *buck = platform_get_drvdata(pdev); - - regulator_unregister(buck->regulator); - - return 0; -} - static struct platform_driver lp8788_buck_driver = { .probe = lp8788_buck_probe, - .remove = lp8788_buck_remove, .driver = { .name = LP8788_DEV_BUCK, .owner = THIS_MODULE, diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c index 0527d87c6dd5..b9a29a29933f 100644 --- a/drivers/regulator/lp8788-ldo.c +++ b/drivers/regulator/lp8788-ldo.c @@ -543,7 +543,7 @@ static int lp8788_dldo_probe(struct platform_device *pdev) cfg.driver_data = ldo; cfg.regmap = lp->regmap; - rdev = regulator_register(&lp8788_dldo_desc[id], &cfg); + rdev = devm_regulator_register(&pdev->dev, &lp8788_dldo_desc[id], &cfg); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); dev_err(&pdev->dev, "DLDO%d regulator register err = %d\n", @@ -557,18 +557,8 @@ static int lp8788_dldo_probe(struct platform_device *pdev) return 0; } -static int lp8788_dldo_remove(struct platform_device *pdev) -{ - struct lp8788_ldo *ldo = platform_get_drvdata(pdev); - - regulator_unregister(ldo->regulator); - - return 0; -} - static struct platform_driver lp8788_dldo_driver = { .probe = lp8788_dldo_probe, - .remove = lp8788_dldo_remove, .driver = { .name = LP8788_DEV_DLDO, .owner = THIS_MODULE, @@ -603,7 +593,7 @@ static int lp8788_aldo_probe(struct platform_device *pdev) cfg.driver_data = ldo; cfg.regmap = lp->regmap; - rdev = regulator_register(&lp8788_aldo_desc[id], &cfg); + rdev = devm_regulator_register(&pdev->dev, &lp8788_aldo_desc[id], &cfg); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); dev_err(&pdev->dev, "ALDO%d regulator register err = %d\n", @@ -617,18 +607,8 @@ static int lp8788_aldo_probe(struct platform_device *pdev) return 0; } -static int lp8788_aldo_remove(struct platform_device *pdev) -{ - struct lp8788_ldo *ldo = platform_get_drvdata(pdev); - - regulator_unregister(ldo->regulator); - - return 0; -} - static struct platform_driver lp8788_aldo_driver = { .probe = lp8788_aldo_probe, - .remove = lp8788_aldo_remove, .driver = { .name = LP8788_DEV_ALDO, .owner = THIS_MODULE, diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index d80b5fa758ae..759510789e71 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -312,7 +312,7 @@ static int max8925_regulator_probe(struct platform_device *pdev) if (pdata) config.init_data = pdata; - rdev = regulator_register(&ri->desc, &config); + rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", ri->desc.name); @@ -323,22 +323,12 @@ static int max8925_regulator_probe(struct platform_device *pdev) return 0; } -static int max8925_regulator_remove(struct platform_device *pdev) -{ - struct regulator_dev *rdev = platform_get_drvdata(pdev); - - regulator_unregister(rdev); - - return 0; -} - static struct platform_driver max8925_regulator_driver = { .driver = { .name = "max8925-regulator", .owner = THIS_MODULE, }, .probe = max8925_regulator_probe, - .remove = max8925_regulator_remove, }; static int __init max8925_regulator_init(void) diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index bcd2488d1252..2d618fc9c1af 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -690,8 +690,9 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev, if (max8997->ignore_gpiodvs_side_effect == false) return -EINVAL; - dev_warn(&rdev->dev, "MAX8997 GPIO-DVS Side Effect Warning: GPIO SET:" - " %d -> %d\n", max8997->buck125_gpioindex, tmp_idx); + dev_warn(&rdev->dev, + "MAX8997 GPIO-DVS Side Effect Warning: GPIO SET: %d -> %d\n", + max8997->buck125_gpioindex, tmp_idx); out: if (new_idx < 0 || new_val < 0) diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index f036b26d4cfc..7f4a67edf780 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -258,34 +258,34 @@ static struct mc13xxx_regulator mc13783_regulators[] = { MC13783_FIXED_DEFINE(REG, VAUDIO, REGULATORMODE0, mc13783_vaudio_val), MC13783_FIXED_DEFINE(REG, VIOHI, REGULATORMODE0, mc13783_viohi_val), - MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0, REGULATORSETTING0, mc13783_violo_val), - MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, mc13783_vdig_val), - MC13783_DEFINE_REGU(VGEN, REGULATORMODE0, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VGEN, REGULATORMODE0, REGULATORSETTING0, mc13783_vgen_val), - MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0, REGULATORSETTING0, mc13783_vrfdig_val), - MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0, REGULATORSETTING0, mc13783_vrfref_val), - MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0, REGULATORSETTING0, mc13783_vrfcp_val), - MC13783_DEFINE_REGU(VSIM, REGULATORMODE1, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VSIM, REGULATORMODE1, REGULATORSETTING0, mc13783_vsim_val), - MC13783_DEFINE_REGU(VESIM, REGULATORMODE1, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VESIM, REGULATORMODE1, REGULATORSETTING0, mc13783_vesim_val), - MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \ + MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, mc13783_vcam_val), MC13783_FIXED_DEFINE(REG, VRFBG, REGULATORMODE1, mc13783_vrfbg_val), - MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1, \ + MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1, mc13783_vvib_val), - MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1, \ + MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1, mc13783_vrf_val), - MC13783_DEFINE_REGU(VRF2, REGULATORMODE1, REGULATORSETTING1, \ + MC13783_DEFINE_REGU(VRF2, REGULATORMODE1, REGULATORSETTING1, mc13783_vrf_val), - MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1, REGULATORSETTING1, \ + MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1, REGULATORSETTING1, mc13783_vmmc_val), - MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1, \ + MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1, mc13783_vmmc_val), MC13783_GPO_DEFINE(REG, GPO1, POWERMISC, mc13783_gpo_val), MC13783_GPO_DEFINE(REG, GPO2, POWERMISC, mc13783_gpo_val), diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 7827384680d6..ea4f36f2cbe2 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -23,6 +23,8 @@ static void of_get_regulation_constraints(struct device_node *np, const __be32 *min_uA, *max_uA, *ramp_delay; struct property *prop; struct regulation_constraints *constraints = &(*init_data)->constraints; + int ret; + u32 pval; constraints->name = of_get_property(np, "regulator-name", NULL); @@ -73,6 +75,10 @@ static void of_get_regulation_constraints(struct device_node *np, else constraints->ramp_disable = true; } + + ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval); + if (!ret) + constraints->enable_time = pval; } /** diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index d68f05b105b5..9c62b1d34685 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -229,13 +229,7 @@ static unsigned int palmas_smps_ramp_delay[4] = {0, 10000, 5000, 2500}; #define SMPS_CTRL_MODE_ECO 0x02 #define SMPS_CTRL_MODE_PWM 0x03 -/* These values are derived from the data sheet. And are the number of steps - * where there is a voltage change, the ranges at beginning and end of register - * max/min values where there are no change are ommitted. - * - * So they are basically (maxV-minV)/stepV - */ -#define PALMAS_SMPS_NUM_VOLTAGES 117 +#define PALMAS_SMPS_NUM_VOLTAGES 122 #define PALMAS_SMPS10_NUM_VOLTAGES 2 #define PALMAS_LDO_NUM_VOLTAGES 50 diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index b49eaeedea84..3727b7d0e9ac 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -246,7 +246,8 @@ static int pcap_regulator_probe(struct platform_device *pdev) config.init_data = dev_get_platdata(&pdev->dev); config.driver_data = pcap; - rdev = regulator_register(&pcap_regulators[pdev->id], &config); + rdev = devm_regulator_register(&pdev->dev, &pcap_regulators[pdev->id], + &config); if (IS_ERR(rdev)) return PTR_ERR(rdev); @@ -255,22 +256,12 @@ static int pcap_regulator_probe(struct platform_device *pdev) return 0; } -static int pcap_regulator_remove(struct platform_device *pdev) -{ - struct regulator_dev *rdev = platform_get_drvdata(pdev); - - regulator_unregister(rdev); - - return 0; -} - static struct platform_driver pcap_regulator_driver = { .driver = { .name = "pcap-regulator", .owner = THIS_MODULE, }, .probe = pcap_regulator_probe, - .remove = pcap_regulator_remove, }; static int __init pcap_regulator_init(void) diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index 0f3576d48abf..d7da1c15a6da 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -90,7 +90,8 @@ static int pcf50633_regulator_probe(struct platform_device *pdev) config.driver_data = pcf; config.regmap = pcf->regmap; - rdev = regulator_register(®ulators[pdev->id], &config); + rdev = devm_regulator_register(&pdev->dev, ®ulators[pdev->id], + &config); if (IS_ERR(rdev)) return PTR_ERR(rdev); @@ -102,21 +103,11 @@ static int pcf50633_regulator_probe(struct platform_device *pdev) return 0; } -static int pcf50633_regulator_remove(struct platform_device *pdev) -{ - struct regulator_dev *rdev = platform_get_drvdata(pdev); - - regulator_unregister(rdev); - - return 0; -} - static struct platform_driver pcf50633_regulator_driver = { .driver = { .name = "pcf50633-regltr", }, .probe = pcf50633_regulator_probe, - .remove = pcf50633_regulator_remove, }; static int __init pcf50633_regulator_init(void) diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c index 8c2a8195d8a7..20aab8f90e08 100644 --- a/drivers/regulator/ti-abb-regulator.c +++ b/drivers/regulator/ti-abb-regulator.c @@ -279,8 +279,12 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb, ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, regs->control_reg, abb->base); - /* program LDO VBB vset override if needed */ - if (abb->ldo_base) + /* + * program LDO VBB vset override if needed for !bypass mode + * XXX: Do not switch sequence - for !bypass, LDO override reset *must* + * be performed *before* switch to bias mode else VBB glitches. + */ + if (abb->ldo_base && info->opp_sel != TI_ABB_NOMINAL_OPP) ti_abb_program_ldovbb(dev, abb, info); /* Initiate ABB ldo change */ @@ -295,6 +299,14 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb, if (ret) goto out; + /* + * Reset LDO VBB vset override bypass mode + * XXX: Do not switch sequence - for bypass, LDO override reset *must* + * be performed *after* switch to bypass else VBB glitches. + */ + if (abb->ldo_base && info->opp_sel == TI_ABB_NOMINAL_OPP) + ti_abb_program_ldovbb(dev, abb, info); + out: return ret; } @@ -603,7 +615,7 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb, pname, *volt_table, vset_mask); continue; } - info->vset = efuse_val & vset_mask >> __ffs(vset_mask); + info->vset = (efuse_val & vset_mask) >> __ffs(vset_mask); dev_dbg(dev, "[%d]v=%d vset=%x\n", i, *volt_table, info->vset); check_abb: switch (info->opp_sel) { diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c index ec9453ffb77f..e0e818d89f46 100644 --- a/drivers/regulator/tps6105x-regulator.c +++ b/drivers/regulator/tps6105x-regulator.c @@ -146,8 +146,9 @@ static int tps6105x_regulator_probe(struct platform_device *pdev) config.driver_data = tps6105x; /* Register regulator with framework */ - tps6105x->regulator = regulator_register(&tps6105x_regulator_desc, - &config); + tps6105x->regulator = devm_regulator_register(&pdev->dev, + &tps6105x_regulator_desc, + &config); if (IS_ERR(tps6105x->regulator)) { ret = PTR_ERR(tps6105x->regulator); dev_err(&tps6105x->client->dev, @@ -159,20 +160,12 @@ static int tps6105x_regulator_probe(struct platform_device *pdev) return 0; } -static int tps6105x_regulator_remove(struct platform_device *pdev) -{ - struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev); - regulator_unregister(tps6105x->regulator); - return 0; -} - static struct platform_driver tps6105x_regulator_driver = { .driver = { .name = "tps6105x-regulator", .owner = THIS_MODULE, }, .probe = tps6105x_regulator_probe, - .remove = tps6105x_regulator_remove, }; static __init int tps6105x_regulator_init(void) diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 8860379fd6be..9ea1bf26bd13 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -52,25 +52,17 @@ static const unsigned int LDO1_VSEL_table[] = { }; static const struct regulator_linear_range tps65217_uv1_ranges[] = { - { .min_uV = 900000, .max_uV = 1500000, .min_sel = 0, .max_sel = 24, - .uV_step = 25000 }, - { .min_uV = 1550000, .max_uV = 1800000, .min_sel = 25, .max_sel = 30, - .uV_step = 50000 }, - { .min_uV = 1850000, .max_uV = 2900000, .min_sel = 31, .max_sel = 52, - .uV_step = 50000 }, - { .min_uV = 3000000, .max_uV = 3200000, .min_sel = 53, .max_sel = 55, - .uV_step = 100000 }, - { .min_uV = 3300000, .max_uV = 3300000, .min_sel = 56, .max_sel = 62, - .uV_step = 0 }, + REGULATOR_LINEAR_RANGE(900000, 0, 24, 25000), + REGULATOR_LINEAR_RANGE(1550000, 25, 30, 50000), + REGULATOR_LINEAR_RANGE(1850000, 31, 52, 50000), + REGULATOR_LINEAR_RANGE(3000000, 53, 55, 100000), + REGULATOR_LINEAR_RANGE(3300000, 56, 62, 0), }; static const struct regulator_linear_range tps65217_uv2_ranges[] = { - { .min_uV = 1500000, .max_uV = 1900000, .min_sel = 0, .max_sel = 8, - .uV_step = 50000 }, - { .min_uV = 2000000, .max_uV = 2400000, .min_sel = 9, .max_sel = 13, - .uV_step = 100000 }, - { .min_uV = 2450000, .max_uV = 3300000, .min_sel = 14, .max_sel = 31, - .uV_step = 50000 }, + REGULATOR_LINEAR_RANGE(1500000, 0, 8, 50000), + REGULATOR_LINEAR_RANGE(2000000, 9, 13, 100000), + REGULATOR_LINEAR_RANGE(2450000, 14, 31, 50000), }; static int tps65217_pmic_enable(struct regulator_dev *dev) diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 62e8d28beabd..9f6bfda711b7 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c @@ -577,21 +577,6 @@ static struct regulator_ops regulator_ops = { .get_current_limit = get_current_limit, }; -static int pmic_remove(struct spi_device *spi) -{ - struct tps6524x *hw = spi_get_drvdata(spi); - int i; - - if (!hw) - return 0; - for (i = 0; i < N_REGULATORS; i++) { - regulator_unregister(hw->rdev[i]); - hw->rdev[i] = NULL; - } - spi_set_drvdata(spi, NULL); - return 0; -} - static int pmic_probe(struct spi_device *spi) { struct tps6524x *hw; @@ -599,7 +584,7 @@ static int pmic_probe(struct spi_device *spi) const struct supply_info *info = supply_info; struct regulator_init_data *init_data; struct regulator_config config = { }; - int ret = 0, i; + int i; init_data = dev_get_platdata(dev); if (!init_data) { @@ -632,24 +617,17 @@ static int pmic_probe(struct spi_device *spi) config.init_data = init_data; config.driver_data = hw; - hw->rdev[i] = regulator_register(&hw->desc[i], &config); - if (IS_ERR(hw->rdev[i])) { - ret = PTR_ERR(hw->rdev[i]); - hw->rdev[i] = NULL; - goto fail; - } + hw->rdev[i] = devm_regulator_register(dev, &hw->desc[i], + &config); + if (IS_ERR(hw->rdev[i])) + return PTR_ERR(hw->rdev[i]); } return 0; - -fail: - pmic_remove(spi); - return ret; } static struct spi_driver pmic_driver = { .probe = pmic_probe, - .remove = pmic_remove, .driver = { .name = "tps6524x", .owner = THIS_MODULE, diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c index 1ed4d049abfe..9cafaa0f9455 100644 --- a/drivers/regulator/tps65912-regulator.c +++ b/drivers/regulator/tps65912-regulator.c @@ -119,12 +119,9 @@ struct tps65912_reg { }; static const struct regulator_linear_range tps65912_ldo_ranges[] = { - { .min_uV = 800000, .max_uV = 1600000, .min_sel = 0, .max_sel = 32, - .uV_step = 25000 }, - { .min_uV = 1650000, .max_uV = 3000000, .min_sel = 33, .max_sel = 60, - .uV_step = 50000 }, - { .min_uV = 3100000, .max_uV = 3300000, .min_sel = 61, .max_sel = 63, - .uV_step = 100000 }, + REGULATOR_LINEAR_RANGE(800000, 0, 32, 25000), + REGULATOR_LINEAR_RANGE(1650000, 33, 60, 50000), + REGULATOR_LINEAR_RANGE(3100000, 61, 63, 100000), }; static int tps65912_get_range(struct tps65912_reg *pmic, int id) diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 78aae4cbb004..8ebd785485c7 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -1188,7 +1188,7 @@ static int twlreg_probe(struct platform_device *pdev) config.driver_data = info; config.of_node = pdev->dev.of_node; - rdev = regulator_register(&info->desc, &config); + rdev = devm_regulator_register(&pdev->dev, &info->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "can't register %s, %ld\n", info->desc.name, PTR_ERR(rdev)); @@ -1217,7 +1217,6 @@ static int twlreg_remove(struct platform_device *pdev) struct regulator_dev *rdev = platform_get_drvdata(pdev); struct twlreg_info *info = rdev->reg_data; - regulator_unregister(rdev); kfree(info); return 0; } diff --git a/drivers/regulator/vexpress.c b/drivers/regulator/vexpress.c index 4668c7f8133d..f3ae28a7e663 100644 --- a/drivers/regulator/vexpress.c +++ b/drivers/regulator/vexpress.c @@ -96,7 +96,7 @@ static int vexpress_regulator_probe(struct platform_device *pdev) config.driver_data = reg; config.of_node = pdev->dev.of_node; - reg->regdev = regulator_register(®->desc, &config); + reg->regdev = devm_regulator_register(&pdev->dev, ®->desc, &config); if (IS_ERR(reg->regdev)) { err = PTR_ERR(reg->regdev); goto error_regulator_register; @@ -119,7 +119,6 @@ static int vexpress_regulator_remove(struct platform_device *pdev) struct vexpress_regulator *reg = platform_get_drvdata(pdev); vexpress_config_func_put(reg->func); - regulator_unregister(reg->regdev); return 0; } diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 2be72fe36535..46d6700467b5 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -63,10 +63,8 @@ static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data) */ static const struct regulator_linear_range wm831x_gp_ldo_ranges[] = { - { .min_uV = 900000, .max_uV = 1650000, .min_sel = 0, .max_sel = 14, - .uV_step = 50000 }, - { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31, - .uV_step = 100000 }, + REGULATOR_LINEAR_RANGE(900000, 0, 14, 50000), + REGULATOR_LINEAR_RANGE(1700000, 15, 31, 100000), }; static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, @@ -320,10 +318,8 @@ static struct platform_driver wm831x_gp_ldo_driver = { */ static const struct regulator_linear_range wm831x_aldo_ranges[] = { - { .min_uV = 1000000, .max_uV = 1650000, .min_sel = 0, .max_sel = 12, - .uV_step = 50000 }, - { .min_uV = 1700000, .max_uV = 3500000, .min_sel = 13, .max_sel = 31, - .uV_step = 100000 }, + REGULATOR_LINEAR_RANGE(1000000, 0, 12, 50000), + REGULATOR_LINEAR_RANGE(1700000, 13, 31, 100000), }; static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index a438e937cfa0..de7b9c73e3fa 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -543,10 +543,8 @@ static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev, } static const struct regulator_linear_range wm8350_ldo_ranges[] = { - { .min_uV = 900000, .max_uV = 1750000, .min_sel = 0, .max_sel = 15, - .uV_step = 50000 }, - { .min_uV = 1800000, .max_uV = 3300000, .min_sel = 16, .max_sel = 31, - .uV_step = 100000 }, + REGULATOR_LINEAR_RANGE(900000, 0, 15, 50000), + REGULATOR_LINEAR_RANGE(1800000, 16, 31, 100000), }; static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV) diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 870b52f709bc..82d829000851 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -20,10 +20,8 @@ #include <linux/mfd/wm8400-private.h> static const struct regulator_linear_range wm8400_ldo_ranges[] = { - { .min_uV = 900000, .max_uV = 1600000, .min_sel = 0, .max_sel = 14, - .uV_step = 50000 }, - { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31, - .uV_step = 100000 }, + REGULATOR_LINEAR_RANGE(900000, 0, 14, 50000), + REGULATOR_LINEAR_RANGE(1700000, 15, 31, 100000), }; static struct regulator_ops wm8400_ldo_ops = { |