diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2019-07-10 23:24:10 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2019-07-10 23:24:10 -0700 |
commit | 597473720f4dc69749542bfcfed4a927a43d935e (patch) | |
tree | 711bf773910fb93d1dd9120c633adc807685e0d8 /drivers/regulator | |
parent | Input: atmel_mxt_ts - fix leak in mxt_update_cfg() (diff) | |
parent | Input: gpio_keys_polled - allow specifying name of input device (diff) | |
download | linux-dev-597473720f4dc69749542bfcfed4a927a43d935e.tar.xz linux-dev-597473720f4dc69749542bfcfed4a927a43d935e.zip |
Merge branch 'next' into for-linus
Prepare input updates for 5.3 merge window.
Diffstat (limited to 'drivers/regulator')
79 files changed, 4832 insertions, 1951 deletions
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index fd86446e499b..753a6a1b30c3 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -11,7 +11,6 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/err.h> -#include <linux/i2c.h> #include <linux/of.h> #include <linux/regulator/of_regulator.h> #include <linux/platform_device.h> @@ -22,12 +21,7 @@ struct pm8607_regulator_info { struct regulator_desc desc; - struct pm860x_chip *chip; - struct regulator_dev *regulator; - struct i2c_client *i2c; - struct i2c_client *i2c_8606; - unsigned int *vol_table; unsigned int *vol_suspend; int slope_double; @@ -210,13 +204,15 @@ static const unsigned int LDO14_suspend_table[] = { static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - int ret = -EINVAL; + int ret; + + ret = regulator_list_voltage_table(rdev, index); + if (ret < 0) + return ret; + + if (info->slope_double) + ret <<= 1; - if (info->vol_table && (index < rdev->desc->n_voltages)) { - ret = info->vol_table[index]; - if (info->slope_double) - ret <<= 1; - } return ret; } @@ -257,6 +253,7 @@ static const struct regulator_ops pm8606_preg_ops = { .type = REGULATOR_VOLTAGE, \ .id = PM8607_ID_##vreg, \ .owner = THIS_MODULE, \ + .volt_table = vreg##_table, \ .n_voltages = ARRAY_SIZE(vreg##_table), \ .vsel_reg = PM8607_##vreg, \ .vsel_mask = ARRAY_SIZE(vreg##_table) - 1, \ @@ -266,7 +263,6 @@ static const struct regulator_ops pm8606_preg_ops = { .enable_mask = 1 << (ebit), \ }, \ .slope_double = (0), \ - .vol_table = (unsigned int *)&vreg##_table, \ .vol_suspend = (unsigned int *)&vreg##_suspend_table, \ } @@ -278,6 +274,7 @@ static const struct regulator_ops pm8606_preg_ops = { .type = REGULATOR_VOLTAGE, \ .id = PM8607_ID_LDO##_id, \ .owner = THIS_MODULE, \ + .volt_table = LDO##_id##_table, \ .n_voltages = ARRAY_SIZE(LDO##_id##_table), \ .vsel_reg = PM8607_##vreg, \ .vsel_mask = (ARRAY_SIZE(LDO##_id##_table) - 1) << (shift), \ @@ -285,7 +282,6 @@ static const struct regulator_ops pm8606_preg_ops = { .enable_mask = 1 << (ebit), \ }, \ .slope_double = (0), \ - .vol_table = (unsigned int *)&LDO##_id##_table, \ .vol_suspend = (unsigned int *)&LDO##_id##_suspend_table, \ } @@ -328,7 +324,7 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev, return -ENODEV; } for_each_child_of_node(nproot, np) { - if (!of_node_cmp(np->name, info->desc.name)) { + if (of_node_name_eq(np, info->desc.name)) { config->init_data = of_get_regulator_init_data(&pdev->dev, np, &info->desc); @@ -349,6 +345,7 @@ static int pm8607_regulator_probe(struct platform_device *pdev) struct pm8607_regulator_info *info = NULL; struct regulator_init_data *pdata = dev_get_platdata(&pdev->dev); struct regulator_config config = { }; + struct regulator_dev *rdev; struct resource *res; int i; @@ -371,13 +368,9 @@ static int pm8607_regulator_probe(struct platform_device *pdev) /* i is used to check regulator ID */ i = -1; } - info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; - info->i2c_8606 = (chip->id == CHIP_PM8607) ? chip->companion : - chip->client; - info->chip = chip; /* check DVC ramp slope double */ - if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double) + if ((i == PM8607_ID_BUCK3) && chip->buck3_double) info->slope_double = 1; config.dev = &pdev->dev; @@ -392,12 +385,11 @@ static int pm8607_regulator_probe(struct platform_device *pdev) else config.regmap = chip->regmap_companion; - info->regulator = devm_regulator_register(&pdev->dev, &info->desc, - &config); - if (IS_ERR(info->regulator)) { + rdev = devm_regulator_register(&pdev->dev, &info->desc, &config); + if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", info->desc.name); - return PTR_ERR(info->regulator); + return PTR_ERR(rdev); } platform_set_drvdata(pdev, info); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 926cee0d0b5f..b7f249ee5e68 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -180,6 +180,17 @@ config REGULATOR_BCM590XX BCM590xx PMUs. This will enable support for the software controllable LDO/Switching regulators. +config REGULATOR_BD70528 + tristate "ROHM BD70528 Power Regulator" + depends on MFD_ROHM_BD70528 + help + This driver supports voltage regulators on ROHM BD70528 PMIC. + This will enable support for the software controllable buck + and LDO regulators. + + This driver can also be built as a module. If so, the module + will be called bd70528-regulator. + config REGULATOR_BD718XX tristate "ROHM BD71837 Power Regulator" depends on MFD_ROHM_BD718XX @@ -457,6 +468,14 @@ config REGULATOR_MAX77620 chip to control Step-Down DC-DC and LDOs. Say Y here to enable the regulator driver. +config REGULATOR_MAX77650 + tristate "Maxim MAX77650/77651 regulator support" + depends on MFD_MAX77650 + help + Regulator driver for MAX77650/77651 PMIC from Maxim + Semiconductor. This device has a SIMO with three independent + power rails and an LDO. + config REGULATOR_MAX8649 tristate "Maxim 8649 voltage regulator" depends on I2C @@ -484,7 +503,7 @@ config REGULATOR_MAX8925 tristate "Maxim MAX8925 Power Management IC" depends on MFD_MAX8925 help - Say y here to support the voltage regulaltor of Maxim MAX8925 PMIC. + Say y here to support the voltage regulator of Maxim MAX8925 PMIC. config REGULATOR_MAX8952 tristate "Maxim MAX8952 Power Management IC" @@ -501,7 +520,7 @@ config REGULATOR_MAX8973 select REGMAP_I2C help The MAXIM MAX8973 high-efficiency. three phase, DC-DC step-down - switching regulator delievers up to 9A of output current. Each + switching regulator delivers up to 9A of output current. Each phase operates at a 2MHz fixed frequency with a 120 deg shift from the adjacent phase, allowing the use of small magnetic component. @@ -567,6 +586,16 @@ config REGULATOR_MC13892 Say y here to support the regulators found on the Freescale MC13892 PMIC. +config REGULATOR_MCP16502 + tristate "Microchip MCP16502 PMIC" + depends on I2C && OF + select REGMAP_I2C + help + Say y here to support the MCP16502 PMIC. This driver supports + basic operations (get/set voltage, get/set operating mode) + through the regulator interface. In addition it enables + suspend-to-ram/standby transition. + config REGULATOR_MT6311 tristate "MediaTek MT6311 PMIC" depends on I2C @@ -636,7 +665,7 @@ config REGULATOR_PCF50633 tristate "NXP PCF50633 regulator driver" depends on MFD_PCF50633 help - Say Y here to support the voltage regulators and convertors + Say Y here to support the voltage regulators and converters on PCF50633 config REGULATOR_PFUZE100 @@ -914,7 +943,7 @@ config REGULATOR_TPS65132 select REGMAP_I2C help This driver supports TPS65132 single inductor - dual output - power supply specifcally designed for display panels. + power supply specifically designed for display panels. config REGULATOR_TPS65217 tristate "TI TPS65217 Power regulators" diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 72488ef11b8a..1169f8a27d91 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o +obj-$(CONFIG_REGULATOR_BD70528) += bd70528-regulator.o obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o @@ -60,6 +61,7 @@ obj-$(CONFIG_REGULATOR_LTC3676) += ltc3676.o obj-$(CONFIG_REGULATOR_MAX14577) += max14577-regulator.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o +obj-$(CONFIG_REGULATOR_MAX77650) += max77650-regulator.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o @@ -74,6 +76,7 @@ obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o +obj-$(CONFIG_REGULATOR_MCP16502) += mcp16502.o obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 21e20483bd91..e0239cf3f56d 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -131,7 +131,7 @@ * ACT8865 voltage number */ #define ACT8865_VOLTAGE_NUM 64 -#define ACT8600_SUDCDC_VOLTAGE_NUM 255 +#define ACT8600_SUDCDC_VOLTAGE_NUM 256 struct act8865 { struct regmap *regmap; @@ -222,7 +222,8 @@ static const struct regulator_linear_range act8600_sudcdc_voltage_ranges[] = { REGULATOR_LINEAR_RANGE(3000000, 0, 63, 0), REGULATOR_LINEAR_RANGE(3000000, 64, 159, 100000), REGULATOR_LINEAR_RANGE(12600000, 160, 191, 200000), - REGULATOR_LINEAR_RANGE(19000000, 191, 255, 400000), + REGULATOR_LINEAR_RANGE(19000000, 192, 247, 400000), + REGULATOR_LINEAR_RANGE(41400000, 248, 255, 0), }; static struct regulator_ops act8865_ops = { diff --git a/drivers/regulator/act8945a-regulator.c b/drivers/regulator/act8945a-regulator.c index 43fda8b4455a..caa61d306a69 100644 --- a/drivers/regulator/act8945a-regulator.c +++ b/drivers/regulator/act8945a-regulator.c @@ -15,31 +15,41 @@ #include <linux/module.h> #include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <dt-bindings/regulator/active-semi,8945a-regulator.h> /** * ACT8945A Global Register Map. */ #define ACT8945A_SYS_MODE 0x00 #define ACT8945A_SYS_CTRL 0x01 +#define ACT8945A_SYS_UNLK_REGS 0x0b #define ACT8945A_DCDC1_VSET1 0x20 #define ACT8945A_DCDC1_VSET2 0x21 #define ACT8945A_DCDC1_CTRL 0x22 +#define ACT8945A_DCDC1_SUS 0x24 #define ACT8945A_DCDC2_VSET1 0x30 #define ACT8945A_DCDC2_VSET2 0x31 #define ACT8945A_DCDC2_CTRL 0x32 +#define ACT8945A_DCDC2_SUS 0x34 #define ACT8945A_DCDC3_VSET1 0x40 #define ACT8945A_DCDC3_VSET2 0x41 #define ACT8945A_DCDC3_CTRL 0x42 +#define ACT8945A_DCDC3_SUS 0x44 #define ACT8945A_LDO1_VSET 0x50 #define ACT8945A_LDO1_CTRL 0x51 +#define ACT8945A_LDO1_SUS 0x52 #define ACT8945A_LDO2_VSET 0x54 #define ACT8945A_LDO2_CTRL 0x55 +#define ACT8945A_LDO2_SUS 0x56 #define ACT8945A_LDO3_VSET 0x60 #define ACT8945A_LDO3_CTRL 0x61 +#define ACT8945A_LDO3_SUS 0x62 #define ACT8945A_LDO4_VSET 0x64 #define ACT8945A_LDO4_CTRL 0x65 +#define ACT8945A_LDO4_SUS 0x66 /** * Field Definitions. @@ -60,7 +70,12 @@ enum { ACT8945A_ID_LDO2, ACT8945A_ID_LDO3, ACT8945A_ID_LDO4, - ACT8945A_REG_NUM, + ACT8945A_ID_MAX, +}; + +struct act8945a_pmic { + struct regmap *regmap; + u32 op_mode[ACT8945A_ID_MAX]; }; static const struct regulator_linear_range act8945a_voltage_ranges[] = { @@ -69,6 +84,144 @@ static const struct regulator_linear_range act8945a_voltage_ranges[] = { REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000), }; +static int act8945a_set_suspend_state(struct regulator_dev *rdev, bool enable) +{ + struct regmap *regmap = rdev->regmap; + int id = rdev_get_id(rdev); + int reg, val; + + switch (id) { + case ACT8945A_ID_DCDC1: + reg = ACT8945A_DCDC1_SUS; + val = 0xa8; + break; + case ACT8945A_ID_DCDC2: + reg = ACT8945A_DCDC2_SUS; + val = 0xa8; + break; + case ACT8945A_ID_DCDC3: + reg = ACT8945A_DCDC3_SUS; + val = 0xa8; + break; + case ACT8945A_ID_LDO1: + reg = ACT8945A_LDO1_SUS; + val = 0xe8; + break; + case ACT8945A_ID_LDO2: + reg = ACT8945A_LDO2_SUS; + val = 0xe8; + break; + case ACT8945A_ID_LDO3: + reg = ACT8945A_LDO3_SUS; + val = 0xe8; + break; + case ACT8945A_ID_LDO4: + reg = ACT8945A_LDO4_SUS; + val = 0xe8; + break; + default: + return -EINVAL; + } + + if (enable) + val |= BIT(4); + + /* + * Ask the PMIC to enable/disable this output when entering hibernate + * mode. + */ + return regmap_write(regmap, reg, val); +} + +static int act8945a_set_suspend_enable(struct regulator_dev *rdev) +{ + return act8945a_set_suspend_state(rdev, true); +} + +static int act8945a_set_suspend_disable(struct regulator_dev *rdev) +{ + return act8945a_set_suspend_state(rdev, false); +} + +static unsigned int act8945a_of_map_mode(unsigned int mode) +{ + switch (mode) { + case ACT8945A_REGULATOR_MODE_FIXED: + case ACT8945A_REGULATOR_MODE_NORMAL: + return REGULATOR_MODE_NORMAL; + case ACT8945A_REGULATOR_MODE_LOWPOWER: + return REGULATOR_MODE_STANDBY; + default: + return REGULATOR_MODE_INVALID; + } +} + +static int act8945a_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct act8945a_pmic *act8945a = rdev_get_drvdata(rdev); + struct regmap *regmap = rdev->regmap; + int id = rdev_get_id(rdev); + int reg, ret, val = 0; + + switch (id) { + case ACT8945A_ID_DCDC1: + reg = ACT8945A_DCDC1_CTRL; + break; + case ACT8945A_ID_DCDC2: + reg = ACT8945A_DCDC2_CTRL; + break; + case ACT8945A_ID_DCDC3: + reg = ACT8945A_DCDC3_CTRL; + break; + case ACT8945A_ID_LDO1: + reg = ACT8945A_LDO1_SUS; + break; + case ACT8945A_ID_LDO2: + reg = ACT8945A_LDO2_SUS; + break; + case ACT8945A_ID_LDO3: + reg = ACT8945A_LDO3_SUS; + break; + case ACT8945A_ID_LDO4: + reg = ACT8945A_LDO4_SUS; + break; + default: + return -EINVAL; + } + + switch (mode) { + case REGULATOR_MODE_STANDBY: + if (id > ACT8945A_ID_DCDC3) + val = BIT(5); + break; + case REGULATOR_MODE_NORMAL: + if (id <= ACT8945A_ID_DCDC3) + val = BIT(5); + break; + default: + return -EINVAL; + } + + ret = regmap_update_bits(regmap, reg, BIT(5), val); + if (ret) + return ret; + + act8945a->op_mode[id] = mode; + + return 0; +} + +static unsigned int act8945a_get_mode(struct regulator_dev *rdev) +{ + struct act8945a_pmic *act8945a = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + + if (id < ACT8945A_ID_DCDC1 || id >= ACT8945A_ID_MAX) + return -EINVAL; + + return act8945a->op_mode[id]; +} + static const struct regulator_ops act8945a_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, @@ -76,7 +229,11 @@ static const struct regulator_ops act8945a_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, + .set_mode = act8945a_set_mode, + .get_mode = act8945a_get_mode, .is_enabled = regulator_is_enabled_regmap, + .set_suspend_enable = act8945a_set_suspend_enable, + .set_suspend_disable = act8945a_set_suspend_disable, }; #define ACT89xx_REG(_name, _family, _id, _vsel_reg, _supply) \ @@ -84,6 +241,7 @@ static const struct regulator_ops act8945a_ops = { .name = _name, \ .supply_name = _supply, \ .of_match = of_match_ptr("REG_"#_id), \ + .of_map_mode = act8945a_of_map_mode, \ .regulators_node = of_match_ptr("regulators"), \ .id = _family##_ID_##_id, \ .type = REGULATOR_VOLTAGE, \ @@ -122,10 +280,22 @@ static int act8945a_pmic_probe(struct platform_device *pdev) { struct regulator_config config = { }; const struct regulator_desc *regulators; + struct act8945a_pmic *act8945a; struct regulator_dev *rdev; int i, num_regulators; bool voltage_select; + act8945a = devm_kzalloc(&pdev->dev, sizeof(*act8945a), GFP_KERNEL); + if (!act8945a) + return -ENOMEM; + + act8945a->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!act8945a->regmap) { + dev_err(&pdev->dev, + "could not retrieve regmap from parent device\n"); + return -EINVAL; + } + voltage_select = of_property_read_bool(pdev->dev.parent->of_node, "active-semi,vsel-high"); @@ -139,8 +309,10 @@ static int act8945a_pmic_probe(struct platform_device *pdev) config.dev = &pdev->dev; config.dev->of_node = pdev->dev.parent->of_node; + config.driver_data = act8945a; for (i = 0; i < num_regulators; i++) { - rdev = devm_regulator_register(&pdev->dev, ®ulators[i], &config); + rdev = devm_regulator_register(&pdev->dev, ®ulators[i], + &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s regulator\n", @@ -149,14 +321,42 @@ static int act8945a_pmic_probe(struct platform_device *pdev) } } - return 0; + platform_set_drvdata(pdev, act8945a); + + /* Unlock expert registers. */ + return regmap_write(act8945a->regmap, ACT8945A_SYS_UNLK_REGS, 0xef); +} + +static int __maybe_unused act8945a_suspend(struct device *pdev) +{ + struct act8945a_pmic *act8945a = dev_get_drvdata(pdev); + + /* + * Ask the PMIC to enter the suspend mode on the next PWRHLD + * transition. + */ + return regmap_write(act8945a->regmap, ACT8945A_SYS_CTRL, 0x42); +} + +static SIMPLE_DEV_PM_OPS(act8945a_pm, act8945a_suspend, NULL); + +static void act8945a_pmic_shutdown(struct platform_device *pdev) +{ + struct act8945a_pmic *act8945a = platform_get_drvdata(pdev); + + /* + * Ask the PMIC to shutdown everything on the next PWRHLD transition. + */ + regmap_write(act8945a->regmap, ACT8945A_SYS_CTRL, 0x0); } static struct platform_driver act8945a_pmic_driver = { .driver = { .name = "act8945a-regulator", + .pm = &act8945a_pm, }, .probe = act8945a_pmic_probe, + .shutdown = act8945a_pmic_shutdown, }; module_platform_driver(act8945a_pmic_driver); diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index 9a72eae4926d..bf3ab405eed1 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -40,35 +40,10 @@ struct arizona_ldo1 { struct gpio_desc *ena_gpiod; }; -static int arizona_ldo1_hc_list_voltage(struct regulator_dev *rdev, - unsigned int selector) -{ - if (selector >= rdev->desc->n_voltages) - return -EINVAL; - - if (selector == rdev->desc->n_voltages - 1) - return 1800000; - else - return rdev->desc->min_uV + (rdev->desc->uV_step * selector); -} - -static int arizona_ldo1_hc_map_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int sel; - - sel = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step); - if (sel >= rdev->desc->n_voltages) - sel = rdev->desc->n_voltages - 1; - - return sel; -} - static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev, unsigned sel) { - struct arizona_ldo1 *ldo = rdev_get_drvdata(rdev); - struct regmap *regmap = ldo->regmap; + struct regmap *regmap = rdev_get_regmap(rdev); unsigned int val; int ret; @@ -85,16 +60,12 @@ static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev, if (val) return 0; - val = sel << ARIZONA_LDO1_VSEL_SHIFT; - - return regmap_update_bits(regmap, ARIZONA_LDO1_CONTROL_1, - ARIZONA_LDO1_VSEL_MASK, val); + return regulator_set_voltage_sel_regmap(rdev, sel); } static int arizona_ldo1_hc_get_voltage_sel(struct regulator_dev *rdev) { - struct arizona_ldo1 *ldo = rdev_get_drvdata(rdev); - struct regmap *regmap = ldo->regmap; + struct regmap *regmap = rdev_get_regmap(rdev); unsigned int val; int ret; @@ -105,32 +76,35 @@ static int arizona_ldo1_hc_get_voltage_sel(struct regulator_dev *rdev) if (val & ARIZONA_LDO1_HI_PWR) return rdev->desc->n_voltages - 1; - ret = regmap_read(regmap, ARIZONA_LDO1_CONTROL_1, &val); - if (ret != 0) - return ret; - - return (val & ARIZONA_LDO1_VSEL_MASK) >> ARIZONA_LDO1_VSEL_SHIFT; + return regulator_get_voltage_sel_regmap(rdev); } static const struct regulator_ops arizona_ldo1_hc_ops = { - .list_voltage = arizona_ldo1_hc_list_voltage, - .map_voltage = arizona_ldo1_hc_map_voltage, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, .get_voltage_sel = arizona_ldo1_hc_get_voltage_sel, .set_voltage_sel = arizona_ldo1_hc_set_voltage_sel, .get_bypass = regulator_get_bypass_regmap, .set_bypass = regulator_set_bypass_regmap, }; +static const struct regulator_linear_range arizona_ldo1_hc_ranges[] = { + REGULATOR_LINEAR_RANGE(900000, 0, 0x6, 50000), + REGULATOR_LINEAR_RANGE(1800000, 0x7, 0x7, 0), +}; + static const struct regulator_desc arizona_ldo1_hc = { .name = "LDO1", .supply_name = "LDOVDD", .type = REGULATOR_VOLTAGE, .ops = &arizona_ldo1_hc_ops, + .vsel_reg = ARIZONA_LDO1_CONTROL_1, + .vsel_mask = ARIZONA_LDO1_VSEL_MASK, .bypass_reg = ARIZONA_LDO1_CONTROL_1, .bypass_mask = ARIZONA_LDO1_BYPASS, - .min_uV = 900000, - .uV_step = 50000, + .linear_ranges = arizona_ldo1_hc_ranges, + .n_linear_ranges = ARRAY_SIZE(arizona_ldo1_hc_ranges), .n_voltages = 8, .enable_time = 1500, .ramp_delay = 24000, @@ -283,9 +257,6 @@ static int arizona_ldo1_common_init(struct platform_device *pdev, of_node_put(config.of_node); if (IS_ERR(ldo1->regulator)) { - if (config.ena_gpiod) - gpiod_put(config.ena_gpiod); - ret = PTR_ERR(ldo1->regulator); dev_err(&pdev->dev, "Failed to register LDO1 supply: %d\n", ret); diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c index 565a71343a8e..f7fe218bb3e4 100644 --- a/drivers/regulator/as3711-regulator.c +++ b/drivers/regulator/as3711-regulator.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * AS3711 PMIC regulator driver, using DCDC Step Down and LDO supplies * * Copyright (C) 2012 Renesas Electronics Corporation * Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the version 2 of the GNU General Public License as - * published by the Free Software Foundation */ #include <linux/err.h> diff --git a/drivers/regulator/as3722-regulator.c b/drivers/regulator/as3722-regulator.c index 66337e12719b..e5fed289b52d 100644 --- a/drivers/regulator/as3722-regulator.c +++ b/drivers/regulator/as3722-regulator.c @@ -886,7 +886,7 @@ static int as3722_regulator_probe(struct platform_device *pdev) as3722_regs->desc[id].min_uV = 410000; } else { as3722_regs->desc[id].n_voltages = - AS3722_SD0_VSEL_MAX + 1, + AS3722_SD0_VSEL_MAX + 1; as3722_regs->desc[id].min_uV = 610000; } as3722_regs->desc[id].uV_step = 10000; diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index a3734039a86a..fba8f58ab769 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -13,31 +13,262 @@ * GNU General Public License for more details. */ +#include <linux/bitops.h> +#include <linux/delay.h> #include <linux/err.h> #include <linux/init.h> +#include <linux/mfd/axp20x.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/regmap.h> -#include <linux/mfd/axp20x.h> #include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> +#define AXP20X_GPIO0_FUNC_MASK GENMASK(3, 0) +#define AXP20X_GPIO1_FUNC_MASK GENMASK(3, 0) + #define AXP20X_IO_ENABLED 0x03 #define AXP20X_IO_DISABLED 0x07 +#define AXP20X_WORKMODE_DCDC2_MASK BIT_MASK(2) +#define AXP20X_WORKMODE_DCDC3_MASK BIT_MASK(1) + +#define AXP20X_FREQ_DCDC_MASK GENMASK(3, 0) + +#define AXP20X_VBUS_IPSOUT_MGMT_MASK BIT_MASK(2) + +#define AXP20X_DCDC2_V_OUT_MASK GENMASK(5, 0) +#define AXP20X_DCDC3_V_OUT_MASK GENMASK(7, 0) +#define AXP20X_LDO24_V_OUT_MASK GENMASK(7, 4) +#define AXP20X_LDO3_V_OUT_MASK GENMASK(6, 0) +#define AXP20X_LDO5_V_OUT_MASK GENMASK(7, 4) + +#define AXP20X_PWR_OUT_EXTEN_MASK BIT_MASK(0) +#define AXP20X_PWR_OUT_DCDC3_MASK BIT_MASK(1) +#define AXP20X_PWR_OUT_LDO2_MASK BIT_MASK(2) +#define AXP20X_PWR_OUT_LDO4_MASK BIT_MASK(3) +#define AXP20X_PWR_OUT_DCDC2_MASK BIT_MASK(4) +#define AXP20X_PWR_OUT_LDO3_MASK BIT_MASK(6) + +#define AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_RATE_MASK BIT_MASK(0) +#define AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_RATE(x) \ + ((x) << 0) +#define AXP20X_DCDC2_LDO3_V_RAMP_LDO3_RATE_MASK BIT_MASK(1) +#define AXP20X_DCDC2_LDO3_V_RAMP_LDO3_RATE(x) \ + ((x) << 1) +#define AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN_MASK BIT_MASK(2) +#define AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN BIT(2) +#define AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN_MASK BIT_MASK(3) +#define AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN BIT(3) + +#define AXP20X_LDO4_V_OUT_1250mV_START 0x0 +#define AXP20X_LDO4_V_OUT_1250mV_STEPS 0 +#define AXP20X_LDO4_V_OUT_1250mV_END \ + (AXP20X_LDO4_V_OUT_1250mV_START + AXP20X_LDO4_V_OUT_1250mV_STEPS) +#define AXP20X_LDO4_V_OUT_1300mV_START 0x1 +#define AXP20X_LDO4_V_OUT_1300mV_STEPS 7 +#define AXP20X_LDO4_V_OUT_1300mV_END \ + (AXP20X_LDO4_V_OUT_1300mV_START + AXP20X_LDO4_V_OUT_1300mV_STEPS) +#define AXP20X_LDO4_V_OUT_2500mV_START 0x9 +#define AXP20X_LDO4_V_OUT_2500mV_STEPS 0 +#define AXP20X_LDO4_V_OUT_2500mV_END \ + (AXP20X_LDO4_V_OUT_2500mV_START + AXP20X_LDO4_V_OUT_2500mV_STEPS) +#define AXP20X_LDO4_V_OUT_2700mV_START 0xa +#define AXP20X_LDO4_V_OUT_2700mV_STEPS 1 +#define AXP20X_LDO4_V_OUT_2700mV_END \ + (AXP20X_LDO4_V_OUT_2700mV_START + AXP20X_LDO4_V_OUT_2700mV_STEPS) +#define AXP20X_LDO4_V_OUT_3000mV_START 0xc +#define AXP20X_LDO4_V_OUT_3000mV_STEPS 3 +#define AXP20X_LDO4_V_OUT_3000mV_END \ + (AXP20X_LDO4_V_OUT_3000mV_START + AXP20X_LDO4_V_OUT_3000mV_STEPS) +#define AXP20X_LDO4_V_OUT_NUM_VOLTAGES 16 + #define AXP22X_IO_ENABLED 0x03 #define AXP22X_IO_DISABLED 0x04 -#define AXP20X_WORKMODE_DCDC2_MASK BIT(2) -#define AXP20X_WORKMODE_DCDC3_MASK BIT(1) -#define AXP22X_WORKMODE_DCDCX_MASK(x) BIT(x) - -#define AXP20X_FREQ_DCDC_MASK 0x0f +#define AXP22X_WORKMODE_DCDCX_MASK(x) BIT_MASK(x) #define AXP22X_MISC_N_VBUSEN_FUNC BIT(4) +#define AXP22X_DCDC1_V_OUT_MASK GENMASK(4, 0) +#define AXP22X_DCDC2_V_OUT_MASK GENMASK(5, 0) +#define AXP22X_DCDC3_V_OUT_MASK GENMASK(5, 0) +#define AXP22X_DCDC4_V_OUT_MASK GENMASK(5, 0) +#define AXP22X_DCDC5_V_OUT_MASK GENMASK(4, 0) +#define AXP22X_DC5LDO_V_OUT_MASK GENMASK(2, 0) +#define AXP22X_ALDO1_V_OUT_MASK GENMASK(4, 0) +#define AXP22X_ALDO2_V_OUT_MASK GENMASK(4, 0) +#define AXP22X_ALDO3_V_OUT_MASK GENMASK(4, 0) +#define AXP22X_DLDO1_V_OUT_MASK GENMASK(4, 0) +#define AXP22X_DLDO2_V_OUT_MASK GENMASK(4, 0) +#define AXP22X_DLDO3_V_OUT_MASK GENMASK(4, 0) +#define AXP22X_DLDO4_V_OUT_MASK GENMASK(4, 0) +#define AXP22X_ELDO1_V_OUT_MASK GENMASK(4, 0) +#define AXP22X_ELDO2_V_OUT_MASK GENMASK(4, 0) +#define AXP22X_ELDO3_V_OUT_MASK GENMASK(4, 0) +#define AXP22X_LDO_IO0_V_OUT_MASK GENMASK(4, 0) +#define AXP22X_LDO_IO1_V_OUT_MASK GENMASK(4, 0) + +#define AXP22X_PWR_OUT_DC5LDO_MASK BIT_MASK(0) +#define AXP22X_PWR_OUT_DCDC1_MASK BIT_MASK(1) +#define AXP22X_PWR_OUT_DCDC2_MASK BIT_MASK(2) +#define AXP22X_PWR_OUT_DCDC3_MASK BIT_MASK(3) +#define AXP22X_PWR_OUT_DCDC4_MASK BIT_MASK(4) +#define AXP22X_PWR_OUT_DCDC5_MASK BIT_MASK(5) +#define AXP22X_PWR_OUT_ALDO1_MASK BIT_MASK(6) +#define AXP22X_PWR_OUT_ALDO2_MASK BIT_MASK(7) + +#define AXP22X_PWR_OUT_SW_MASK BIT_MASK(6) +#define AXP22X_PWR_OUT_DC1SW_MASK BIT_MASK(7) + +#define AXP22X_PWR_OUT_ELDO1_MASK BIT_MASK(0) +#define AXP22X_PWR_OUT_ELDO2_MASK BIT_MASK(1) +#define AXP22X_PWR_OUT_ELDO3_MASK BIT_MASK(2) +#define AXP22X_PWR_OUT_DLDO1_MASK BIT_MASK(3) +#define AXP22X_PWR_OUT_DLDO2_MASK BIT_MASK(4) +#define AXP22X_PWR_OUT_DLDO3_MASK BIT_MASK(5) +#define AXP22X_PWR_OUT_DLDO4_MASK BIT_MASK(6) +#define AXP22X_PWR_OUT_ALDO3_MASK BIT_MASK(7) + +#define AXP803_PWR_OUT_DCDC1_MASK BIT_MASK(0) +#define AXP803_PWR_OUT_DCDC2_MASK BIT_MASK(1) +#define AXP803_PWR_OUT_DCDC3_MASK BIT_MASK(2) +#define AXP803_PWR_OUT_DCDC4_MASK BIT_MASK(3) +#define AXP803_PWR_OUT_DCDC5_MASK BIT_MASK(4) +#define AXP803_PWR_OUT_DCDC6_MASK BIT_MASK(5) + +#define AXP803_PWR_OUT_FLDO1_MASK BIT_MASK(2) +#define AXP803_PWR_OUT_FLDO2_MASK BIT_MASK(3) + +#define AXP803_DCDC1_V_OUT_MASK GENMASK(4, 0) +#define AXP803_DCDC2_V_OUT_MASK GENMASK(6, 0) +#define AXP803_DCDC3_V_OUT_MASK GENMASK(6, 0) +#define AXP803_DCDC4_V_OUT_MASK GENMASK(6, 0) +#define AXP803_DCDC5_V_OUT_MASK GENMASK(6, 0) +#define AXP803_DCDC6_V_OUT_MASK GENMASK(6, 0) + +#define AXP803_FLDO1_V_OUT_MASK GENMASK(3, 0) +#define AXP803_FLDO2_V_OUT_MASK GENMASK(3, 0) + +#define AXP803_DCDC23_POLYPHASE_DUAL BIT(6) +#define AXP803_DCDC56_POLYPHASE_DUAL BIT(5) + +#define AXP803_DCDC234_500mV_START 0x00 +#define AXP803_DCDC234_500mV_STEPS 70 +#define AXP803_DCDC234_500mV_END \ + (AXP803_DCDC234_500mV_START + AXP803_DCDC234_500mV_STEPS) +#define AXP803_DCDC234_1220mV_START 0x47 +#define AXP803_DCDC234_1220mV_STEPS 4 +#define AXP803_DCDC234_1220mV_END \ + (AXP803_DCDC234_1220mV_START + AXP803_DCDC234_1220mV_STEPS) +#define AXP803_DCDC234_NUM_VOLTAGES 76 + +#define AXP803_DCDC5_800mV_START 0x00 +#define AXP803_DCDC5_800mV_STEPS 32 +#define AXP803_DCDC5_800mV_END \ + (AXP803_DCDC5_800mV_START + AXP803_DCDC5_800mV_STEPS) +#define AXP803_DCDC5_1140mV_START 0x21 +#define AXP803_DCDC5_1140mV_STEPS 35 +#define AXP803_DCDC5_1140mV_END \ + (AXP803_DCDC5_1140mV_START + AXP803_DCDC5_1140mV_STEPS) +#define AXP803_DCDC5_NUM_VOLTAGES 68 + +#define AXP803_DCDC6_600mV_START 0x00 +#define AXP803_DCDC6_600mV_STEPS 50 +#define AXP803_DCDC6_600mV_END \ + (AXP803_DCDC6_600mV_START + AXP803_DCDC6_600mV_STEPS) +#define AXP803_DCDC6_1120mV_START 0x33 +#define AXP803_DCDC6_1120mV_STEPS 14 +#define AXP803_DCDC6_1120mV_END \ + (AXP803_DCDC6_1120mV_START + AXP803_DCDC6_1120mV_STEPS) +#define AXP803_DCDC6_NUM_VOLTAGES 72 + +#define AXP803_DLDO2_700mV_START 0x00 +#define AXP803_DLDO2_700mV_STEPS 26 +#define AXP803_DLDO2_700mV_END \ + (AXP803_DLDO2_700mV_START + AXP803_DLDO2_700mV_STEPS) +#define AXP803_DLDO2_3400mV_START 0x1b +#define AXP803_DLDO2_3400mV_STEPS 4 +#define AXP803_DLDO2_3400mV_END \ + (AXP803_DLDO2_3400mV_START + AXP803_DLDO2_3400mV_STEPS) +#define AXP803_DLDO2_NUM_VOLTAGES 32 + +#define AXP806_DCDCA_V_CTRL_MASK GENMASK(6, 0) +#define AXP806_DCDCB_V_CTRL_MASK GENMASK(4, 0) +#define AXP806_DCDCC_V_CTRL_MASK GENMASK(6, 0) +#define AXP806_DCDCD_V_CTRL_MASK GENMASK(5, 0) +#define AXP806_DCDCE_V_CTRL_MASK GENMASK(4, 0) +#define AXP806_ALDO1_V_CTRL_MASK GENMASK(4, 0) +#define AXP806_ALDO2_V_CTRL_MASK GENMASK(4, 0) +#define AXP806_ALDO3_V_CTRL_MASK GENMASK(4, 0) +#define AXP806_BLDO1_V_CTRL_MASK GENMASK(3, 0) +#define AXP806_BLDO2_V_CTRL_MASK GENMASK(3, 0) +#define AXP806_BLDO3_V_CTRL_MASK GENMASK(3, 0) +#define AXP806_BLDO4_V_CTRL_MASK GENMASK(3, 0) +#define AXP806_CLDO1_V_CTRL_MASK GENMASK(4, 0) +#define AXP806_CLDO2_V_CTRL_MASK GENMASK(4, 0) +#define AXP806_CLDO3_V_CTRL_MASK GENMASK(4, 0) + +#define AXP806_PWR_OUT_DCDCA_MASK BIT_MASK(0) +#define AXP806_PWR_OUT_DCDCB_MASK BIT_MASK(1) +#define AXP806_PWR_OUT_DCDCC_MASK BIT_MASK(2) +#define AXP806_PWR_OUT_DCDCD_MASK BIT_MASK(3) +#define AXP806_PWR_OUT_DCDCE_MASK BIT_MASK(4) +#define AXP806_PWR_OUT_ALDO1_MASK BIT_MASK(5) +#define AXP806_PWR_OUT_ALDO2_MASK BIT_MASK(6) +#define AXP806_PWR_OUT_ALDO3_MASK BIT_MASK(7) +#define AXP806_PWR_OUT_BLDO1_MASK BIT_MASK(0) +#define AXP806_PWR_OUT_BLDO2_MASK BIT_MASK(1) +#define AXP806_PWR_OUT_BLDO3_MASK BIT_MASK(2) +#define AXP806_PWR_OUT_BLDO4_MASK BIT_MASK(3) +#define AXP806_PWR_OUT_CLDO1_MASK BIT_MASK(4) +#define AXP806_PWR_OUT_CLDO2_MASK BIT_MASK(5) +#define AXP806_PWR_OUT_CLDO3_MASK BIT_MASK(6) +#define AXP806_PWR_OUT_SW_MASK BIT_MASK(7) + +#define AXP806_DCDCAB_POLYPHASE_DUAL 0x40 +#define AXP806_DCDCABC_POLYPHASE_TRI 0x80 +#define AXP806_DCDCABC_POLYPHASE_MASK GENMASK(7, 6) + +#define AXP806_DCDCDE_POLYPHASE_DUAL BIT(5) + +#define AXP806_DCDCA_600mV_START 0x00 +#define AXP806_DCDCA_600mV_STEPS 50 +#define AXP806_DCDCA_600mV_END \ + (AXP806_DCDCA_600mV_START + AXP806_DCDCA_600mV_STEPS) +#define AXP806_DCDCA_1120mV_START 0x33 +#define AXP806_DCDCA_1120mV_STEPS 14 +#define AXP806_DCDCA_1120mV_END \ + (AXP806_DCDCA_1120mV_START + AXP806_DCDCA_1120mV_STEPS) +#define AXP806_DCDCA_NUM_VOLTAGES 72 + +#define AXP806_DCDCD_600mV_START 0x00 +#define AXP806_DCDCD_600mV_STEPS 45 +#define AXP806_DCDCD_600mV_END \ + (AXP806_DCDCD_600mV_START + AXP806_DCDCD_600mV_STEPS) +#define AXP806_DCDCD_1600mV_START 0x2e +#define AXP806_DCDCD_1600mV_STEPS 17 +#define AXP806_DCDCD_1600mV_END \ + (AXP806_DCDCD_1600mV_START + AXP806_DCDCD_1600mV_STEPS) +#define AXP806_DCDCD_NUM_VOLTAGES 64 + +#define AXP809_DCDC4_600mV_START 0x00 +#define AXP809_DCDC4_600mV_STEPS 47 +#define AXP809_DCDC4_600mV_END \ + (AXP809_DCDC4_600mV_START + AXP809_DCDC4_600mV_STEPS) +#define AXP809_DCDC4_1800mV_START 0x30 +#define AXP809_DCDC4_1800mV_STEPS 8 +#define AXP809_DCDC4_1800mV_END \ + (AXP809_DCDC4_1800mV_START + AXP809_DCDC4_1800mV_STEPS) +#define AXP809_DCDC4_NUM_VOLTAGES 57 + +#define AXP813_DCDC7_V_OUT_MASK GENMASK(6, 0) + +#define AXP813_PWR_OUT_DCDC7_MASK BIT_MASK(6) + #define AXP_DESC_IO(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ _vmask, _ereg, _emask, _enable_val, _disable_val) \ [_family##_##_id] = { \ @@ -128,6 +359,134 @@ .ops = &axp20x_ops_range, \ } +static const int axp209_dcdc2_ldo3_slew_rates[] = { + 1600, + 800, +}; + +static int axp20x_set_ramp_delay(struct regulator_dev *rdev, int ramp) +{ + struct axp20x_dev *axp20x = rdev_get_drvdata(rdev); + const struct regulator_desc *desc; + u8 reg, mask, enable, cfg = 0xff; + const int *slew_rates; + int rate_count = 0; + + desc = rdev->desc; + + switch (axp20x->variant) { + case AXP209_ID: + if (desc->id == AXP20X_DCDC2) { + slew_rates = axp209_dcdc2_ldo3_slew_rates; + rate_count = ARRAY_SIZE(axp209_dcdc2_ldo3_slew_rates); + reg = AXP20X_DCDC2_LDO3_V_RAMP; + mask = AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_RATE_MASK | + AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN_MASK; + enable = (ramp > 0) ? + AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN : + !AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN; + break; + } + + if (desc->id == AXP20X_LDO3) { + slew_rates = axp209_dcdc2_ldo3_slew_rates; + rate_count = ARRAY_SIZE(axp209_dcdc2_ldo3_slew_rates); + reg = AXP20X_DCDC2_LDO3_V_RAMP; + mask = AXP20X_DCDC2_LDO3_V_RAMP_LDO3_RATE_MASK | + AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN_MASK; + enable = (ramp > 0) ? + AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN : + !AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN; + break; + } + + if (rate_count > 0) + break; + + /* fall through */ + default: + /* Not supported for this regulator */ + return -ENOTSUPP; + } + + if (ramp == 0) { + cfg = enable; + } else { + int i; + + for (i = 0; i < rate_count; i++) { + if (ramp <= slew_rates[i]) + cfg = AXP20X_DCDC2_LDO3_V_RAMP_LDO3_RATE(i); + else + break; + } + + if (cfg == 0xff) { + dev_err(axp20x->dev, "unsupported ramp value %d", ramp); + return -EINVAL; + } + + cfg |= enable; + } + + return regmap_update_bits(axp20x->regmap, reg, mask, cfg); +} + +static int axp20x_regulator_enable_regmap(struct regulator_dev *rdev) +{ + struct axp20x_dev *axp20x = rdev_get_drvdata(rdev); + const struct regulator_desc *desc; + + if (!rdev) + return -EINVAL; + + desc = rdev->desc; + + switch (axp20x->variant) { + case AXP209_ID: + if ((desc->id == AXP20X_LDO3) && + rdev->constraints && rdev->constraints->soft_start) { + int v_out; + int ret; + + /* + * On some boards, the LDO3 can be overloaded when + * turning on, causing the entire PMIC to shutdown + * without warning. Turning it on at the minimal voltage + * and then setting the voltage to the requested value + * works reliably. + */ + if (regulator_is_enabled_regmap(rdev)) + break; + + v_out = regulator_get_voltage_sel_regmap(rdev); + if (v_out < 0) + return v_out; + + if (v_out == 0) + break; + + ret = regulator_set_voltage_sel_regmap(rdev, 0x00); + /* + * A small pause is needed between + * setting the voltage and enabling the LDO to give the + * internal state machine time to process the request. + */ + usleep_range(1000, 5000); + ret |= regulator_enable_regmap(rdev); + ret |= regulator_set_voltage_sel_regmap(rdev, v_out); + + return ret; + } + break; + default: + /* No quirks */ + break; + } + + return regulator_enable_regmap(rdev); +}; + static const struct regulator_ops axp20x_ops_fixed = { .list_voltage = regulator_list_voltage_linear, }; @@ -145,9 +504,10 @@ static const struct regulator_ops axp20x_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, - .enable = regulator_enable_regmap, + .enable = axp20x_regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, + .set_ramp_delay = axp20x_set_ramp_delay, }; static const struct regulator_ops axp20x_ops_sw = { @@ -157,77 +517,116 @@ static const struct regulator_ops axp20x_ops_sw = { }; static const struct regulator_linear_range axp20x_ldo4_ranges[] = { - REGULATOR_LINEAR_RANGE(1250000, 0x0, 0x0, 0), - REGULATOR_LINEAR_RANGE(1300000, 0x1, 0x8, 100000), - REGULATOR_LINEAR_RANGE(2500000, 0x9, 0x9, 0), - REGULATOR_LINEAR_RANGE(2700000, 0xa, 0xb, 100000), - REGULATOR_LINEAR_RANGE(3000000, 0xc, 0xf, 100000), + REGULATOR_LINEAR_RANGE(1250000, + AXP20X_LDO4_V_OUT_1250mV_START, + AXP20X_LDO4_V_OUT_1250mV_END, + 0), + REGULATOR_LINEAR_RANGE(1300000, + AXP20X_LDO4_V_OUT_1300mV_START, + AXP20X_LDO4_V_OUT_1300mV_END, + 100000), + REGULATOR_LINEAR_RANGE(2500000, + AXP20X_LDO4_V_OUT_2500mV_START, + AXP20X_LDO4_V_OUT_2500mV_END, + 0), + REGULATOR_LINEAR_RANGE(2700000, + AXP20X_LDO4_V_OUT_2700mV_START, + AXP20X_LDO4_V_OUT_2700mV_END, + 100000), + REGULATOR_LINEAR_RANGE(3000000, + AXP20X_LDO4_V_OUT_3000mV_START, + AXP20X_LDO4_V_OUT_3000mV_END, + 100000), }; static const struct regulator_desc axp20x_regulators[] = { AXP_DESC(AXP20X, DCDC2, "dcdc2", "vin2", 700, 2275, 25, - AXP20X_DCDC2_V_OUT, 0x3f, AXP20X_PWR_OUT_CTRL, 0x10), + AXP20X_DCDC2_V_OUT, AXP20X_DCDC2_V_OUT_MASK, + AXP20X_PWR_OUT_CTRL, AXP20X_PWR_OUT_DCDC2_MASK), AXP_DESC(AXP20X, DCDC3, "dcdc3", "vin3", 700, 3500, 25, - AXP20X_DCDC3_V_OUT, 0x7f, AXP20X_PWR_OUT_CTRL, 0x02), + AXP20X_DCDC3_V_OUT, AXP20X_DCDC3_V_OUT_MASK, + AXP20X_PWR_OUT_CTRL, AXP20X_PWR_OUT_DCDC3_MASK), AXP_DESC_FIXED(AXP20X, LDO1, "ldo1", "acin", 1300), AXP_DESC(AXP20X, LDO2, "ldo2", "ldo24in", 1800, 3300, 100, - AXP20X_LDO24_V_OUT, 0xf0, AXP20X_PWR_OUT_CTRL, 0x04), + AXP20X_LDO24_V_OUT, AXP20X_LDO24_V_OUT_MASK, + AXP20X_PWR_OUT_CTRL, AXP20X_PWR_OUT_LDO2_MASK), AXP_DESC(AXP20X, LDO3, "ldo3", "ldo3in", 700, 3500, 25, - AXP20X_LDO3_V_OUT, 0x7f, AXP20X_PWR_OUT_CTRL, 0x40), - AXP_DESC_RANGES(AXP20X, LDO4, "ldo4", "ldo24in", axp20x_ldo4_ranges, - 16, AXP20X_LDO24_V_OUT, 0x0f, AXP20X_PWR_OUT_CTRL, - 0x08), + AXP20X_LDO3_V_OUT, AXP20X_LDO3_V_OUT_MASK, + AXP20X_PWR_OUT_CTRL, AXP20X_PWR_OUT_LDO3_MASK), + AXP_DESC_RANGES(AXP20X, LDO4, "ldo4", "ldo24in", + axp20x_ldo4_ranges, AXP20X_LDO4_V_OUT_NUM_VOLTAGES, + AXP20X_LDO24_V_OUT, AXP20X_LDO24_V_OUT_MASK, + AXP20X_PWR_OUT_CTRL, AXP20X_PWR_OUT_LDO4_MASK), AXP_DESC_IO(AXP20X, LDO5, "ldo5", "ldo5in", 1800, 3300, 100, - AXP20X_LDO5_V_OUT, 0xf0, AXP20X_GPIO0_CTRL, 0x07, + AXP20X_LDO5_V_OUT, AXP20X_LDO5_V_OUT_MASK, + AXP20X_GPIO0_CTRL, AXP20X_GPIO0_FUNC_MASK, AXP20X_IO_ENABLED, AXP20X_IO_DISABLED), }; static const struct regulator_desc axp22x_regulators[] = { AXP_DESC(AXP22X, DCDC1, "dcdc1", "vin1", 1600, 3400, 100, - AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(1)), + AXP22X_DCDC1_V_OUT, AXP22X_DCDC1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC1_MASK), AXP_DESC(AXP22X, DCDC2, "dcdc2", "vin2", 600, 1540, 20, - AXP22X_DCDC2_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(2)), + AXP22X_DCDC2_V_OUT, AXP22X_DCDC2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC2_MASK), AXP_DESC(AXP22X, DCDC3, "dcdc3", "vin3", 600, 1860, 20, - AXP22X_DCDC3_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(3)), + AXP22X_DCDC3_V_OUT, AXP22X_DCDC3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC3_MASK), AXP_DESC(AXP22X, DCDC4, "dcdc4", "vin4", 600, 1540, 20, - AXP22X_DCDC4_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(4)), + AXP22X_DCDC4_V_OUT, AXP22X_DCDC4_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC4_MASK), AXP_DESC(AXP22X, DCDC5, "dcdc5", "vin5", 1000, 2550, 50, - AXP22X_DCDC5_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(5)), + AXP22X_DCDC5_V_OUT, AXP22X_DCDC5_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC5_MASK), /* secondary switchable output of DCDC1 */ - AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", NULL, AXP22X_PWR_OUT_CTRL2, - BIT(7)), + AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", NULL, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DC1SW_MASK), /* LDO regulator internally chained to DCDC5 */ AXP_DESC(AXP22X, DC5LDO, "dc5ldo", NULL, 700, 1400, 100, - AXP22X_DC5LDO_V_OUT, 0x7, AXP22X_PWR_OUT_CTRL1, BIT(0)), + AXP22X_DC5LDO_V_OUT, AXP22X_DC5LDO_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DC5LDO_MASK), AXP_DESC(AXP22X, ALDO1, "aldo1", "aldoin", 700, 3300, 100, - AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(6)), + AXP22X_ALDO1_V_OUT, AXP22X_ALDO1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_ALDO1_MASK), AXP_DESC(AXP22X, ALDO2, "aldo2", "aldoin", 700, 3300, 100, - AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)), + AXP22X_ALDO2_V_OUT, AXP22X_ALDO2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_ALDO2_MASK), AXP_DESC(AXP22X, ALDO3, "aldo3", "aldoin", 700, 3300, 100, - AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(7)), + AXP22X_ALDO3_V_OUT, AXP22X_ALDO3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL3, AXP22X_PWR_OUT_ALDO3_MASK), AXP_DESC(AXP22X, DLDO1, "dldo1", "dldoin", 700, 3300, 100, - AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(3)), + AXP22X_DLDO1_V_OUT, AXP22X_DLDO1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO1_MASK), AXP_DESC(AXP22X, DLDO2, "dldo2", "dldoin", 700, 3300, 100, - AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(4)), + AXP22X_DLDO2_V_OUT, AXP22X_PWR_OUT_DLDO2_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO2_MASK), AXP_DESC(AXP22X, DLDO3, "dldo3", "dldoin", 700, 3300, 100, - AXP22X_DLDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)), + AXP22X_DLDO3_V_OUT, AXP22X_DLDO3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO3_MASK), AXP_DESC(AXP22X, DLDO4, "dldo4", "dldoin", 700, 3300, 100, - AXP22X_DLDO4_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(6)), + AXP22X_DLDO4_V_OUT, AXP22X_DLDO4_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO4_MASK), AXP_DESC(AXP22X, ELDO1, "eldo1", "eldoin", 700, 3300, 100, - AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)), + AXP22X_ELDO1_V_OUT, AXP22X_ELDO1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO1_MASK), AXP_DESC(AXP22X, ELDO2, "eldo2", "eldoin", 700, 3300, 100, - AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)), + AXP22X_ELDO2_V_OUT, AXP22X_ELDO2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO1_MASK), AXP_DESC(AXP22X, ELDO3, "eldo3", "eldoin", 700, 3300, 100, - AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)), + AXP22X_ELDO3_V_OUT, AXP22X_ELDO3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO3_MASK), /* Note the datasheet only guarantees reliable operation up to * 3.3V, this needs to be enforced via dts provided constraints */ AXP_DESC_IO(AXP22X, LDO_IO0, "ldo_io0", "ips", 700, 3800, 100, - AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07, + AXP22X_LDO_IO0_V_OUT, AXP22X_LDO_IO0_V_OUT_MASK, + AXP20X_GPIO0_CTRL, AXP20X_GPIO0_FUNC_MASK, AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), /* Note the datasheet only guarantees reliable operation up to * 3.3V, this needs to be enforced via dts provided constraints */ AXP_DESC_IO(AXP22X, LDO_IO1, "ldo_io1", "ips", 700, 3800, 100, - AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07, + AXP22X_LDO_IO1_V_OUT, AXP22X_LDO_IO1_V_OUT_MASK, + AXP20X_GPIO1_CTRL, AXP20X_GPIO1_FUNC_MASK, AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), AXP_DESC_FIXED(AXP22X, RTC_LDO, "rtc_ldo", "ips", 3000), }; @@ -240,240 +639,354 @@ static const struct regulator_desc axp22x_drivevbus_regulator = { .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, .enable_reg = AXP20X_VBUS_IPSOUT_MGMT, - .enable_mask = BIT(2), + .enable_mask = AXP20X_VBUS_IPSOUT_MGMT_MASK, .ops = &axp20x_ops_sw, }; /* DCDC ranges shared with AXP813 */ static const struct regulator_linear_range axp803_dcdc234_ranges[] = { - REGULATOR_LINEAR_RANGE(500000, 0x0, 0x46, 10000), - REGULATOR_LINEAR_RANGE(1220000, 0x47, 0x4b, 20000), + REGULATOR_LINEAR_RANGE(500000, + AXP803_DCDC234_500mV_START, + AXP803_DCDC234_500mV_END, + 10000), + REGULATOR_LINEAR_RANGE(1220000, + AXP803_DCDC234_1220mV_START, + AXP803_DCDC234_1220mV_END, + 20000), }; static const struct regulator_linear_range axp803_dcdc5_ranges[] = { - REGULATOR_LINEAR_RANGE(800000, 0x0, 0x20, 10000), - REGULATOR_LINEAR_RANGE(1140000, 0x21, 0x44, 20000), + REGULATOR_LINEAR_RANGE(800000, + AXP803_DCDC5_800mV_START, + AXP803_DCDC5_800mV_END, + 10000), + REGULATOR_LINEAR_RANGE(1140000, + AXP803_DCDC5_1140mV_START, + AXP803_DCDC5_1140mV_END, + 20000), }; static const struct regulator_linear_range axp803_dcdc6_ranges[] = { - REGULATOR_LINEAR_RANGE(600000, 0x0, 0x32, 10000), - REGULATOR_LINEAR_RANGE(1120000, 0x33, 0x47, 20000), + REGULATOR_LINEAR_RANGE(600000, + AXP803_DCDC6_600mV_START, + AXP803_DCDC6_600mV_END, + 10000), + REGULATOR_LINEAR_RANGE(1120000, + AXP803_DCDC6_1120mV_START, + AXP803_DCDC6_1120mV_END, + 20000), }; -/* AXP806's CLDO2 and AXP809's DLDO1 shares the same range */ +/* AXP806's CLDO2 and AXP809's DLDO1 share the same range */ static const struct regulator_linear_range axp803_dldo2_ranges[] = { - REGULATOR_LINEAR_RANGE(700000, 0x0, 0x1a, 100000), - REGULATOR_LINEAR_RANGE(3400000, 0x1b, 0x1f, 200000), + REGULATOR_LINEAR_RANGE(700000, + AXP803_DLDO2_700mV_START, + AXP803_DLDO2_700mV_END, + 100000), + REGULATOR_LINEAR_RANGE(3400000, + AXP803_DLDO2_3400mV_START, + AXP803_DLDO2_3400mV_END, + 200000), }; static const struct regulator_desc axp803_regulators[] = { AXP_DESC(AXP803, DCDC1, "dcdc1", "vin1", 1600, 3400, 100, - AXP803_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(0)), - AXP_DESC_RANGES(AXP803, DCDC2, "dcdc2", "vin2", axp803_dcdc234_ranges, - 76, AXP803_DCDC2_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, - BIT(1)), - AXP_DESC_RANGES(AXP803, DCDC3, "dcdc3", "vin3", axp803_dcdc234_ranges, - 76, AXP803_DCDC3_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, - BIT(2)), - AXP_DESC_RANGES(AXP803, DCDC4, "dcdc4", "vin4", axp803_dcdc234_ranges, - 76, AXP803_DCDC4_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, - BIT(3)), - AXP_DESC_RANGES(AXP803, DCDC5, "dcdc5", "vin5", axp803_dcdc5_ranges, - 68, AXP803_DCDC5_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, - BIT(4)), - AXP_DESC_RANGES(AXP803, DCDC6, "dcdc6", "vin6", axp803_dcdc6_ranges, - 72, AXP803_DCDC6_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, - BIT(5)), + AXP803_DCDC1_V_OUT, AXP803_DCDC1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC1_MASK), + AXP_DESC_RANGES(AXP803, DCDC2, "dcdc2", "vin2", + axp803_dcdc234_ranges, AXP803_DCDC234_NUM_VOLTAGES, + AXP803_DCDC2_V_OUT, AXP803_DCDC2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC2_MASK), + AXP_DESC_RANGES(AXP803, DCDC3, "dcdc3", "vin3", + axp803_dcdc234_ranges, AXP803_DCDC234_NUM_VOLTAGES, + AXP803_DCDC3_V_OUT, AXP803_DCDC3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC3_MASK), + AXP_DESC_RANGES(AXP803, DCDC4, "dcdc4", "vin4", + axp803_dcdc234_ranges, AXP803_DCDC234_NUM_VOLTAGES, + AXP803_DCDC4_V_OUT, AXP803_DCDC4_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC4_MASK), + AXP_DESC_RANGES(AXP803, DCDC5, "dcdc5", "vin5", + axp803_dcdc5_ranges, AXP803_DCDC5_NUM_VOLTAGES, + AXP803_DCDC5_V_OUT, AXP803_DCDC5_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC5_MASK), + AXP_DESC_RANGES(AXP803, DCDC6, "dcdc6", "vin6", + axp803_dcdc6_ranges, AXP803_DCDC6_NUM_VOLTAGES, + AXP803_DCDC6_V_OUT, AXP803_DCDC6_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC6_MASK), /* secondary switchable output of DCDC1 */ - AXP_DESC_SW(AXP803, DC1SW, "dc1sw", NULL, AXP22X_PWR_OUT_CTRL2, - BIT(7)), + AXP_DESC_SW(AXP803, DC1SW, "dc1sw", NULL, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DC1SW_MASK), AXP_DESC(AXP803, ALDO1, "aldo1", "aldoin", 700, 3300, 100, - AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(5)), + AXP22X_ALDO1_V_OUT, AXP22X_ALDO1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL3, AXP806_PWR_OUT_ALDO1_MASK), AXP_DESC(AXP803, ALDO2, "aldo2", "aldoin", 700, 3300, 100, - AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(6)), + AXP22X_ALDO2_V_OUT, AXP22X_ALDO2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL3, AXP806_PWR_OUT_ALDO2_MASK), AXP_DESC(AXP803, ALDO3, "aldo3", "aldoin", 700, 3300, 100, - AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(7)), + AXP22X_ALDO3_V_OUT, AXP22X_ALDO3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL3, AXP806_PWR_OUT_ALDO3_MASK), AXP_DESC(AXP803, DLDO1, "dldo1", "dldoin", 700, 3300, 100, - AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(3)), - AXP_DESC_RANGES(AXP803, DLDO2, "dldo2", "dldoin", axp803_dldo2_ranges, - 32, AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, - BIT(4)), + AXP22X_DLDO1_V_OUT, AXP22X_DLDO1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO1_MASK), + AXP_DESC_RANGES(AXP803, DLDO2, "dldo2", "dldoin", + axp803_dldo2_ranges, AXP803_DLDO2_NUM_VOLTAGES, + AXP22X_DLDO2_V_OUT, AXP22X_DLDO2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO2_MASK), AXP_DESC(AXP803, DLDO3, "dldo3", "dldoin", 700, 3300, 100, - AXP22X_DLDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)), + AXP22X_DLDO3_V_OUT, AXP22X_DLDO3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO3_MASK), AXP_DESC(AXP803, DLDO4, "dldo4", "dldoin", 700, 3300, 100, - AXP22X_DLDO4_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(6)), + AXP22X_DLDO4_V_OUT, AXP22X_DLDO4_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO4_MASK), AXP_DESC(AXP803, ELDO1, "eldo1", "eldoin", 700, 1900, 50, - AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)), + AXP22X_ELDO1_V_OUT, AXP22X_ELDO1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO1_MASK), AXP_DESC(AXP803, ELDO2, "eldo2", "eldoin", 700, 1900, 50, - AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)), + AXP22X_ELDO2_V_OUT, AXP22X_ELDO2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO2_MASK), AXP_DESC(AXP803, ELDO3, "eldo3", "eldoin", 700, 1900, 50, - AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)), + AXP22X_ELDO3_V_OUT, AXP22X_ELDO3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO3_MASK), AXP_DESC(AXP803, FLDO1, "fldo1", "fldoin", 700, 1450, 50, - AXP803_FLDO1_V_OUT, 0x0f, AXP22X_PWR_OUT_CTRL3, BIT(2)), + AXP803_FLDO1_V_OUT, AXP803_FLDO1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL3, AXP803_PWR_OUT_FLDO1_MASK), AXP_DESC(AXP803, FLDO2, "fldo2", "fldoin", 700, 1450, 50, - AXP803_FLDO2_V_OUT, 0x0f, AXP22X_PWR_OUT_CTRL3, BIT(3)), + AXP803_FLDO2_V_OUT, AXP803_FLDO2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL3, AXP803_PWR_OUT_FLDO2_MASK), AXP_DESC_IO(AXP803, LDO_IO0, "ldo-io0", "ips", 700, 3300, 100, - AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07, + AXP22X_LDO_IO0_V_OUT, AXP22X_LDO_IO0_V_OUT_MASK, + AXP20X_GPIO0_CTRL, AXP20X_GPIO0_FUNC_MASK, AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), AXP_DESC_IO(AXP803, LDO_IO1, "ldo-io1", "ips", 700, 3300, 100, - AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07, + AXP22X_LDO_IO1_V_OUT, AXP22X_LDO_IO1_V_OUT_MASK, + AXP20X_GPIO1_CTRL, AXP20X_GPIO1_FUNC_MASK, AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), AXP_DESC_FIXED(AXP803, RTC_LDO, "rtc-ldo", "ips", 3000), }; static const struct regulator_linear_range axp806_dcdca_ranges[] = { - REGULATOR_LINEAR_RANGE(600000, 0x0, 0x32, 10000), - REGULATOR_LINEAR_RANGE(1120000, 0x33, 0x47, 20000), + REGULATOR_LINEAR_RANGE(600000, + AXP806_DCDCA_600mV_START, + AXP806_DCDCA_600mV_END, + 10000), + REGULATOR_LINEAR_RANGE(1120000, + AXP806_DCDCA_1120mV_START, + AXP806_DCDCA_1120mV_END, + 20000), }; static const struct regulator_linear_range axp806_dcdcd_ranges[] = { - REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2d, 20000), - REGULATOR_LINEAR_RANGE(1600000, 0x2e, 0x3f, 100000), + REGULATOR_LINEAR_RANGE(600000, + AXP806_DCDCD_600mV_START, + AXP806_DCDCD_600mV_END, + 20000), + REGULATOR_LINEAR_RANGE(1600000, + AXP806_DCDCD_600mV_START, + AXP806_DCDCD_600mV_END, + 100000), }; static const struct regulator_desc axp806_regulators[] = { - AXP_DESC_RANGES(AXP806, DCDCA, "dcdca", "vina", axp806_dcdca_ranges, - 72, AXP806_DCDCA_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1, - BIT(0)), + AXP_DESC_RANGES(AXP806, DCDCA, "dcdca", "vina", + axp806_dcdca_ranges, AXP806_DCDCA_NUM_VOLTAGES, + AXP806_DCDCA_V_CTRL, AXP806_DCDCA_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_DCDCA_MASK), AXP_DESC(AXP806, DCDCB, "dcdcb", "vinb", 1000, 2550, 50, - AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(1)), - AXP_DESC_RANGES(AXP806, DCDCC, "dcdcc", "vinc", axp806_dcdca_ranges, - 72, AXP806_DCDCC_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1, - BIT(2)), - AXP_DESC_RANGES(AXP806, DCDCD, "dcdcd", "vind", axp806_dcdcd_ranges, - 64, AXP806_DCDCD_V_CTRL, 0x3f, AXP806_PWR_OUT_CTRL1, - BIT(3)), + AXP806_DCDCB_V_CTRL, AXP806_DCDCB_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_DCDCB_MASK), + AXP_DESC_RANGES(AXP806, DCDCC, "dcdcc", "vinc", + axp806_dcdca_ranges, AXP806_DCDCA_NUM_VOLTAGES, + AXP806_DCDCC_V_CTRL, AXP806_DCDCC_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_DCDCC_MASK), + AXP_DESC_RANGES(AXP806, DCDCD, "dcdcd", "vind", + axp806_dcdcd_ranges, AXP806_DCDCD_NUM_VOLTAGES, + AXP806_DCDCD_V_CTRL, AXP806_DCDCD_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_DCDCD_MASK), AXP_DESC(AXP806, DCDCE, "dcdce", "vine", 1100, 3400, 100, - AXP806_DCDCE_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(4)), + AXP806_DCDCE_V_CTRL, AXP806_DCDCE_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_DCDCE_MASK), AXP_DESC(AXP806, ALDO1, "aldo1", "aldoin", 700, 3300, 100, - AXP806_ALDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(5)), + AXP806_ALDO1_V_CTRL, AXP806_ALDO1_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_ALDO1_MASK), AXP_DESC(AXP806, ALDO2, "aldo2", "aldoin", 700, 3400, 100, - AXP806_ALDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(6)), + AXP806_ALDO2_V_CTRL, AXP806_ALDO2_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_ALDO2_MASK), AXP_DESC(AXP806, ALDO3, "aldo3", "aldoin", 700, 3300, 100, - AXP806_ALDO3_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(7)), + AXP806_ALDO3_V_CTRL, AXP806_ALDO3_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL1, AXP806_PWR_OUT_ALDO3_MASK), AXP_DESC(AXP806, BLDO1, "bldo1", "bldoin", 700, 1900, 100, - AXP806_BLDO1_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(0)), + AXP806_BLDO1_V_CTRL, AXP806_BLDO1_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_BLDO1_MASK), AXP_DESC(AXP806, BLDO2, "bldo2", "bldoin", 700, 1900, 100, - AXP806_BLDO2_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(1)), + AXP806_BLDO2_V_CTRL, AXP806_BLDO2_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_BLDO2_MASK), AXP_DESC(AXP806, BLDO3, "bldo3", "bldoin", 700, 1900, 100, - AXP806_BLDO3_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(2)), + AXP806_BLDO3_V_CTRL, AXP806_BLDO3_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_BLDO3_MASK), AXP_DESC(AXP806, BLDO4, "bldo4", "bldoin", 700, 1900, 100, - AXP806_BLDO4_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(3)), + AXP806_BLDO4_V_CTRL, AXP806_BLDO4_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_BLDO4_MASK), AXP_DESC(AXP806, CLDO1, "cldo1", "cldoin", 700, 3300, 100, - AXP806_CLDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(4)), - AXP_DESC_RANGES(AXP806, CLDO2, "cldo2", "cldoin", axp803_dldo2_ranges, - 32, AXP806_CLDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, - BIT(5)), + AXP806_CLDO1_V_CTRL, AXP806_CLDO1_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_CLDO1_MASK), + AXP_DESC_RANGES(AXP806, CLDO2, "cldo2", "cldoin", + axp803_dldo2_ranges, AXP803_DLDO2_NUM_VOLTAGES, + AXP806_CLDO2_V_CTRL, AXP806_CLDO2_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_CLDO2_MASK), AXP_DESC(AXP806, CLDO3, "cldo3", "cldoin", 700, 3300, 100, - AXP806_CLDO3_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(6)), - AXP_DESC_SW(AXP806, SW, "sw", "swin", AXP806_PWR_OUT_CTRL2, BIT(7)), + AXP806_CLDO3_V_CTRL, AXP806_CLDO3_V_CTRL_MASK, + AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_CLDO3_MASK), + AXP_DESC_SW(AXP806, SW, "sw", "swin", + AXP806_PWR_OUT_CTRL2, AXP806_PWR_OUT_SW_MASK), }; static const struct regulator_linear_range axp809_dcdc4_ranges[] = { - REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2f, 20000), - REGULATOR_LINEAR_RANGE(1800000, 0x30, 0x38, 100000), + REGULATOR_LINEAR_RANGE(600000, + AXP809_DCDC4_600mV_START, + AXP809_DCDC4_600mV_END, + 20000), + REGULATOR_LINEAR_RANGE(1800000, + AXP809_DCDC4_1800mV_START, + AXP809_DCDC4_1800mV_END, + 100000), }; static const struct regulator_desc axp809_regulators[] = { AXP_DESC(AXP809, DCDC1, "dcdc1", "vin1", 1600, 3400, 100, - AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(1)), + AXP22X_DCDC1_V_OUT, AXP22X_DCDC1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC1_MASK), AXP_DESC(AXP809, DCDC2, "dcdc2", "vin2", 600, 1540, 20, - AXP22X_DCDC2_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(2)), + AXP22X_DCDC2_V_OUT, AXP22X_DCDC2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC2_MASK), AXP_DESC(AXP809, DCDC3, "dcdc3", "vin3", 600, 1860, 20, - AXP22X_DCDC3_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(3)), - AXP_DESC_RANGES(AXP809, DCDC4, "dcdc4", "vin4", axp809_dcdc4_ranges, - 57, AXP22X_DCDC4_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, - BIT(4)), + AXP22X_DCDC3_V_OUT, AXP22X_DCDC3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC3_MASK), + AXP_DESC_RANGES(AXP809, DCDC4, "dcdc4", "vin4", + axp809_dcdc4_ranges, AXP809_DCDC4_NUM_VOLTAGES, + AXP22X_DCDC4_V_OUT, AXP22X_DCDC4_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC4_MASK), AXP_DESC(AXP809, DCDC5, "dcdc5", "vin5", 1000, 2550, 50, - AXP22X_DCDC5_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(5)), + AXP22X_DCDC5_V_OUT, AXP22X_DCDC5_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DCDC5_MASK), /* secondary switchable output of DCDC1 */ - AXP_DESC_SW(AXP809, DC1SW, "dc1sw", NULL, AXP22X_PWR_OUT_CTRL2, - BIT(7)), + AXP_DESC_SW(AXP809, DC1SW, "dc1sw", NULL, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DC1SW_MASK), /* LDO regulator internally chained to DCDC5 */ AXP_DESC(AXP809, DC5LDO, "dc5ldo", NULL, 700, 1400, 100, - AXP22X_DC5LDO_V_OUT, 0x7, AXP22X_PWR_OUT_CTRL1, BIT(0)), + AXP22X_DC5LDO_V_OUT, AXP22X_DC5LDO_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_DC5LDO_MASK), AXP_DESC(AXP809, ALDO1, "aldo1", "aldoin", 700, 3300, 100, - AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(6)), + AXP22X_ALDO1_V_OUT, AXP22X_ALDO1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_ALDO1_MASK), AXP_DESC(AXP809, ALDO2, "aldo2", "aldoin", 700, 3300, 100, - AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)), + AXP22X_ALDO2_V_OUT, AXP22X_ALDO2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP22X_PWR_OUT_ALDO2_MASK), AXP_DESC(AXP809, ALDO3, "aldo3", "aldoin", 700, 3300, 100, - AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)), - AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp803_dldo2_ranges, - 32, AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, - BIT(3)), + AXP22X_ALDO3_V_OUT, AXP22X_ALDO3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ALDO3_MASK), + AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", + axp803_dldo2_ranges, AXP803_DLDO2_NUM_VOLTAGES, + AXP22X_DLDO1_V_OUT, AXP22X_DLDO1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO1_MASK), AXP_DESC(AXP809, DLDO2, "dldo2", "dldoin", 700, 3300, 100, - AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(4)), + AXP22X_DLDO2_V_OUT, AXP22X_DLDO2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO2_MASK), AXP_DESC(AXP809, ELDO1, "eldo1", "eldoin", 700, 3300, 100, - AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)), + AXP22X_ELDO1_V_OUT, AXP22X_ELDO1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO1_MASK), AXP_DESC(AXP809, ELDO2, "eldo2", "eldoin", 700, 3300, 100, - AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)), + AXP22X_ELDO2_V_OUT, AXP22X_ELDO2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO2_MASK), AXP_DESC(AXP809, ELDO3, "eldo3", "eldoin", 700, 3300, 100, - AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)), + AXP22X_ELDO3_V_OUT, AXP22X_ELDO3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO3_MASK), /* * Note the datasheet only guarantees reliable operation up to * 3.3V, this needs to be enforced via dts provided constraints */ AXP_DESC_IO(AXP809, LDO_IO0, "ldo_io0", "ips", 700, 3800, 100, - AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07, + AXP22X_LDO_IO0_V_OUT, AXP22X_LDO_IO0_V_OUT_MASK, + AXP20X_GPIO0_CTRL, AXP20X_GPIO0_FUNC_MASK, AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), /* * Note the datasheet only guarantees reliable operation up to * 3.3V, this needs to be enforced via dts provided constraints */ AXP_DESC_IO(AXP809, LDO_IO1, "ldo_io1", "ips", 700, 3800, 100, - AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07, + AXP22X_LDO_IO1_V_OUT, AXP22X_LDO_IO1_V_OUT_MASK, + AXP20X_GPIO1_CTRL, AXP20X_GPIO1_FUNC_MASK, AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), AXP_DESC_FIXED(AXP809, RTC_LDO, "rtc_ldo", "ips", 1800), - AXP_DESC_SW(AXP809, SW, "sw", "swin", AXP22X_PWR_OUT_CTRL2, BIT(6)), + AXP_DESC_SW(AXP809, SW, "sw", "swin", + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_SW_MASK), }; static const struct regulator_desc axp813_regulators[] = { AXP_DESC(AXP813, DCDC1, "dcdc1", "vin1", 1600, 3400, 100, - AXP803_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(0)), - AXP_DESC_RANGES(AXP813, DCDC2, "dcdc2", "vin2", axp803_dcdc234_ranges, - 76, AXP803_DCDC2_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, - BIT(1)), - AXP_DESC_RANGES(AXP813, DCDC3, "dcdc3", "vin3", axp803_dcdc234_ranges, - 76, AXP803_DCDC3_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, - BIT(2)), - AXP_DESC_RANGES(AXP813, DCDC4, "dcdc4", "vin4", axp803_dcdc234_ranges, - 76, AXP803_DCDC4_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, - BIT(3)), - AXP_DESC_RANGES(AXP813, DCDC5, "dcdc5", "vin5", axp803_dcdc5_ranges, - 68, AXP803_DCDC5_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, - BIT(4)), - AXP_DESC_RANGES(AXP813, DCDC6, "dcdc6", "vin6", axp803_dcdc6_ranges, - 72, AXP803_DCDC6_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, - BIT(5)), - AXP_DESC_RANGES(AXP813, DCDC7, "dcdc7", "vin7", axp803_dcdc6_ranges, - 72, AXP813_DCDC7_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, - BIT(6)), + AXP803_DCDC1_V_OUT, AXP803_DCDC1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC1_MASK), + AXP_DESC_RANGES(AXP813, DCDC2, "dcdc2", "vin2", + axp803_dcdc234_ranges, AXP803_DCDC234_NUM_VOLTAGES, + AXP803_DCDC2_V_OUT, AXP803_DCDC2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC2_MASK), + AXP_DESC_RANGES(AXP813, DCDC3, "dcdc3", "vin3", + axp803_dcdc234_ranges, AXP803_DCDC234_NUM_VOLTAGES, + AXP803_DCDC3_V_OUT, AXP803_DCDC3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC3_MASK), + AXP_DESC_RANGES(AXP813, DCDC4, "dcdc4", "vin4", + axp803_dcdc234_ranges, AXP803_DCDC234_NUM_VOLTAGES, + AXP803_DCDC4_V_OUT, AXP803_DCDC4_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC4_MASK), + AXP_DESC_RANGES(AXP813, DCDC5, "dcdc5", "vin5", + axp803_dcdc5_ranges, AXP803_DCDC5_NUM_VOLTAGES, + AXP803_DCDC5_V_OUT, AXP803_DCDC5_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC5_MASK), + AXP_DESC_RANGES(AXP813, DCDC6, "dcdc6", "vin6", + axp803_dcdc6_ranges, AXP803_DCDC6_NUM_VOLTAGES, + AXP803_DCDC6_V_OUT, AXP803_DCDC6_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP803_PWR_OUT_DCDC6_MASK), + AXP_DESC_RANGES(AXP813, DCDC7, "dcdc7", "vin7", + axp803_dcdc6_ranges, AXP803_DCDC6_NUM_VOLTAGES, + AXP813_DCDC7_V_OUT, AXP813_DCDC7_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL1, AXP813_PWR_OUT_DCDC7_MASK), AXP_DESC(AXP813, ALDO1, "aldo1", "aldoin", 700, 3300, 100, - AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(5)), + AXP22X_ALDO1_V_OUT, AXP22X_ALDO1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL3, AXP806_PWR_OUT_ALDO1_MASK), AXP_DESC(AXP813, ALDO2, "aldo2", "aldoin", 700, 3300, 100, - AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(6)), + AXP22X_ALDO2_V_OUT, AXP22X_ALDO2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL3, AXP806_PWR_OUT_ALDO2_MASK), AXP_DESC(AXP813, ALDO3, "aldo3", "aldoin", 700, 3300, 100, - AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(7)), + AXP22X_ALDO3_V_OUT, AXP22X_ALDO3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL3, AXP806_PWR_OUT_ALDO3_MASK), AXP_DESC(AXP813, DLDO1, "dldo1", "dldoin", 700, 3300, 100, - AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(3)), - AXP_DESC_RANGES(AXP813, DLDO2, "dldo2", "dldoin", axp803_dldo2_ranges, - 32, AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, - BIT(4)), + AXP22X_DLDO1_V_OUT, AXP22X_DLDO1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO1_MASK), + AXP_DESC_RANGES(AXP813, DLDO2, "dldo2", "dldoin", + axp803_dldo2_ranges, AXP803_DLDO2_NUM_VOLTAGES, + AXP22X_DLDO2_V_OUT, AXP22X_DLDO2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO2_MASK), AXP_DESC(AXP813, DLDO3, "dldo3", "dldoin", 700, 3300, 100, - AXP22X_DLDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)), + AXP22X_DLDO3_V_OUT, AXP22X_DLDO3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO3_MASK), AXP_DESC(AXP813, DLDO4, "dldo4", "dldoin", 700, 3300, 100, - AXP22X_DLDO4_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(6)), + AXP22X_DLDO4_V_OUT, AXP22X_DLDO4_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DLDO4_MASK), AXP_DESC(AXP813, ELDO1, "eldo1", "eldoin", 700, 1900, 50, - AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)), + AXP22X_ELDO1_V_OUT, AXP22X_ELDO1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO1_MASK), AXP_DESC(AXP813, ELDO2, "eldo2", "eldoin", 700, 1900, 50, - AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)), + AXP22X_ELDO2_V_OUT, AXP22X_ELDO2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO2_MASK), AXP_DESC(AXP813, ELDO3, "eldo3", "eldoin", 700, 1900, 50, - AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)), + AXP22X_ELDO3_V_OUT, AXP22X_ELDO3_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_ELDO3_MASK), /* to do / check ... */ AXP_DESC(AXP813, FLDO1, "fldo1", "fldoin", 700, 1450, 50, - AXP803_FLDO1_V_OUT, 0x0f, AXP22X_PWR_OUT_CTRL3, BIT(2)), + AXP803_FLDO1_V_OUT, AXP803_FLDO1_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL3, AXP803_PWR_OUT_FLDO1_MASK), AXP_DESC(AXP813, FLDO2, "fldo2", "fldoin", 700, 1450, 50, - AXP803_FLDO2_V_OUT, 0x0f, AXP22X_PWR_OUT_CTRL3, BIT(3)), + AXP803_FLDO2_V_OUT, AXP803_FLDO2_V_OUT_MASK, + AXP22X_PWR_OUT_CTRL3, AXP803_PWR_OUT_FLDO2_MASK), /* * TODO: FLDO3 = {DCDC5, FLDOIN} / 2 * @@ -482,12 +995,15 @@ static const struct regulator_desc axp813_regulators[] = { */ AXP_DESC_FIXED(AXP813, RTC_LDO, "rtc-ldo", "ips", 1800), AXP_DESC_IO(AXP813, LDO_IO0, "ldo-io0", "ips", 700, 3300, 100, - AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07, + AXP22X_LDO_IO0_V_OUT, AXP22X_LDO_IO0_V_OUT_MASK, + AXP20X_GPIO0_CTRL, AXP20X_GPIO0_FUNC_MASK, AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), AXP_DESC_IO(AXP813, LDO_IO1, "ldo-io1", "ips", 700, 3300, 100, - AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07, + AXP22X_LDO_IO1_V_OUT, AXP22X_LDO_IO1_V_OUT_MASK, + AXP20X_GPIO1_CTRL, AXP20X_GPIO1_FUNC_MASK, AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), - AXP_DESC_SW(AXP813, SW, "sw", "swin", AXP22X_PWR_OUT_CTRL2, BIT(7)), + AXP_DESC_SW(AXP813, SW, "sw", "swin", + AXP22X_PWR_OUT_CTRL2, AXP22X_PWR_OUT_DC1SW_MASK), }; static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) @@ -663,9 +1179,9 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id) switch (id) { case AXP803_DCDC3: - return !!(reg & BIT(6)); + return !!(reg & AXP803_DCDC23_POLYPHASE_DUAL); case AXP803_DCDC6: - return !!(reg & BIT(5)); + return !!(reg & AXP803_DCDC56_POLYPHASE_DUAL); } break; @@ -674,12 +1190,15 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id) switch (id) { case AXP806_DCDCB: - return (((reg & GENMASK(7, 6)) == BIT(6)) || - ((reg & GENMASK(7, 6)) == BIT(7))); + return (((reg & AXP806_DCDCABC_POLYPHASE_MASK) == + AXP806_DCDCAB_POLYPHASE_DUAL) || + ((reg & AXP806_DCDCABC_POLYPHASE_MASK) == + AXP806_DCDCABC_POLYPHASE_TRI)); case AXP806_DCDCC: - return ((reg & GENMASK(7, 6)) == BIT(7)); + return ((reg & AXP806_DCDCABC_POLYPHASE_MASK) == + AXP806_DCDCABC_POLYPHASE_TRI); case AXP806_DCDCE: - return !!(reg & BIT(5)); + return !!(reg & AXP806_DCDCDE_POLYPHASE_DUAL); } break; diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c index 92d6d7b10cf7..e49c0a7d5dd5 100644 --- a/drivers/regulator/bcm590xx-regulator.c +++ b/drivers/regulator/bcm590xx-regulator.c @@ -242,8 +242,12 @@ static int bcm590xx_get_enable_register(int id) case BCM590XX_REG_SDSR2: reg = BCM590XX_SDSR2PMCTRL1; break; + case BCM590XX_REG_VSR: + reg = BCM590XX_VSRPMCTRL1; + break; case BCM590XX_REG_VBUS: reg = BCM590XX_OTG_CTRL; + break; } diff --git a/drivers/regulator/bd70528-regulator.c b/drivers/regulator/bd70528-regulator.c new file mode 100644 index 000000000000..30e3ed430a8a --- /dev/null +++ b/drivers/regulator/bd70528-regulator.c @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 ROHM Semiconductors +// bd70528-regulator.c ROHM BD70528MWV regulator driver + +#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> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/slab.h> + +#define BUCK_RAMPRATE_250MV 0 +#define BUCK_RAMPRATE_125MV 1 +#define BUCK_RAMP_MAX 250 + +static const struct regulator_linear_range bd70528_buck1_volts[] = { + REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x1, 600000), + REGULATOR_LINEAR_RANGE(2750000, 0x2, 0xf, 50000), +}; +static const struct regulator_linear_range bd70528_buck2_volts[] = { + REGULATOR_LINEAR_RANGE(1200000, 0x00, 0x1, 300000), + REGULATOR_LINEAR_RANGE(1550000, 0x2, 0xd, 50000), + REGULATOR_LINEAR_RANGE(3000000, 0xe, 0xf, 300000), +}; +static const struct regulator_linear_range bd70528_buck3_volts[] = { + REGULATOR_LINEAR_RANGE(800000, 0x00, 0xd, 50000), + REGULATOR_LINEAR_RANGE(1800000, 0xe, 0xf, 0), +}; + +/* All LDOs have same voltage ranges */ +static const struct regulator_linear_range bd70528_ldo_volts[] = { + REGULATOR_LINEAR_RANGE(1650000, 0x0, 0x07, 50000), + REGULATOR_LINEAR_RANGE(2100000, 0x8, 0x0f, 100000), + REGULATOR_LINEAR_RANGE(2850000, 0x10, 0x19, 50000), + REGULATOR_LINEAR_RANGE(3300000, 0x19, 0x1f, 0), +}; + +/* Also both LEDs support same voltages */ +static const unsigned int led_volts[] = { + 20000, 30000 +}; + +static int bd70528_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) +{ + if (ramp_delay > 0 && ramp_delay <= BUCK_RAMP_MAX) { + unsigned int ramp_value = BUCK_RAMPRATE_250MV; + + if (ramp_delay <= 125) + ramp_value = BUCK_RAMPRATE_125MV; + + return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, + BD70528_MASK_BUCK_RAMP, + ramp_value << BD70528_SIFT_BUCK_RAMP); + } + dev_err(&rdev->dev, "%s: ramp_delay: %d not supported\n", + rdev->desc->name, ramp_delay); + return -EINVAL; +} + +static int bd70528_led_set_voltage_sel(struct regulator_dev *rdev, + unsigned int sel) +{ + int ret; + + ret = regulator_is_enabled_regmap(rdev); + if (ret < 0) + return ret; + + if (ret == 0) + return regulator_set_voltage_sel_regmap(rdev, sel); + + dev_err(&rdev->dev, + "LED voltage change not allowed when led is enabled\n"); + + return -EBUSY; +} + +static const struct regulator_ops bd70528_buck_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = bd70528_set_ramp_delay, +}; + +static const struct regulator_ops bd70528_ldo_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = bd70528_set_ramp_delay, +}; + +static const struct regulator_ops bd70528_led_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = bd70528_led_set_voltage_sel, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static const struct regulator_desc bd70528_desc[] = { + { + .name = "buck1", + .of_match = of_match_ptr("BUCK1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD70528_BUCK1, + .ops = &bd70528_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd70528_buck1_volts, + .n_linear_ranges = ARRAY_SIZE(bd70528_buck1_volts), + .n_voltages = BD70528_BUCK_VOLTS, + .enable_reg = BD70528_REG_BUCK1_EN, + .enable_mask = BD70528_MASK_RUN_EN, + .vsel_reg = BD70528_REG_BUCK1_VOLT, + .vsel_mask = BD70528_MASK_BUCK_VOLT, + .owner = THIS_MODULE, + }, + { + .name = "buck2", + .of_match = of_match_ptr("BUCK2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD70528_BUCK2, + .ops = &bd70528_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd70528_buck2_volts, + .n_linear_ranges = ARRAY_SIZE(bd70528_buck2_volts), + .n_voltages = BD70528_BUCK_VOLTS, + .enable_reg = BD70528_REG_BUCK2_EN, + .enable_mask = BD70528_MASK_RUN_EN, + .vsel_reg = BD70528_REG_BUCK2_VOLT, + .vsel_mask = BD70528_MASK_BUCK_VOLT, + .owner = THIS_MODULE, + }, + { + .name = "buck3", + .of_match = of_match_ptr("BUCK3"), + .regulators_node = of_match_ptr("regulators"), + .id = BD70528_BUCK3, + .ops = &bd70528_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd70528_buck3_volts, + .n_linear_ranges = ARRAY_SIZE(bd70528_buck3_volts), + .n_voltages = BD70528_BUCK_VOLTS, + .enable_reg = BD70528_REG_BUCK3_EN, + .enable_mask = BD70528_MASK_RUN_EN, + .vsel_reg = BD70528_REG_BUCK3_VOLT, + .vsel_mask = BD70528_MASK_BUCK_VOLT, + .owner = THIS_MODULE, + }, + { + .name = "ldo1", + .of_match = of_match_ptr("LDO1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD70528_LDO1, + .ops = &bd70528_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd70528_ldo_volts, + .n_linear_ranges = ARRAY_SIZE(bd70528_ldo_volts), + .n_voltages = BD70528_LDO_VOLTS, + .enable_reg = BD70528_REG_LDO1_EN, + .enable_mask = BD70528_MASK_RUN_EN, + .vsel_reg = BD70528_REG_LDO1_VOLT, + .vsel_mask = BD70528_MASK_LDO_VOLT, + .owner = THIS_MODULE, + }, + { + .name = "ldo2", + .of_match = of_match_ptr("LDO2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD70528_LDO2, + .ops = &bd70528_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd70528_ldo_volts, + .n_linear_ranges = ARRAY_SIZE(bd70528_ldo_volts), + .n_voltages = BD70528_LDO_VOLTS, + .enable_reg = BD70528_REG_LDO2_EN, + .enable_mask = BD70528_MASK_RUN_EN, + .vsel_reg = BD70528_REG_LDO2_VOLT, + .vsel_mask = BD70528_MASK_LDO_VOLT, + .owner = THIS_MODULE, + }, + { + .name = "ldo3", + .of_match = of_match_ptr("LDO3"), + .regulators_node = of_match_ptr("regulators"), + .id = BD70528_LDO3, + .ops = &bd70528_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd70528_ldo_volts, + .n_linear_ranges = ARRAY_SIZE(bd70528_ldo_volts), + .n_voltages = BD70528_LDO_VOLTS, + .enable_reg = BD70528_REG_LDO3_EN, + .enable_mask = BD70528_MASK_RUN_EN, + .vsel_reg = BD70528_REG_LDO3_VOLT, + .vsel_mask = BD70528_MASK_LDO_VOLT, + .owner = THIS_MODULE, + }, + { + .name = "ldo_led1", + .of_match = of_match_ptr("LDO_LED1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD70528_LED1, + .ops = &bd70528_led_ops, + .type = REGULATOR_VOLTAGE, + .volt_table = &led_volts[0], + .n_voltages = ARRAY_SIZE(led_volts), + .enable_reg = BD70528_REG_LED_EN, + .enable_mask = BD70528_MASK_LED1_EN, + .vsel_reg = BD70528_REG_LED_VOLT, + .vsel_mask = BD70528_MASK_LED1_VOLT, + .owner = THIS_MODULE, + }, + { + .name = "ldo_led2", + .of_match = of_match_ptr("LDO_LED2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD70528_LED2, + .ops = &bd70528_led_ops, + .type = REGULATOR_VOLTAGE, + .volt_table = &led_volts[0], + .n_voltages = ARRAY_SIZE(led_volts), + .enable_reg = BD70528_REG_LED_EN, + .enable_mask = BD70528_MASK_LED2_EN, + .vsel_reg = BD70528_REG_LED_VOLT, + .vsel_mask = BD70528_MASK_LED2_VOLT, + .owner = THIS_MODULE, + }, + +}; + +static int bd70528_probe(struct platform_device *pdev) +{ + struct rohm_regmap_dev *bd70528; + int i; + struct regulator_config config = { + .dev = pdev->dev.parent, + }; + + bd70528 = dev_get_drvdata(pdev->dev.parent); + if (!bd70528) { + dev_err(&pdev->dev, "No MFD driver data\n"); + return -EINVAL; + } + + config.regmap = bd70528->regmap; + + for (i = 0; i < ARRAY_SIZE(bd70528_desc); i++) { + struct regulator_dev *rdev; + + rdev = devm_regulator_register(&pdev->dev, &bd70528_desc[i], + &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, + "failed to register %s regulator\n", + bd70528_desc[i].name); + return PTR_ERR(rdev); + } + } + return 0; +} + +static struct platform_driver bd70528_regulator = { + .driver = { + .name = "bd70528-pmic" + }, + .probe = bd70528_probe, +}; + +module_platform_driver(bd70528_regulator); + +MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); +MODULE_DESCRIPTION("BD70528 voltage regulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c index 3a47e0372e77..b2191be49670 100644 --- a/drivers/regulator/bd718x7-regulator.c +++ b/drivers/regulator/bd718x7-regulator.c @@ -9,6 +9,7 @@ #include <linux/kernel.h> #include <linux/mfd/rohm-bd718x7.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> @@ -78,7 +79,7 @@ static int bd718xx_set_voltage_sel_pickable_restricted( return regulator_set_voltage_sel_pickable_regmap(rdev, sel); } -static struct regulator_ops bd718xx_pickable_range_ldo_ops = { +static const struct regulator_ops bd718xx_pickable_range_ldo_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -87,7 +88,7 @@ static struct regulator_ops bd718xx_pickable_range_ldo_ops = { .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap, }; -static struct regulator_ops bd718xx_pickable_range_buck_ops = { +static const struct regulator_ops bd718xx_pickable_range_buck_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -97,7 +98,7 @@ static struct regulator_ops bd718xx_pickable_range_buck_ops = { .set_voltage_time_sel = regulator_set_voltage_time_sel, }; -static struct regulator_ops bd718xx_ldo_regulator_ops = { +static const struct regulator_ops bd718xx_ldo_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -106,7 +107,7 @@ static struct regulator_ops bd718xx_ldo_regulator_ops = { .get_voltage_sel = regulator_get_voltage_sel_regmap, }; -static struct regulator_ops bd718xx_ldo_regulator_nolinear_ops = { +static const struct regulator_ops bd718xx_ldo_regulator_nolinear_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -115,7 +116,7 @@ static struct regulator_ops bd718xx_ldo_regulator_nolinear_ops = { .get_voltage_sel = regulator_get_voltage_sel_regmap, }; -static struct regulator_ops bd718xx_buck_regulator_ops = { +static const struct regulator_ops bd718xx_buck_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -125,17 +126,18 @@ static struct regulator_ops bd718xx_buck_regulator_ops = { .set_voltage_time_sel = regulator_set_voltage_time_sel, }; -static struct regulator_ops bd718xx_buck_regulator_nolinear_ops = { +static const struct regulator_ops bd718xx_buck_regulator_nolinear_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = bd718xx_set_voltage_sel_restricted, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, }; -static struct regulator_ops bd718xx_dvs_buck_regulator_ops = { +static const struct regulator_ops bd718xx_dvs_buck_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -348,6 +350,135 @@ static const struct reg_init bd71837_ldo6_inits[] = { }, }; +#define NUM_DVS_BUCKS 4 + +struct of_dvs_setting { + const char *prop; + unsigned int reg; +}; + +static int set_dvs_levels(const struct of_dvs_setting *dvs, + struct device_node *np, + const struct regulator_desc *desc, + struct regmap *regmap) +{ + int ret, i; + unsigned int uv; + + ret = of_property_read_u32(np, dvs->prop, &uv); + if (ret) { + if (ret != -EINVAL) + return ret; + return 0; + } + + for (i = 0; i < desc->n_voltages; i++) { + ret = regulator_desc_list_voltage_linear_range(desc, i); + if (ret < 0) + continue; + if (ret == uv) { + i <<= ffs(desc->vsel_mask) - 1; + ret = regmap_update_bits(regmap, dvs->reg, + DVS_BUCK_RUN_MASK, i); + break; + } + } + return ret; +} + +static int buck4_set_hw_dvs_levels(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *cfg) +{ + int ret, i; + const struct of_dvs_setting dvs[] = { + { + .prop = "rohm,dvs-run-voltage", + .reg = BD71837_REG_BUCK4_VOLT_RUN, + }, + }; + + for (i = 0; i < ARRAY_SIZE(dvs); i++) { + ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap); + if (ret) + break; + } + return ret; +} +static int buck3_set_hw_dvs_levels(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *cfg) +{ + int ret, i; + const struct of_dvs_setting dvs[] = { + { + .prop = "rohm,dvs-run-voltage", + .reg = BD71837_REG_BUCK3_VOLT_RUN, + }, + }; + + for (i = 0; i < ARRAY_SIZE(dvs); i++) { + ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap); + if (ret) + break; + } + return ret; +} + +static int buck2_set_hw_dvs_levels(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *cfg) +{ + int ret, i; + const struct of_dvs_setting dvs[] = { + { + .prop = "rohm,dvs-run-voltage", + .reg = BD718XX_REG_BUCK2_VOLT_RUN, + }, + { + .prop = "rohm,dvs-idle-voltage", + .reg = BD718XX_REG_BUCK2_VOLT_IDLE, + }, + }; + + + + for (i = 0; i < ARRAY_SIZE(dvs); i++) { + ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap); + if (ret) + break; + } + return ret; +} + +static int buck1_set_hw_dvs_levels(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *cfg) +{ + int ret, i; + const struct of_dvs_setting dvs[] = { + { + .prop = "rohm,dvs-run-voltage", + .reg = BD718XX_REG_BUCK1_VOLT_RUN, + }, + { + .prop = "rohm,dvs-idle-voltage", + .reg = BD718XX_REG_BUCK1_VOLT_IDLE, + }, + { + .prop = "rohm,dvs-suspend-voltage", + .reg = BD718XX_REG_BUCK1_VOLT_SUSP, + }, + }; + + for (i = 0; i < ARRAY_SIZE(dvs); i++) { + ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap); + if (ret) + break; + } + return ret; +} + static const struct bd718xx_regulator_data bd71847_regulators[] = { { .desc = { @@ -366,6 +497,7 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = { .enable_reg = BD718XX_REG_BUCK1_CTRL, .enable_mask = BD718XX_BUCK_EN, .owner = THIS_MODULE, + .of_parse_cb = buck1_set_hw_dvs_levels, }, .init = { .reg = BD718XX_REG_BUCK1_CTRL, @@ -389,6 +521,7 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = { .enable_reg = BD718XX_REG_BUCK2_CTRL, .enable_mask = BD718XX_BUCK_EN, .owner = THIS_MODULE, + .of_parse_cb = buck2_set_hw_dvs_levels, }, .init = { .reg = BD718XX_REG_BUCK2_CTRL, @@ -660,6 +793,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = { .enable_reg = BD718XX_REG_BUCK1_CTRL, .enable_mask = BD718XX_BUCK_EN, .owner = THIS_MODULE, + .of_parse_cb = buck1_set_hw_dvs_levels, }, .init = { .reg = BD718XX_REG_BUCK1_CTRL, @@ -683,6 +817,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = { .enable_reg = BD718XX_REG_BUCK2_CTRL, .enable_mask = BD718XX_BUCK_EN, .owner = THIS_MODULE, + .of_parse_cb = buck2_set_hw_dvs_levels, }, .init = { .reg = BD718XX_REG_BUCK2_CTRL, @@ -706,6 +841,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = { .enable_reg = BD71837_REG_BUCK3_CTRL, .enable_mask = BD718XX_BUCK_EN, .owner = THIS_MODULE, + .of_parse_cb = buck3_set_hw_dvs_levels, }, .init = { .reg = BD71837_REG_BUCK3_CTRL, @@ -729,6 +865,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = { .enable_reg = BD71837_REG_BUCK4_CTRL, .enable_mask = BD718XX_BUCK_EN, .owner = THIS_MODULE, + .of_parse_cb = buck4_set_hw_dvs_levels, }, .init = { .reg = BD71837_REG_BUCK4_CTRL, @@ -1007,7 +1144,7 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = { }; struct bd718xx_pmic_inits { - const struct bd718xx_regulator_data (*r_datas)[]; + const struct bd718xx_regulator_data *r_datas; unsigned int r_amount; }; @@ -1017,16 +1154,17 @@ static int bd718xx_probe(struct platform_device *pdev) struct regulator_config config = { 0 }; struct bd718xx_pmic_inits pmic_regulators[] = { [BD718XX_TYPE_BD71837] = { - .r_datas = &bd71837_regulators, + .r_datas = bd71837_regulators, .r_amount = ARRAY_SIZE(bd71837_regulators), }, [BD718XX_TYPE_BD71847] = { - .r_datas = &bd71847_regulators, + .r_datas = bd71847_regulators, .r_amount = ARRAY_SIZE(bd71847_regulators), }, }; int i, j, err; + bool use_snvs; mfd = dev_get_drvdata(pdev->dev.parent); if (!mfd) { @@ -1053,13 +1191,37 @@ static int bd718xx_probe(struct platform_device *pdev) BD718XX_REG_REGLOCK); } + use_snvs = of_property_read_bool(pdev->dev.parent->of_node, + "rohm,reset-snvs-powered"); + + /* + * Change the next stage from poweroff to be READY instead of SNVS + * for all reset types because OTP loading at READY will clear SEL + * bit allowing HW defaults for power rails to be used + */ + if (!use_snvs) { + err = regmap_update_bits(mfd->regmap, BD718XX_REG_TRANS_COND1, + BD718XX_ON_REQ_POWEROFF_MASK | + BD718XX_SWRESET_POWEROFF_MASK | + BD718XX_WDOG_POWEROFF_MASK | + BD718XX_KEY_L_POWEROFF_MASK, + BD718XX_POWOFF_TO_RDY); + if (err) { + dev_err(&pdev->dev, "Failed to change reset target\n"); + goto err; + } else { + dev_dbg(&pdev->dev, + "Changed all resets from SVNS to READY\n"); + } + } + for (i = 0; i < pmic_regulators[mfd->chip_type].r_amount; i++) { const struct regulator_desc *desc; struct regulator_dev *rdev; const struct bd718xx_regulator_data *r; - r = &(*pmic_regulators[mfd->chip_type].r_datas)[i]; + r = &pmic_regulators[mfd->chip_type].r_datas[i]; desc = &r->desc; config.dev = pdev->dev.parent; @@ -1073,19 +1235,33 @@ static int bd718xx_probe(struct platform_device *pdev) err = PTR_ERR(rdev); goto err; } - /* Regulator register gets the regulator constraints and + + /* + * Regulator register gets the regulator constraints and * applies them (set_machine_constraints). This should have * turned the control register(s) to correct values and we * can now switch the control from PMIC state machine to the * register interface + * + * At poweroff transition PMIC HW disables EN bit for + * regulators but leaves SEL bit untouched. So if state + * transition from POWEROFF is done to SNVS - then all power + * rails controlled by SW (having SEL bit set) stay disabled + * as EN is cleared. This will result boot failure if any + * crucial systems are powered by these rails. We don't + * enable SW control for crucial regulators if snvs state is + * used */ - err = regmap_update_bits(mfd->regmap, r->init.reg, - r->init.mask, r->init.val); - if (err) { - dev_err(&pdev->dev, - "Failed to write BUCK/LDO SEL bit for (%s)\n", - desc->name); - goto err; + if (!use_snvs || !rdev->constraints->always_on || + !rdev->constraints->boot_on) { + err = regmap_update_bits(mfd->regmap, r->init.reg, + r->init.mask, r->init.val); + if (err) { + dev_err(&pdev->dev, + "Failed to take control for (%s)\n", + desc->name); + goto err; + } } for (j = 0; j < r->additional_init_amnt; j++) { err = regmap_update_bits(mfd->regmap, diff --git a/drivers/regulator/bd9571mwv-regulator.c b/drivers/regulator/bd9571mwv-regulator.c index 274c5ed7cd73..e690c2ce5b3c 100644 --- a/drivers/regulator/bd9571mwv-regulator.c +++ b/drivers/regulator/bd9571mwv-regulator.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * ROHM BD9571MWV-M regulator driver * * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65086 driver * * NOTE: VD09 is missing @@ -108,7 +100,7 @@ static int bd9571mwv_reg_set_voltage_sel_regmap(struct regulator_dev *rdev, } /* Operations permitted on AVS voltage regulator */ -static struct regulator_ops avs_ops = { +static const struct regulator_ops avs_ops = { .set_voltage_sel = bd9571mwv_avs_set_voltage_sel_regmap, .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = bd9571mwv_avs_get_voltage_sel_regmap, @@ -116,7 +108,7 @@ static struct regulator_ops avs_ops = { }; /* Operations permitted on voltage regulators */ -static struct regulator_ops reg_ops = { +static const struct regulator_ops reg_ops = { .set_voltage_sel = bd9571mwv_reg_set_voltage_sel_regmap, .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -124,13 +116,13 @@ static struct regulator_ops reg_ops = { }; /* Operations permitted on voltage monitors */ -static struct regulator_ops vid_ops = { +static const struct regulator_ops vid_ops = { .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, }; -static struct regulator_desc regulators[] = { +static const struct regulator_desc regulators[] = { BD9571MWV_REG("VD09", "vd09", VD09, avs_ops, 0, 0x7f, 0x80, 600000, 10000, 0x3c), BD9571MWV_REG("VD18", "vd18", VD18, vid_ops, BD9571MWV_VD18_VID, 0xf, diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 2c66b528aede..68473d0cc57e 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -23,7 +23,6 @@ #include <linux/mutex.h> #include <linux/suspend.h> #include <linux/delay.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/of.h> #include <linux/regmap.h> @@ -50,6 +49,8 @@ #define rdev_dbg(rdev, fmt, ...) \ pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) +static DEFINE_WW_CLASS(regulator_ww_class); +static DEFINE_MUTEX(regulator_nesting_mutex); static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_map_list); static LIST_HEAD(regulator_ena_gpio_list); @@ -80,7 +81,6 @@ struct regulator_enable_gpio { struct gpio_desc *gpiod; u32 enable_count; /* a number of enabled shared GPIO */ u32 request_count; /* a number of requested shared GPIO */ - unsigned int ena_gpio_invert:1; }; /* @@ -97,7 +97,7 @@ struct regulator_supply_alias { }; static int _regulator_is_enabled(struct regulator_dev *rdev); -static int _regulator_disable(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); @@ -105,6 +105,11 @@ static int _notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data); 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); @@ -138,18 +143,10 @@ static bool regulator_ops_is_valid(struct regulator_dev *rdev, int ops) return false; } -static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev) -{ - if (rdev && rdev->supply) - return rdev->supply->rdev; - - return NULL; -} - /** * regulator_lock_nested - lock a single regulator * @rdev: regulator source - * @subclass: mutex subclass used for lockdep + * @ww_ctx: w/w mutex acquire context * * This function can be called many times by one task on * a single regulator and its mutex will be locked only @@ -157,25 +154,54 @@ static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev) * than the one, which initially locked the mutex, it will * wait on mutex. */ -static void regulator_lock_nested(struct regulator_dev *rdev, - unsigned int subclass) +static inline int regulator_lock_nested(struct regulator_dev *rdev, + struct ww_acquire_ctx *ww_ctx) { - if (!mutex_trylock(&rdev->mutex)) { - if (rdev->mutex_owner == current) { + bool lock = false; + int ret = 0; + + mutex_lock(®ulator_nesting_mutex); + + if (ww_ctx || !ww_mutex_trylock(&rdev->mutex)) { + if (rdev->mutex_owner == current) rdev->ref_cnt++; - return; + else + lock = true; + + if (lock) { + mutex_unlock(®ulator_nesting_mutex); + ret = ww_mutex_lock(&rdev->mutex, ww_ctx); + mutex_lock(®ulator_nesting_mutex); } - mutex_lock_nested(&rdev->mutex, subclass); + } else { + lock = true; } - rdev->ref_cnt = 1; - rdev->mutex_owner = current; + if (lock && ret != -EDEADLK) { + rdev->ref_cnt++; + rdev->mutex_owner = current; + } + + mutex_unlock(®ulator_nesting_mutex); + + return ret; } -static inline void regulator_lock(struct regulator_dev *rdev) +/** + * regulator_lock - lock a single regulator + * @rdev: regulator source + * + * This function can be called many times by one task on + * a single regulator and its mutex will be locked only + * once. If a task, which is calling this function is other + * than the one, which initially locked the mutex, it will + * wait on mutex. + */ +void regulator_lock(struct regulator_dev *rdev) { - regulator_lock_nested(rdev, 0); + regulator_lock_nested(rdev, NULL); } +EXPORT_SYMBOL_GPL(regulator_lock); /** * regulator_unlock - unlock a single regulator @@ -184,47 +210,191 @@ static inline void regulator_lock(struct regulator_dev *rdev) * This function unlocks the mutex when the * reference counter reaches 0. */ -static void regulator_unlock(struct regulator_dev *rdev) +void regulator_unlock(struct regulator_dev *rdev) { - if (rdev->ref_cnt != 0) { - rdev->ref_cnt--; + mutex_lock(®ulator_nesting_mutex); + + if (--rdev->ref_cnt == 0) { + rdev->mutex_owner = NULL; + ww_mutex_unlock(&rdev->mutex); + } + + WARN_ON_ONCE(rdev->ref_cnt < 0); - if (!rdev->ref_cnt) { - rdev->mutex_owner = NULL; - mutex_unlock(&rdev->mutex); + mutex_unlock(®ulator_nesting_mutex); +} +EXPORT_SYMBOL_GPL(regulator_unlock); + +static bool regulator_supply_is_couple(struct regulator_dev *rdev) +{ + struct regulator_dev *c_rdev; + int i; + + for (i = 1; i < rdev->coupling_desc.n_coupled; i++) { + c_rdev = rdev->coupling_desc.coupled_rdevs[i]; + + if (rdev->supply->rdev == c_rdev) + return true; + } + + return false; +} + +static void regulator_unlock_recursive(struct regulator_dev *rdev, + unsigned int n_coupled) +{ + struct regulator_dev *c_rdev; + int i; + + for (i = n_coupled; i > 0; i--) { + c_rdev = rdev->coupling_desc.coupled_rdevs[i - 1]; + + if (!c_rdev) + continue; + + if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) + regulator_unlock_recursive( + c_rdev->supply->rdev, + c_rdev->coupling_desc.n_coupled); + + regulator_unlock(c_rdev); + } +} + +static int regulator_lock_recursive(struct regulator_dev *rdev, + struct regulator_dev **new_contended_rdev, + struct regulator_dev **old_contended_rdev, + struct ww_acquire_ctx *ww_ctx) +{ + struct regulator_dev *c_rdev; + int i, err; + + for (i = 0; i < rdev->coupling_desc.n_coupled; i++) { + c_rdev = rdev->coupling_desc.coupled_rdevs[i]; + + if (!c_rdev) + continue; + + if (c_rdev != *old_contended_rdev) { + err = regulator_lock_nested(c_rdev, ww_ctx); + if (err) { + if (err == -EDEADLK) { + *new_contended_rdev = c_rdev; + goto err_unlock; + } + + /* shouldn't happen */ + WARN_ON_ONCE(err != -EALREADY); + } + } else { + *old_contended_rdev = NULL; + } + + if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) { + err = regulator_lock_recursive(c_rdev->supply->rdev, + new_contended_rdev, + old_contended_rdev, + ww_ctx); + if (err) { + regulator_unlock(c_rdev); + goto err_unlock; + } } } + + return 0; + +err_unlock: + regulator_unlock_recursive(rdev, i); + + return err; } /** - * regulator_lock_supply - lock a regulator and its supplies - * @rdev: regulator source + * regulator_unlock_dependent - unlock regulator's suppliers and coupled + * regulators + * @rdev: regulator source + * @ww_ctx: w/w mutex acquire context + * + * Unlock all regulators related with rdev by coupling or supplying. */ -static void regulator_lock_supply(struct regulator_dev *rdev) +static void regulator_unlock_dependent(struct regulator_dev *rdev, + struct ww_acquire_ctx *ww_ctx) { - int i; - - for (i = 0; rdev; rdev = rdev_get_supply(rdev), i++) - regulator_lock_nested(rdev, i); + regulator_unlock_recursive(rdev, rdev->coupling_desc.n_coupled); + ww_acquire_fini(ww_ctx); } /** - * regulator_unlock_supply - unlock a regulator and its supplies - * @rdev: regulator source + * regulator_lock_dependent - lock regulator's suppliers and coupled regulators + * @rdev: regulator source + * @ww_ctx: w/w mutex acquire context + * + * This function as a wrapper on regulator_lock_recursive(), which locks + * all regulators related with rdev by coupling or supplying. */ -static void regulator_unlock_supply(struct regulator_dev *rdev) +static void regulator_lock_dependent(struct regulator_dev *rdev, + struct ww_acquire_ctx *ww_ctx) { - struct regulator *supply; + struct regulator_dev *new_contended_rdev = NULL; + struct regulator_dev *old_contended_rdev = NULL; + int err; - while (1) { - regulator_unlock(rdev); - supply = rdev->supply; + mutex_lock(®ulator_list_mutex); + + ww_acquire_init(ww_ctx, ®ulator_ww_class); + + do { + if (new_contended_rdev) { + ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx); + old_contended_rdev = new_contended_rdev; + old_contended_rdev->ref_cnt++; + } + + err = regulator_lock_recursive(rdev, + &new_contended_rdev, + &old_contended_rdev, + ww_ctx); + + if (old_contended_rdev) + regulator_unlock(old_contended_rdev); + + } while (err == -EDEADLK); + + ww_acquire_done(ww_ctx); + + mutex_unlock(®ulator_list_mutex); +} - if (!rdev->supply) - return; +/** + * of_get_child_regulator - get a child regulator device node + * based on supply name + * @parent: Parent device node + * @prop_name: Combination regulator supply name and "-supply" + * + * Traverse all child nodes. + * Extract the child regulator device node corresponding to the supply name. + * returns the device node corresponding to the regulator if found, else + * returns NULL. + */ +static struct device_node *of_get_child_regulator(struct device_node *parent, + const char *prop_name) +{ + struct device_node *regnode = NULL; + struct device_node *child = NULL; - rdev = supply->rdev; + for_each_child_of_node(parent, child) { + regnode = of_parse_phandle(child, prop_name, 0); + + if (!regnode) { + regnode = of_get_child_regulator(child, prop_name); + if (regnode) + return regnode; + } else { + return regnode; + } } + return NULL; } /** @@ -247,6 +417,10 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp regnode = of_parse_phandle(dev->of_node, prop_name, 0); if (!regnode) { + regnode = of_get_child_regulator(dev->of_node, prop_name); + if (regnode) + return regnode; + dev_dbg(dev, "Looking up %s property in node %pOF failed\n", prop_name, dev->of_node); return NULL; @@ -582,8 +756,10 @@ static ssize_t regulator_total_uA_show(struct device *dev, int uA = 0; regulator_lock(rdev); - list_for_each_entry(regulator, &rdev->consumer_list, list) - uA += regulator->uA_load; + list_for_each_entry(regulator, &rdev->consumer_list, list) { + if (regulator->enable_count) + uA += regulator->uA_load; + } regulator_unlock(rdev); return sprintf(buf, "%d\n", uA); } @@ -738,14 +914,14 @@ static int drms_uA_update(struct regulator_dev *rdev) int current_uA = 0, output_uV, input_uV, err; unsigned int mode; - lockdep_assert_held_once(&rdev->mutex); - /* * first check to see if we can set modes at all, otherwise just * tell the consumer everything is OK. */ - if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS)) + if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS)) { + rdev_dbg(rdev, "DRMS operation not allowed\n"); return 0; + } if (!rdev->desc->ops->get_optimum_mode && !rdev->desc->ops->set_load) @@ -756,8 +932,10 @@ static int drms_uA_update(struct regulator_dev *rdev) return -EINVAL; /* calc total requested load */ - list_for_each_entry(sibling, &rdev->consumer_list, list) - current_uA += sibling->uA_load; + list_for_each_entry(sibling, &rdev->consumer_list, list) { + if (sibling->enable_count) + current_uA += sibling->uA_load; + } current_uA += rdev->constraints->system_load; @@ -815,7 +993,7 @@ static int suspend_set_state(struct regulator_dev *rdev, if (rstate == NULL) return 0; - /* If we have no suspend mode configration don't set anything; + /* If we have no suspend mode configuration don't set anything; * only warn if the driver implements set_suspend_voltage or * set_suspend_mode callback. */ @@ -943,7 +1121,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, int current_uV = _regulator_get_voltage(rdev); if (current_uV == -ENOTRECOVERABLE) { - /* This regulator can't be read and must be initted */ + /* This regulator can't be read and must be initialized */ rdev_info(rdev, "Setting %d-%duV\n", rdev->constraints->min_uV, rdev->constraints->max_uV); @@ -1156,17 +1334,14 @@ static int set_machine_constraints(struct regulator_dev *rdev, rdev_err(rdev, "failed to set initial mode: %d\n", ret); return ret; } - } - - /* If the constraints say the regulator should be on at this point - * and we have control then make sure it is enabled. - */ - if (rdev->constraints->always_on || rdev->constraints->boot_on) { - ret = _regulator_do_enable(rdev); - if (ret < 0 && ret != -EINVAL) { - rdev_err(rdev, "failed to enable\n"); - return ret; - } + } else if (rdev->constraints->system_load) { + /* + * We'll only apply the initial system load if an + * initial mode wasn't specified. + */ + regulator_lock(rdev); + drms_uA_update(rdev); + regulator_unlock(rdev); } if ((rdev->constraints->ramp_delay || rdev->constraints->ramp_disable) @@ -1214,6 +1389,27 @@ static int set_machine_constraints(struct regulator_dev *rdev, } } + /* If the constraints say the regulator should be on at this point + * and we have control then make sure it is enabled. + */ + if (rdev->constraints->always_on || rdev->constraints->boot_on) { + if (rdev->supply) { + ret = regulator_enable(rdev->supply); + if (ret < 0) { + _regulator_put(rdev->supply); + rdev->supply = NULL; + return ret; + } + } + + ret = _regulator_do_enable(rdev); + if (ret < 0 && ret != -EINVAL) { + rdev_err(rdev, "failed to enable\n"); + return ret; + } + rdev->use_count++; + } + print_constraints(rdev); return 0; } @@ -1576,7 +1772,7 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) struct device *dev = rdev->dev.parent; int ret; - /* No supply to resovle? */ + /* No supply to resolve? */ if (!rdev->supply_name) return 0; @@ -1628,8 +1824,12 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) return ret; } - /* Cascade always-on state to supply */ - if (_regulator_is_enabled(rdev)) { + /* + * In set_machine_constraints() we may have turned this regulator on + * but we couldn't propagate to the supply if it hadn't been resolved + * yet. Do it now. + */ + if (rdev->use_count) { ret = regulator_enable(rdev->supply); if (ret < 0) { _regulator_put(rdev->supply); @@ -1713,6 +1913,16 @@ struct regulator *_regulator_get(struct device *dev, const char *id, return regulator; } + mutex_lock(®ulator_list_mutex); + ret = (rdev->coupling_desc.n_resolved != rdev->coupling_desc.n_coupled); + mutex_unlock(®ulator_list_mutex); + + if (ret != 0) { + regulator = ERR_PTR(-EPROBE_DEFER); + put_device(&rdev->dev); + return regulator; + } + ret = regulator_resolve_supply(rdev); if (ret < 0) { regulator = ERR_PTR(ret); @@ -1832,20 +2042,15 @@ static void _regulator_put(struct regulator *regulator) lockdep_assert_held_once(®ulator_list_mutex); + /* Docs say you must disable before calling regulator_put() */ + WARN_ON(regulator->enable_count); + rdev = regulator->rdev; debugfs_remove_recursive(regulator->debugfs); if (regulator->dev) { - int count = 0; - struct regulator *r; - - list_for_each_entry(r, &rdev->consumer_list, list) - if (r->dev == regulator->dev) - count++; - - if (count == 1) - device_link_remove(regulator->dev, &rdev->dev); + device_link_remove(regulator->dev, &rdev->dev); /* remove any sysfs entries */ sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); @@ -2016,38 +2221,21 @@ static int regulator_ena_gpio_request(struct regulator_dev *rdev, { struct regulator_enable_gpio *pin; struct gpio_desc *gpiod; - int ret; - if (config->ena_gpiod) - gpiod = config->ena_gpiod; - else - gpiod = gpio_to_desc(config->ena_gpio); + gpiod = config->ena_gpiod; list_for_each_entry(pin, ®ulator_ena_gpio_list, list) { if (pin->gpiod == gpiod) { - rdev_dbg(rdev, "GPIO %d is already used\n", - config->ena_gpio); + rdev_dbg(rdev, "GPIO is already used\n"); goto update_ena_gpio_to_rdev; } } - if (!config->ena_gpiod) { - ret = gpio_request_one(config->ena_gpio, - GPIOF_DIR_OUT | config->ena_gpio_flags, - rdev_get_name(rdev)); - if (ret) - return ret; - } - pin = kzalloc(sizeof(struct regulator_enable_gpio), GFP_KERNEL); - if (pin == NULL) { - if (!config->ena_gpiod) - gpio_free(config->ena_gpio); + if (pin == NULL) return -ENOMEM; - } pin->gpiod = gpiod; - pin->ena_gpio_invert = config->ena_gpio_invert; list_add(&pin->list, ®ulator_ena_gpio_list); update_ena_gpio_to_rdev: @@ -2068,7 +2256,6 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev) if (pin->gpiod == rdev->ena_pin->gpiod) { if (pin->request_count <= 1) { pin->request_count = 0; - gpiod_put(pin->gpiod); list_del(&pin->list); kfree(pin); rdev->ena_pin = NULL; @@ -2098,8 +2285,7 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) if (enable) { /* Enable GPIO at initial use */ if (pin->enable_count == 0) - gpiod_set_value_cansleep(pin->gpiod, - !pin->ena_gpio_invert); + gpiod_set_value_cansleep(pin->gpiod, 1); pin->enable_count++; } else { @@ -2110,8 +2296,7 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) /* Disable GPIO if not used */ if (pin->enable_count <= 1) { - gpiod_set_value_cansleep(pin->gpiod, - pin->ena_gpio_invert); + gpiod_set_value_cansleep(pin->gpiod, 0); pin->enable_count = 0; } } @@ -2188,7 +2373,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) * timer wrapping. * in case of multiple timer wrapping, either it can be * detected by out-of-range remaining, or it cannot be - * detected and we gets a panelty of + * detected and we get a penalty of * _regulator_enable_delay(). */ remaining = intended - start_jiffy; @@ -2225,34 +2410,109 @@ static int _regulator_do_enable(struct regulator_dev *rdev) return 0; } +/** + * _regulator_handle_consumer_enable - handle that a consumer enabled + * @regulator: regulator source + * + * Some things on a regulator consumer (like the contribution towards total + * load on the regulator) only have an effect when the consumer wants the + * regulator enabled. Explained in example with two consumers of the same + * regulator: + * consumer A: set_load(100); => total load = 0 + * consumer A: regulator_enable(); => total load = 100 + * consumer B: set_load(1000); => total load = 100 + * consumer B: regulator_enable(); => total load = 1100 + * consumer A: regulator_disable(); => total_load = 1000 + * + * This function (together with _regulator_handle_consumer_disable) is + * responsible for keeping track of the refcount for a given regulator consumer + * and applying / unapplying these things. + * + * Returns 0 upon no error; -error upon error. + */ +static int _regulator_handle_consumer_enable(struct regulator *regulator) +{ + struct regulator_dev *rdev = regulator->rdev; + + lockdep_assert_held_once(&rdev->mutex.base); + + regulator->enable_count++; + if (regulator->uA_load && regulator->enable_count == 1) + return drms_uA_update(rdev); + + return 0; +} + +/** + * _regulator_handle_consumer_disable - handle that a consumer disabled + * @regulator: regulator source + * + * The opposite of _regulator_handle_consumer_enable(). + * + * Returns 0 upon no error; -error upon error. + */ +static int _regulator_handle_consumer_disable(struct regulator *regulator) +{ + struct regulator_dev *rdev = regulator->rdev; + + lockdep_assert_held_once(&rdev->mutex.base); + + if (!regulator->enable_count) { + rdev_err(rdev, "Underflow of regulator enable count\n"); + return -EINVAL; + } + + regulator->enable_count--; + if (regulator->uA_load && regulator->enable_count == 0) + return drms_uA_update(rdev); + + return 0; +} + /* locks held by regulator_enable() */ -static int _regulator_enable(struct regulator_dev *rdev) +static int _regulator_enable(struct regulator *regulator) { + struct regulator_dev *rdev = regulator->rdev; int ret; - lockdep_assert_held_once(&rdev->mutex); + lockdep_assert_held_once(&rdev->mutex.base); - /* check voltage and requested load before enabling */ - if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS)) - drms_uA_update(rdev); + if (rdev->use_count == 0 && rdev->supply) { + ret = _regulator_enable(rdev->supply); + if (ret < 0) + return ret; + } + + /* balance only if there are regulators coupled */ + if (rdev->coupling_desc.n_coupled > 1) { + ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON); + if (ret < 0) + goto err_disable_supply; + } + + ret = _regulator_handle_consumer_enable(regulator); + if (ret < 0) + goto err_disable_supply; if (rdev->use_count == 0) { /* The regulator may on if it's not switchable or left on */ ret = _regulator_is_enabled(rdev); if (ret == -EINVAL || ret == 0) { if (!regulator_ops_is_valid(rdev, - REGULATOR_CHANGE_STATUS)) - return -EPERM; + REGULATOR_CHANGE_STATUS)) { + ret = -EPERM; + goto err_consumer_disable; + } ret = _regulator_do_enable(rdev); if (ret < 0) - return ret; + goto err_consumer_disable; _notifier_call_chain(rdev, REGULATOR_EVENT_ENABLE, NULL); } else if (ret < 0) { rdev_err(rdev, "is_enabled() failed: %d\n", ret); - return ret; + goto err_consumer_disable; } /* Fallthrough on positive return values - already enabled */ } @@ -2260,6 +2520,15 @@ static int _regulator_enable(struct regulator_dev *rdev) rdev->use_count++; return 0; + +err_consumer_disable: + _regulator_handle_consumer_disable(regulator); + +err_disable_supply: + if (rdev->use_count == 0 && rdev->supply) + _regulator_disable(rdev->supply); + + return ret; } /** @@ -2276,23 +2545,12 @@ static int _regulator_enable(struct regulator_dev *rdev) int regulator_enable(struct regulator *regulator) { struct regulator_dev *rdev = regulator->rdev; - int ret = 0; - - if (regulator->always_on) - return 0; - - if (rdev->supply) { - ret = regulator_enable(rdev->supply); - if (ret != 0) - return ret; - } - - mutex_lock(&rdev->mutex); - ret = _regulator_enable(rdev); - mutex_unlock(&rdev->mutex); + struct ww_acquire_ctx ww_ctx; + int ret; - if (ret != 0 && rdev->supply) - regulator_disable(rdev->supply); + regulator_lock_dependent(rdev, &ww_ctx); + ret = _regulator_enable(regulator); + regulator_unlock_dependent(rdev, &ww_ctx); return ret; } @@ -2330,11 +2588,12 @@ static int _regulator_do_disable(struct regulator_dev *rdev) } /* locks held by regulator_disable() */ -static int _regulator_disable(struct regulator_dev *rdev) +static int _regulator_disable(struct regulator *regulator) { + struct regulator_dev *rdev = regulator->rdev; int ret = 0; - lockdep_assert_held_once(&rdev->mutex); + lockdep_assert_held_once(&rdev->mutex.base); if (WARN(rdev->use_count <= 0, "unbalanced disables for %s\n", rdev_get_name(rdev))) @@ -2366,12 +2625,18 @@ static int _regulator_disable(struct regulator_dev *rdev) rdev->use_count = 0; } else if (rdev->use_count > 1) { - if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS)) - drms_uA_update(rdev); - rdev->use_count--; } + if (ret == 0) + ret = _regulator_handle_consumer_disable(regulator); + + if (ret == 0 && rdev->coupling_desc.n_coupled > 1) + ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON); + + if (ret == 0 && rdev->use_count == 0 && rdev->supply) + ret = _regulator_disable(rdev->supply); + return ret; } @@ -2390,17 +2655,12 @@ static int _regulator_disable(struct regulator_dev *rdev) int regulator_disable(struct regulator *regulator) { struct regulator_dev *rdev = regulator->rdev; - int ret = 0; - - if (regulator->always_on) - return 0; - - mutex_lock(&rdev->mutex); - ret = _regulator_disable(rdev); - mutex_unlock(&rdev->mutex); + struct ww_acquire_ctx ww_ctx; + int ret; - if (ret == 0 && rdev->supply) - regulator_disable(rdev->supply); + regulator_lock_dependent(rdev, &ww_ctx); + ret = _regulator_disable(regulator); + regulator_unlock_dependent(rdev, &ww_ctx); return ret; } @@ -2411,7 +2671,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev) { int ret = 0; - lockdep_assert_held_once(&rdev->mutex); + lockdep_assert_held_once(&rdev->mutex.base); ret = _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | REGULATOR_EVENT_PRE_DISABLE, NULL); @@ -2444,16 +2704,25 @@ static int _regulator_force_disable(struct regulator_dev *rdev) int regulator_force_disable(struct regulator *regulator) { struct regulator_dev *rdev = regulator->rdev; + struct ww_acquire_ctx ww_ctx; int ret; - mutex_lock(&rdev->mutex); - regulator->uA_load = 0; + regulator_lock_dependent(rdev, &ww_ctx); + ret = _regulator_force_disable(regulator->rdev); - mutex_unlock(&rdev->mutex); - if (rdev->supply) - while (rdev->open_count--) - regulator_disable(rdev->supply); + if (rdev->coupling_desc.n_coupled > 1) + regulator_balance_voltage(rdev, PM_SUSPEND_ON); + + if (regulator->uA_load) { + regulator->uA_load = 0; + ret = drms_uA_update(rdev); + } + + if (rdev->use_count != 0 && rdev->supply) + _regulator_disable(rdev->supply); + + regulator_unlock_dependent(rdev, &ww_ctx); return ret; } @@ -2463,14 +2732,12 @@ static void regulator_disable_work(struct work_struct *work) { struct regulator_dev *rdev = container_of(work, struct regulator_dev, disable_work.work); + struct ww_acquire_ctx ww_ctx; int count, i, ret; + struct regulator *regulator; + int total_count = 0; - regulator_lock(rdev); - - BUG_ON(!rdev->deferred_disables); - - count = rdev->deferred_disables; - rdev->deferred_disables = 0; + regulator_lock_dependent(rdev, &ww_ctx); /* * Workqueue functions queue the new work instance while the previous @@ -2480,29 +2747,33 @@ static void regulator_disable_work(struct work_struct *work) */ cancel_delayed_work(&rdev->disable_work); - for (i = 0; i < count; i++) { - ret = _regulator_disable(rdev); - if (ret != 0) - rdev_err(rdev, "Deferred disable failed: %d\n", ret); - } + list_for_each_entry(regulator, &rdev->consumer_list, list) { + count = regulator->deferred_disables; - regulator_unlock(rdev); + if (!count) + continue; + + total_count += count; + regulator->deferred_disables = 0; - if (rdev->supply) { for (i = 0; i < count; i++) { - ret = regulator_disable(rdev->supply); - if (ret != 0) { - rdev_err(rdev, - "Supply disable failed: %d\n", ret); - } + ret = _regulator_disable(regulator); + if (ret != 0) + rdev_err(rdev, "Deferred disable failed: %d\n", ret); } } + WARN_ON(!total_count); + + if (rdev->coupling_desc.n_coupled > 1) + regulator_balance_voltage(rdev, PM_SUSPEND_ON); + + regulator_unlock_dependent(rdev, &ww_ctx); } /** * regulator_disable_deferred - disable regulator output with delay * @regulator: regulator source - * @ms: miliseconds until the regulator is disabled + * @ms: milliseconds until the regulator is disabled * * Execute regulator_disable() on the regulator after a delay. This * is intended for use with devices that require some time to quiesce. @@ -2515,14 +2786,11 @@ int regulator_disable_deferred(struct regulator *regulator, int ms) { struct regulator_dev *rdev = regulator->rdev; - if (regulator->always_on) - return 0; - if (!ms) return regulator_disable(regulator); regulator_lock(rdev); - rdev->deferred_disables++; + regulator->deferred_disables++; mod_delayed_work(system_power_efficient_wq, &rdev->disable_work, msecs_to_jiffies(ms)); regulator_unlock(rdev); @@ -2597,9 +2865,9 @@ int regulator_is_enabled(struct regulator *regulator) if (regulator->always_on) return 1; - mutex_lock(®ulator->rdev->mutex); + regulator_lock(regulator->rdev); ret = _regulator_is_enabled(regulator->rdev); - mutex_unlock(®ulator->rdev->mutex); + regulator_unlock(regulator->rdev); return ret; } @@ -3013,8 +3281,6 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, int ret = 0; int old_min_uV, old_max_uV; int current_uV; - int best_supply_uV = 0; - int supply_change_uV = 0; /* If we're setting the same range as last time the change * should be a noop (some cpufreq implementations use the same @@ -3054,10 +3320,27 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, voltage->min_uV = min_uV; voltage->max_uV = max_uV; - ret = regulator_check_consumers(rdev, &min_uV, &max_uV, state); + /* for not coupled regulators this will just set the voltage */ + ret = regulator_balance_voltage(rdev, state); if (ret < 0) goto out2; +out: + return 0; +out2: + voltage->min_uV = old_min_uV; + voltage->max_uV = old_max_uV; + + return ret; +} + +static 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; + int ret; + if (rdev->supply && regulator_ops_is_valid(rdev->supply->rdev, REGULATOR_CHANGE_VOLTAGE) && @@ -3069,13 +3352,13 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, selector = regulator_map_voltage(rdev, min_uV, max_uV); if (selector < 0) { ret = selector; - goto out2; + goto out; } best_supply_uV = _regulator_list_voltage(rdev, selector, 0); if (best_supply_uV < 0) { ret = best_supply_uV; - goto out2; + goto out; } best_supply_uV += rdev->desc->min_dropout_uV; @@ -3083,7 +3366,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, current_supply_uV = _regulator_get_voltage(rdev->supply->rdev); if (current_supply_uV < 0) { ret = current_supply_uV; - goto out2; + goto out; } supply_change_uV = best_supply_uV - current_supply_uV; @@ -3095,7 +3378,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, if (ret) { dev_err(&rdev->dev, "Failed to increase supply voltage: %d\n", ret); - goto out2; + goto out; } } @@ -3105,7 +3388,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, ret = _regulator_do_set_suspend_voltage(rdev, min_uV, max_uV, state); if (ret < 0) - goto out2; + goto out; if (supply_change_uV < 0) { ret = regulator_set_voltage_unlocked(rdev->supply, @@ -3119,10 +3402,273 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, out: return ret; -out2: - voltage->min_uV = old_min_uV; - voltage->max_uV = old_max_uV; +} + +static int regulator_limit_voltage_step(struct regulator_dev *rdev, + int *current_uV, int *min_uV) +{ + struct regulation_constraints *constraints = rdev->constraints; + + /* Limit voltage change only if necessary */ + if (!constraints->max_uV_step || !_regulator_is_enabled(rdev)) + return 1; + + if (*current_uV < 0) { + *current_uV = _regulator_get_voltage(rdev); + + if (*current_uV < 0) + return *current_uV; + } + + if (abs(*current_uV - *min_uV) <= constraints->max_uV_step) + return 1; + + /* Clamp target voltage within the given step */ + if (*current_uV < *min_uV) + *min_uV = min(*current_uV + constraints->max_uV_step, + *min_uV); + else + *min_uV = max(*current_uV - constraints->max_uV_step, + *min_uV); + + return 0; +} + +static int regulator_get_optimal_voltage(struct regulator_dev *rdev, + int *current_uV, + int *min_uV, int *max_uV, + suspend_state_t state, + int n_coupled) +{ + 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; + bool done; + + *current_uV = -1; + + /* + * If there are no coupled regulators, simply set the voltage + * demanded by consumers. + */ + if (n_coupled == 1) { + /* + * If consumers don't provide any demands, set voltage + * to min_uV + */ + desired_min_uV = constraints->min_uV; + desired_max_uV = constraints->max_uV; + + ret = regulator_check_consumers(rdev, + &desired_min_uV, + &desired_max_uV, state); + if (ret < 0) + return ret; + + possible_uV = desired_min_uV; + done = true; + + goto finish; + } + + /* Find highest min desired voltage */ + for (i = 0; i < n_coupled; i++) { + int tmp_min = 0; + int tmp_max = INT_MAX; + + lockdep_assert_held_once(&c_rdevs[i]->mutex.base); + + ret = regulator_check_consumers(c_rdevs[i], + &tmp_min, + &tmp_max, state); + if (ret < 0) + return ret; + + ret = regulator_check_voltage(c_rdevs[i], &tmp_min, &tmp_max); + if (ret < 0) + return ret; + + highest_min_uV = max(highest_min_uV, tmp_min); + + if (i == 0) { + desired_min_uV = tmp_min; + desired_max_uV = tmp_max; + } + } + + /* + * Let target_uV be equal to the desired one if possible. + * If not, set it to minimum voltage, allowed by other coupled + * regulators. + */ + target_uV = max(desired_min_uV, highest_min_uV - max_spread); + + /* + * Find min and max voltages, which currently aren't violating + * max_spread. + */ + for (i = 1; i < n_coupled; i++) { + int tmp_act; + + if (!_regulator_is_enabled(c_rdevs[i])) + continue; + + tmp_act = _regulator_get_voltage(c_rdevs[i]); + if (tmp_act < 0) + return tmp_act; + + min_current_uV = min(tmp_act, min_current_uV); + max_current_uV = max(tmp_act, max_current_uV); + } + + /* There aren't any other regulators enabled */ + if (max_current_uV == 0) { + possible_uV = target_uV; + } else { + /* + * Correct target voltage, so as it currently isn't + * violating max_spread + */ + possible_uV = max(target_uV, max_current_uV - max_spread); + possible_uV = min(possible_uV, min_current_uV + max_spread); + } + + if (possible_uV > desired_max_uV) + return -EINVAL; + + done = (possible_uV == target_uV); + desired_min_uV = possible_uV; +finish: + /* Apply max_uV_step constraint if necessary */ + if (state == PM_SUSPEND_ON) { + ret = regulator_limit_voltage_step(rdev, current_uV, + &desired_min_uV); + if (ret < 0) + return ret; + + if (ret == 0) + done = false; + } + + /* Set current_uV if wasn't done earlier in the code and if necessary */ + if (n_coupled > 1 && *current_uV == -1) { + + if (_regulator_is_enabled(rdev)) { + ret = _regulator_get_voltage(rdev); + if (ret < 0) + return ret; + + *current_uV = ret; + } else { + *current_uV = desired_min_uV; + } + } + + *min_uV = desired_min_uV; + *max_uV = desired_max_uV; + + return done; +} + +static int regulator_balance_voltage(struct regulator_dev *rdev, + suspend_state_t state) +{ + struct regulator_dev **c_rdevs; + struct regulator_dev *best_rdev; + struct coupling_desc *c_desc = &rdev->coupling_desc; + 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; + + c_rdevs = c_desc->coupled_rdevs; + n_coupled = c_desc->n_coupled; + + /* + * If system is in a state other than PM_SUSPEND_ON, don't check + * other coupled regulators. + */ + if (state != PM_SUSPEND_ON) + n_coupled = 1; + + if (c_desc->n_resolved < n_coupled) { + rdev_err(rdev, "Not all coupled regulators registered\n"); + return -EPERM; + } + + for (i = 0; i < n_coupled; i++) + c_rdev_done[i] = false; + + /* + * Find the best possible voltage change on each loop. Leave the loop + * if there isn't any possible change. + */ + do { + best_c_rdev_done = false; + best_delta = 0; + best_min_uV = 0; + best_max_uV = 0; + best_c_rdev = 0; + best_rdev = NULL; + + /* + * Find highest difference between optimal voltage + * and current voltage. + */ + for (i = 0; i < n_coupled; i++) { + /* + * optimal_uV is the best voltage that can be set for + * i-th regulator at the moment without violating + * max_spread constraint in order to balance + * the coupled voltages. + */ + int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0; + + if (c_rdev_done[i]) + continue; + + ret = regulator_get_optimal_voltage(c_rdevs[i], + ¤t_uV, + &optimal_uV, + &optimal_max_uV, + state, n_coupled); + if (ret < 0) + goto out; + + delta = abs(optimal_uV - current_uV); + + if (delta && best_delta <= delta) { + best_c_rdev_done = ret; + best_delta = delta; + best_rdev = c_rdevs[i]; + best_min_uV = optimal_uV; + best_max_uV = optimal_max_uV; + best_c_rdev = i; + } + } + + /* Nothing to change, return successfully */ + if (!best_rdev) { + ret = 0; + goto out; + } + + ret = regulator_set_voltage_rdev(best_rdev, best_min_uV, + best_max_uV, state); + + if (ret < 0) + goto out; + + c_rdev_done[best_c_rdev] = best_c_rdev_done; + + } while (n_coupled > 1); + +out: return ret; } @@ -3146,14 +3692,15 @@ out2: */ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { - int ret = 0; + struct ww_acquire_ctx ww_ctx; + int ret; - regulator_lock_supply(regulator->rdev); + regulator_lock_dependent(regulator->rdev, &ww_ctx); ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV, PM_SUSPEND_ON); - regulator_unlock_supply(regulator->rdev); + regulator_unlock_dependent(regulator->rdev, &ww_ctx); return ret; } @@ -3225,18 +3772,19 @@ static int _regulator_set_suspend_voltage(struct regulator *regulator, int regulator_set_suspend_voltage(struct regulator *regulator, int min_uV, int max_uV, suspend_state_t state) { - int ret = 0; + struct ww_acquire_ctx ww_ctx; + int ret; /* PM_SUSPEND_ON is handled by regulator_set_voltage() */ if (regulator_check_states(state) || state == PM_SUSPEND_ON) return -EINVAL; - regulator_lock_supply(regulator->rdev); + regulator_lock_dependent(regulator->rdev, &ww_ctx); ret = _regulator_set_suspend_voltage(regulator, min_uV, max_uV, state); - regulator_unlock_supply(regulator->rdev); + regulator_unlock_dependent(regulator->rdev, &ww_ctx); return ret; } @@ -3426,13 +3974,12 @@ static int _regulator_get_voltage(struct regulator_dev *rdev) */ int regulator_get_voltage(struct regulator *regulator) { + struct ww_acquire_ctx ww_ctx; int ret; - regulator_lock_supply(regulator->rdev); - + regulator_lock_dependent(regulator->rdev, &ww_ctx); ret = _regulator_get_voltage(regulator->rdev); - - regulator_unlock_supply(regulator->rdev); + regulator_unlock_dependent(regulator->rdev, &ww_ctx); return ret; } @@ -3650,16 +4197,30 @@ EXPORT_SYMBOL_GPL(regulator_get_error_flags); * DRMS will sum the total requested load on the regulator and change * to the most efficient operating mode if platform constraints allow. * + * NOTE: when a regulator consumer requests to have a regulator + * disabled then any load that consumer requested no longer counts + * toward the total requested load. If the regulator is re-enabled + * then the previously requested load will start counting again. + * + * If a regulator is an always-on regulator then an individual consumer's + * load will still be removed if that consumer is fully disabled. + * * On error a negative errno is returned. */ int regulator_set_load(struct regulator *regulator, int uA_load) { struct regulator_dev *rdev = regulator->rdev; - int ret; + int old_uA_load; + int ret = 0; regulator_lock(rdev); + old_uA_load = regulator->uA_load; regulator->uA_load = uA_load; - ret = drms_uA_update(rdev); + if (regulator->enable_count && old_uA_load != uA_load) { + ret = drms_uA_update(rdev); + if (ret < 0) + regulator->uA_load = old_uA_load; + } regulator_unlock(rdev); return ret; @@ -3830,11 +4391,8 @@ int regulator_bulk_enable(int num_consumers, int ret = 0; for (i = 0; i < num_consumers; i++) { - if (consumers[i].consumer->always_on) - consumers[i].ret = 0; - else - async_schedule_domain(regulator_bulk_enable_async, - &consumers[i], &async_domain); + async_schedule_domain(regulator_bulk_enable_async, + &consumers[i], &async_domain); } async_synchronize_full_domain(&async_domain); @@ -3968,7 +4526,7 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free); int regulator_notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data) { - lockdep_assert_held_once(&rdev->mutex); + lockdep_assert_held_once(&rdev->mutex.base); _notifier_call_chain(rdev, event, data); return NOTIFY_DONE; @@ -4070,10 +4628,6 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj, if (attr == &dev_attr_bypass.attr) return ops->get_bypass ? mode : 0; - /* some attributes are type-specific */ - if (attr == &dev_attr_requested_microamps.attr) - return rdev->desc->type == REGULATOR_CURRENT ? mode : 0; - /* constraints need specific supporting methods */ if (attr == &dev_attr_min_microvolts.attr || attr == &dev_attr_max_microvolts.attr) @@ -4157,7 +4711,7 @@ static int regulator_register_resolve_supply(struct device *dev, void *data) return 0; } -static int regulator_fill_coupling_array(struct regulator_dev *rdev) +static void regulator_resolve_coupling(struct regulator_dev *rdev) { struct coupling_desc *c_desc = &rdev->coupling_desc; int n_coupled = c_desc->n_coupled; @@ -4171,33 +4725,58 @@ static int regulator_fill_coupling_array(struct regulator_dev *rdev) c_rdev = of_parse_coupled_regulator(rdev, i - 1); - if (c_rdev) { - c_desc->coupled_rdevs[i] = c_rdev; - c_desc->n_resolved++; - } - } + if (!c_rdev) + continue; - if (rdev->coupling_desc.n_resolved < n_coupled) - return -1; - else - return 0; + regulator_lock(c_rdev); + + c_desc->coupled_rdevs[i] = c_rdev; + c_desc->n_resolved++; + + regulator_unlock(c_rdev); + + regulator_resolve_coupling(c_rdev); + } } -static int regulator_register_fill_coupling_array(struct device *dev, - void *data) +static void regulator_remove_coupling(struct regulator_dev *rdev) { - struct regulator_dev *rdev = dev_to_rdev(dev); + struct coupling_desc *__c_desc, *c_desc = &rdev->coupling_desc; + struct regulator_dev *__c_rdev, *c_rdev; + unsigned int __n_coupled, n_coupled; + int i, k; - if (!IS_ENABLED(CONFIG_OF)) - return 0; + n_coupled = c_desc->n_coupled; - if (regulator_fill_coupling_array(rdev)) - rdev_dbg(rdev, "unable to resolve coupling\n"); + for (i = 1; i < n_coupled; i++) { + c_rdev = c_desc->coupled_rdevs[i]; - return 0; + if (!c_rdev) + continue; + + regulator_lock(c_rdev); + + __c_desc = &c_rdev->coupling_desc; + __n_coupled = __c_desc->n_coupled; + + for (k = 1; k < __n_coupled; k++) { + __c_rdev = __c_desc->coupled_rdevs[k]; + + if (__c_rdev == rdev) { + __c_desc->coupled_rdevs[k] = NULL; + __c_desc->n_resolved--; + break; + } + } + + regulator_unlock(c_rdev); + + c_desc->coupled_rdevs[i] = NULL; + c_desc->n_resolved--; + } } -static int regulator_resolve_coupling(struct regulator_dev *rdev) +static int regulator_init_coupling(struct regulator_dev *rdev) { int n_phandles; @@ -4237,13 +4816,6 @@ static int regulator_resolve_coupling(struct regulator_dev *rdev) if (!of_check_coupling_data(rdev)) return -EPERM; - /* - * After everything has been checked, try to fill rdevs array - * with pointers to regulators parsed from device tree. If some - * regulators are not registered yet, retry in late init call - */ - regulator_fill_coupling_array(rdev); - return 0; } @@ -4265,21 +4837,33 @@ regulator_register(const struct regulator_desc *regulator_desc, struct regulator_config *config = NULL; static atomic_t regulator_no = ATOMIC_INIT(-1); struct regulator_dev *rdev; + bool dangling_cfg_gpiod = false; + bool dangling_of_gpiod = false; struct device *dev; int ret, i; - if (regulator_desc == NULL || cfg == NULL) + if (cfg == NULL) return ERR_PTR(-EINVAL); + if (cfg->ena_gpiod) + dangling_cfg_gpiod = true; + if (regulator_desc == NULL) { + ret = -EINVAL; + goto rinse; + } dev = cfg->dev; WARN_ON(!dev); - if (regulator_desc->name == NULL || regulator_desc->ops == NULL) - return ERR_PTR(-EINVAL); + if (regulator_desc->name == NULL || regulator_desc->ops == NULL) { + ret = -EINVAL; + goto rinse; + } if (regulator_desc->type != REGULATOR_VOLTAGE && - regulator_desc->type != REGULATOR_CURRENT) - return ERR_PTR(-EINVAL); + regulator_desc->type != REGULATOR_CURRENT) { + ret = -EINVAL; + goto rinse; + } /* Only one of each should be implemented */ WARN_ON(regulator_desc->ops->get_voltage && @@ -4290,16 +4874,20 @@ regulator_register(const struct regulator_desc *regulator_desc, /* If we're using selectors we must implement list_voltage. */ if (regulator_desc->ops->get_voltage_sel && !regulator_desc->ops->list_voltage) { - return ERR_PTR(-EINVAL); + ret = -EINVAL; + goto rinse; } if (regulator_desc->ops->set_voltage_sel && !regulator_desc->ops->list_voltage) { - return ERR_PTR(-EINVAL); + ret = -EINVAL; + goto rinse; } rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); - if (rdev == NULL) - return ERR_PTR(-ENOMEM); + if (rdev == NULL) { + ret = -ENOMEM; + goto rinse; + } /* * Duplicate the config so the driver could override it after @@ -4308,17 +4896,28 @@ regulator_register(const struct regulator_desc *regulator_desc, config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL); if (config == NULL) { kfree(rdev); - return ERR_PTR(-ENOMEM); + ret = -ENOMEM; + goto rinse; } init_data = regulator_of_get_init_data(dev, regulator_desc, config, &rdev->dev.of_node); + /* + * We need to keep track of any GPIO descriptor coming from the + * device tree until we have handled it over to the core. If the + * config that was passed in to this function DOES NOT contain + * a descriptor, and the config after this call DOES contain + * a descriptor, we definitely got one from parsing the device + * tree. + */ + if (!cfg->ena_gpiod && config->ena_gpiod) + dangling_of_gpiod = true; if (!init_data) { init_data = config->init_data; rdev->dev.of_node = of_node_get(config->of_node); } - mutex_init(&rdev->mutex); + ww_mutex_init(&rdev->mutex, ®ulator_ww_class); rdev->reg_data = config->driver_data; rdev->owner = regulator_desc->owner; rdev->desc = regulator_desc; @@ -4340,17 +4939,18 @@ regulator_register(const struct regulator_desc *regulator_desc, goto clean; } - if (config->ena_gpiod || - ((config->ena_gpio || config->ena_gpio_initialized) && - gpio_is_valid(config->ena_gpio))) { + if (config->ena_gpiod) { mutex_lock(®ulator_list_mutex); ret = regulator_ena_gpio_request(rdev, config); mutex_unlock(®ulator_list_mutex); if (ret != 0) { - rdev_err(rdev, "Failed to request enable GPIO%d: %d\n", - config->ena_gpio, ret); + rdev_err(rdev, "Failed to request enable GPIO: %d\n", + ret); goto clean; } + /* The regulator core took over the GPIO descriptor */ + dangling_cfg_gpiod = false; + dangling_of_gpiod = false; } /* register with sysfs */ @@ -4380,11 +4980,8 @@ regulator_register(const struct regulator_desc *regulator_desc, if (ret < 0) goto wash; - mutex_lock(®ulator_list_mutex); - ret = regulator_resolve_coupling(rdev); - mutex_unlock(®ulator_list_mutex); - - if (ret != 0) + ret = regulator_init_coupling(rdev); + if (ret < 0) goto wash; /* add consumers devices */ @@ -4418,6 +5015,11 @@ regulator_register(const struct regulator_desc *regulator_desc, rdev_init_debugfs(rdev); + /* try to resolve regulators coupling since a new one was registered */ + mutex_lock(®ulator_list_mutex); + regulator_resolve_coupling(rdev); + mutex_unlock(®ulator_list_mutex); + /* try to resolve regulators supply since a new one was registered */ class_for_each_device(®ulator_class, NULL, NULL, regulator_register_resolve_supply); @@ -4434,8 +5036,13 @@ wash: regulator_ena_gpio_free(rdev); mutex_unlock(®ulator_list_mutex); clean: + if (dangling_of_gpiod) + gpiod_put(config->ena_gpiod); kfree(rdev); kfree(config); +rinse: + if (dangling_cfg_gpiod) + gpiod_put(cfg->ena_gpiod); return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(regulator_register); @@ -4456,15 +5063,19 @@ void regulator_unregister(struct regulator_dev *rdev) regulator_disable(rdev->supply); regulator_put(rdev->supply); } + mutex_lock(®ulator_list_mutex); + debugfs_remove_recursive(rdev->debugfs); flush_work(&rdev->disable_work.work); WARN_ON(rdev->open_count); + regulator_remove_coupling(rdev); unset_regulator_supplies(rdev); list_del(&rdev->list); regulator_ena_gpio_free(rdev); - mutex_unlock(®ulator_list_mutex); device_unregister(&rdev->dev); + + mutex_unlock(®ulator_list_mutex); } EXPORT_SYMBOL_GPL(regulator_unregister); @@ -4602,6 +5213,12 @@ struct device *rdev_get_dev(struct regulator_dev *rdev) } EXPORT_SYMBOL_GPL(rdev_get_dev); +struct regmap *rdev_get_regmap(struct regulator_dev *rdev) +{ + return rdev->regmap; +} +EXPORT_SYMBOL_GPL(rdev_get_regmap); + void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data) { return reg_init_data->driver_data; @@ -4621,23 +5238,8 @@ static int supply_map_show(struct seq_file *sf, void *data) return 0; } +DEFINE_SHOW_ATTRIBUTE(supply_map); -static int supply_map_open(struct inode *inode, struct file *file) -{ - return single_open(file, supply_map_show, inode->i_private); -} -#endif - -static const struct file_operations supply_map_fops = { -#ifdef CONFIG_DEBUG_FS - .open = supply_map_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -#endif -}; - -#ifdef CONFIG_DEBUG_FS struct summary_data { struct seq_file *s; struct regulator_dev *parent; @@ -4672,8 +5274,6 @@ static void regulator_summary_show_subtree(struct seq_file *s, if (!rdev) return; - regulator_lock_nested(rdev, level); - opmode = _regulator_get_mode_unlocked(rdev); seq_printf(s, "%*s%-*s %3d %4d %6d %7s ", level * 3 + 1, "", @@ -4712,8 +5312,11 @@ static void regulator_summary_show_subtree(struct seq_file *s, switch (rdev->desc->type) { case REGULATOR_VOLTAGE: - seq_printf(s, "%37dmA %5dmV %5dmV", + seq_printf(s, "%3d %33dmA%c%5dmV %5dmV", + consumer->enable_count, consumer->uA_load / 1000, + consumer->uA_load && !consumer->enable_count ? + '*' : ' ', consumer->voltage[PM_SUSPEND_ON].min_uV / 1000, consumer->voltage[PM_SUSPEND_ON].max_uV / 1000); break; @@ -4730,8 +5333,105 @@ static void regulator_summary_show_subtree(struct seq_file *s, class_for_each_device(®ulator_class, NULL, &summary_data, regulator_summary_show_children); +} + +struct summary_lock_data { + struct ww_acquire_ctx *ww_ctx; + struct regulator_dev **new_contended_rdev; + struct regulator_dev **old_contended_rdev; +}; + +static int regulator_summary_lock_one(struct device *dev, void *data) +{ + struct regulator_dev *rdev = dev_to_rdev(dev); + struct summary_lock_data *lock_data = data; + int ret = 0; + + if (rdev != *lock_data->old_contended_rdev) { + ret = regulator_lock_nested(rdev, lock_data->ww_ctx); + + if (ret == -EDEADLK) + *lock_data->new_contended_rdev = rdev; + else + WARN_ON_ONCE(ret); + } else { + *lock_data->old_contended_rdev = NULL; + } + + return ret; +} + +static int regulator_summary_unlock_one(struct device *dev, void *data) +{ + struct regulator_dev *rdev = dev_to_rdev(dev); + struct summary_lock_data *lock_data = data; + + if (lock_data) { + if (rdev == *lock_data->new_contended_rdev) + return -EDEADLK; + } regulator_unlock(rdev); + + return 0; +} + +static int regulator_summary_lock_all(struct ww_acquire_ctx *ww_ctx, + struct regulator_dev **new_contended_rdev, + struct regulator_dev **old_contended_rdev) +{ + struct summary_lock_data lock_data; + int ret; + + lock_data.ww_ctx = ww_ctx; + lock_data.new_contended_rdev = new_contended_rdev; + lock_data.old_contended_rdev = old_contended_rdev; + + ret = class_for_each_device(®ulator_class, NULL, &lock_data, + regulator_summary_lock_one); + if (ret) + class_for_each_device(®ulator_class, NULL, &lock_data, + regulator_summary_unlock_one); + + return ret; +} + +static void regulator_summary_lock(struct ww_acquire_ctx *ww_ctx) +{ + struct regulator_dev *new_contended_rdev = NULL; + struct regulator_dev *old_contended_rdev = NULL; + int err; + + mutex_lock(®ulator_list_mutex); + + ww_acquire_init(ww_ctx, ®ulator_ww_class); + + do { + if (new_contended_rdev) { + ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx); + old_contended_rdev = new_contended_rdev; + old_contended_rdev->ref_cnt++; + } + + err = regulator_summary_lock_all(ww_ctx, + &new_contended_rdev, + &old_contended_rdev); + + if (old_contended_rdev) + regulator_unlock(old_contended_rdev); + + } while (err == -EDEADLK); + + ww_acquire_done(ww_ctx); +} + +static void regulator_summary_unlock(struct ww_acquire_ctx *ww_ctx) +{ + class_for_each_device(®ulator_class, NULL, NULL, + regulator_summary_unlock_one); + ww_acquire_fini(ww_ctx); + + mutex_unlock(®ulator_list_mutex); } static int regulator_summary_show_roots(struct device *dev, void *data) @@ -4747,29 +5447,22 @@ static int regulator_summary_show_roots(struct device *dev, void *data) static int regulator_summary_show(struct seq_file *s, void *data) { + struct ww_acquire_ctx ww_ctx; + seq_puts(s, " regulator use open bypass opmode voltage current min max\n"); seq_puts(s, "---------------------------------------------------------------------------------------\n"); + regulator_summary_lock(&ww_ctx); + class_for_each_device(®ulator_class, NULL, s, regulator_summary_show_roots); - return 0; -} + regulator_summary_unlock(&ww_ctx); -static int regulator_summary_open(struct inode *inode, struct file *file) -{ - return single_open(file, regulator_summary_show, inode->i_private); + return 0; } -#endif - -static const struct file_operations regulator_summary_fops = { -#ifdef CONFIG_DEBUG_FS - .open = regulator_summary_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -#endif -}; +DEFINE_SHOW_ATTRIBUTE(regulator_summary); +#endif /* CONFIG_DEBUG_FS */ static int __init regulator_init(void) { @@ -4781,12 +5474,13 @@ static int __init regulator_init(void) if (!debugfs_root) pr_warn("regulator: Failed to create debugfs directory\n"); +#ifdef CONFIG_DEBUG_FS debugfs_create_file("supply_map", 0444, debugfs_root, NULL, &supply_map_fops); debugfs_create_file("regulator_summary", 0444, debugfs_root, NULL, ®ulator_summary_fops); - +#endif regulator_dummy_init(); return ret; @@ -4873,9 +5567,6 @@ static int __init regulator_init_complete(void) class_for_each_device(®ulator_class, NULL, NULL, regulator_late_cleanup); - class_for_each_device(®ulator_class, NULL, NULL, - regulator_register_fill_coupling_array); - return 0; } late_initcall_sync(regulator_init_complete); diff --git a/drivers/regulator/cpcap-regulator.c b/drivers/regulator/cpcap-regulator.c index 2131457937b7..e7dab5c4d1d1 100644 --- a/drivers/regulator/cpcap-regulator.c +++ b/drivers/regulator/cpcap-regulator.c @@ -100,12 +100,11 @@ struct cpcap_regulator { struct regulator_desc rdesc; const u16 assign_reg; const u16 assign_mask; - const u16 vsel_shift; }; #define CPCAP_REG(_ID, reg, assignment_reg, assignment_mask, val_tbl, \ - mode_mask, volt_mask, volt_shft, \ - mode_val, off_val, volt_trans_time) { \ + mode_mask, volt_mask, mode_val, off_val, \ + volt_trans_time) { \ .rdesc = { \ .name = #_ID, \ .of_match = of_match_ptr(#_ID), \ @@ -127,7 +126,6 @@ struct cpcap_regulator { }, \ .assign_reg = (assignment_reg), \ .assign_mask = (assignment_mask), \ - .vsel_shift = (volt_shft), \ } struct cpcap_ddata { @@ -336,155 +334,155 @@ static const unsigned int vaudio_val_tbl[] = { 0, 2775000, }; * SW1 to SW4 and SW6 seems to be unused for mapphone. Note that VSIM and * VSIMCARD have a shared resource assignment bit. */ -static struct cpcap_regulator omap4_regulators[] = { +static const struct cpcap_regulator omap4_regulators[] = { CPCAP_REG(SW1, CPCAP_REG_S1C1, CPCAP_REG_ASSIGN2, CPCAP_BIT_SW1_SEL, unknown_val_tbl, - 0, 0, 0, 0, 0, 0), + 0, 0, 0, 0, 0), CPCAP_REG(SW2, CPCAP_REG_S2C1, CPCAP_REG_ASSIGN2, CPCAP_BIT_SW2_SEL, unknown_val_tbl, - 0, 0, 0, 0, 0, 0), + 0, 0, 0, 0, 0), CPCAP_REG(SW3, CPCAP_REG_S3C, CPCAP_REG_ASSIGN2, CPCAP_BIT_SW3_SEL, unknown_val_tbl, - 0, 0, 0, 0, 0, 0), + 0, 0, 0, 0, 0), CPCAP_REG(SW4, CPCAP_REG_S4C1, CPCAP_REG_ASSIGN2, CPCAP_BIT_SW4_SEL, unknown_val_tbl, - 0, 0, 0, 0, 0, 0), + 0, 0, 0, 0, 0), CPCAP_REG(SW5, CPCAP_REG_S5C, CPCAP_REG_ASSIGN2, CPCAP_BIT_SW5_SEL, sw5_val_tbl, - 0x28, 0, 0, 0x20 | CPCAP_REG_OFF_MODE_SEC, 0, 0), + 0x28, 0, 0x20 | CPCAP_REG_OFF_MODE_SEC, 0, 0), CPCAP_REG(SW6, CPCAP_REG_S6C, CPCAP_REG_ASSIGN2, CPCAP_BIT_SW6_SEL, unknown_val_tbl, - 0, 0, 0, 0, 0, 0), + 0, 0, 0, 0, 0), CPCAP_REG(VCAM, CPCAP_REG_VCAMC, CPCAP_REG_ASSIGN2, CPCAP_BIT_VCAM_SEL, vcam_val_tbl, - 0x87, 0x30, 4, 0x3, 0, 420), + 0x87, 0x30, 0x3, 0, 420), CPCAP_REG(VCSI, CPCAP_REG_VCSIC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VCSI_SEL, vcsi_val_tbl, - 0x47, 0x10, 4, 0x43, 0x41, 350), + 0x47, 0x10, 0x43, 0x41, 350), CPCAP_REG(VDAC, CPCAP_REG_VDACC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VDAC_SEL, vdac_val_tbl, - 0x87, 0x30, 4, 0x3, 0, 420), + 0x87, 0x30, 0x3, 0, 420), CPCAP_REG(VDIG, CPCAP_REG_VDIGC, CPCAP_REG_ASSIGN2, CPCAP_BIT_VDIG_SEL, vdig_val_tbl, - 0x87, 0x30, 4, 0x82, 0, 420), + 0x87, 0x30, 0x82, 0, 420), CPCAP_REG(VFUSE, CPCAP_REG_VFUSEC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VFUSE_SEL, vfuse_val_tbl, - 0x80, 0xf, 0, 0x80, 0, 420), + 0x80, 0xf, 0x80, 0, 420), CPCAP_REG(VHVIO, CPCAP_REG_VHVIOC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VHVIO_SEL, vhvio_val_tbl, - 0x17, 0, 0, 0, 0x12, 0), + 0x17, 0, 0, 0x12, 0), CPCAP_REG(VSDIO, CPCAP_REG_VSDIOC, CPCAP_REG_ASSIGN2, CPCAP_BIT_VSDIO_SEL, vsdio_val_tbl, - 0x87, 0x38, 3, 0x82, 0, 420), + 0x87, 0x38, 0x82, 0, 420), CPCAP_REG(VPLL, CPCAP_REG_VPLLC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VPLL_SEL, vpll_val_tbl, - 0x43, 0x18, 3, 0x2, 0, 420), + 0x43, 0x18, 0x2, 0, 420), CPCAP_REG(VRF1, CPCAP_REG_VRF1C, CPCAP_REG_ASSIGN3, CPCAP_BIT_VRF1_SEL, vrf1_val_tbl, - 0xac, 0x2, 1, 0x4, 0, 10), + 0xac, 0x2, 0x4, 0, 10), CPCAP_REG(VRF2, CPCAP_REG_VRF2C, CPCAP_REG_ASSIGN3, CPCAP_BIT_VRF2_SEL, vrf2_val_tbl, - 0x23, 0x8, 3, 0, 0, 10), + 0x23, 0x8, 0, 0, 10), CPCAP_REG(VRFREF, CPCAP_REG_VRFREFC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VRFREF_SEL, vrfref_val_tbl, - 0x23, 0x8, 3, 0, 0, 420), + 0x23, 0x8, 0, 0, 420), CPCAP_REG(VWLAN1, CPCAP_REG_VWLAN1C, CPCAP_REG_ASSIGN3, CPCAP_BIT_VWLAN1_SEL, vwlan1_val_tbl, - 0x47, 0x10, 4, 0, 0, 420), + 0x47, 0x10, 0, 0, 420), CPCAP_REG(VWLAN2, CPCAP_REG_VWLAN2C, CPCAP_REG_ASSIGN3, CPCAP_BIT_VWLAN2_SEL, vwlan2_val_tbl, - 0x20c, 0xc0, 6, 0x20c, 0, 420), + 0x20c, 0xc0, 0x20c, 0, 420), CPCAP_REG(VSIM, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3, 0xffff, vsim_val_tbl, - 0x23, 0x8, 3, 0x3, 0, 420), + 0x23, 0x8, 0x3, 0, 420), CPCAP_REG(VSIMCARD, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3, 0xffff, vsimcard_val_tbl, - 0x1e80, 0x8, 3, 0x1e00, 0, 420), + 0x1e80, 0x8, 0x1e00, 0, 420), CPCAP_REG(VVIB, CPCAP_REG_VVIBC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VVIB_SEL, vvib_val_tbl, - 0x1, 0xc, 2, 0x1, 0, 500), + 0x1, 0xc, 0x1, 0, 500), CPCAP_REG(VUSB, CPCAP_REG_VUSBC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VUSB_SEL, vusb_val_tbl, - 0x11c, 0x40, 6, 0xc, 0, 0), + 0x11c, 0x40, 0xc, 0, 0), CPCAP_REG(VAUDIO, CPCAP_REG_VAUDIOC, CPCAP_REG_ASSIGN4, CPCAP_BIT_VAUDIO_SEL, vaudio_val_tbl, - 0x16, 0x1, 0, 0x4, 0, 0), + 0x16, 0x1, 0x4, 0, 0), { /* sentinel */ }, }; -static struct cpcap_regulator xoom_regulators[] = { +static const struct cpcap_regulator xoom_regulators[] = { CPCAP_REG(SW1, CPCAP_REG_S1C1, CPCAP_REG_ASSIGN2, CPCAP_BIT_SW1_SEL, unknown_val_tbl, - 0, 0, 0, 0, 0, 0), + 0, 0, 0, 0, 0), CPCAP_REG(SW2, CPCAP_REG_S2C1, CPCAP_REG_ASSIGN2, CPCAP_BIT_SW2_SEL, sw2_sw4_val_tbl, - 0xf00, 0x7f, 0, 0x800, 0, 120), + 0xf00, 0x7f, 0x800, 0, 120), CPCAP_REG(SW3, CPCAP_REG_S3C, CPCAP_REG_ASSIGN2, CPCAP_BIT_SW3_SEL, unknown_val_tbl, - 0, 0, 0, 0, 0, 0), + 0, 0, 0, 0, 0), CPCAP_REG(SW4, CPCAP_REG_S4C1, CPCAP_REG_ASSIGN2, CPCAP_BIT_SW4_SEL, sw2_sw4_val_tbl, - 0xf00, 0x7f, 0, 0x900, 0, 100), + 0xf00, 0x7f, 0x900, 0, 100), CPCAP_REG(SW5, CPCAP_REG_S5C, CPCAP_REG_ASSIGN2, CPCAP_BIT_SW5_SEL, sw5_val_tbl, - 0x2a, 0, 0, 0x22, 0, 0), + 0x2a, 0, 0x22, 0, 0), CPCAP_REG(SW6, CPCAP_REG_S6C, CPCAP_REG_ASSIGN2, CPCAP_BIT_SW6_SEL, unknown_val_tbl, - 0, 0, 0, 0, 0, 0), + 0, 0, 0, 0, 0), CPCAP_REG(VCAM, CPCAP_REG_VCAMC, CPCAP_REG_ASSIGN2, CPCAP_BIT_VCAM_SEL, vcam_val_tbl, - 0x87, 0x30, 4, 0x7, 0, 420), + 0x87, 0x30, 0x7, 0, 420), CPCAP_REG(VCSI, CPCAP_REG_VCSIC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VCSI_SEL, vcsi_val_tbl, - 0x47, 0x10, 4, 0x7, 0, 350), + 0x47, 0x10, 0x7, 0, 350), CPCAP_REG(VDAC, CPCAP_REG_VDACC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VDAC_SEL, vdac_val_tbl, - 0x87, 0x30, 4, 0x3, 0, 420), + 0x87, 0x30, 0x3, 0, 420), CPCAP_REG(VDIG, CPCAP_REG_VDIGC, CPCAP_REG_ASSIGN2, CPCAP_BIT_VDIG_SEL, vdig_val_tbl, - 0x87, 0x30, 4, 0x5, 0, 420), + 0x87, 0x30, 0x5, 0, 420), CPCAP_REG(VFUSE, CPCAP_REG_VFUSEC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VFUSE_SEL, vfuse_val_tbl, - 0x80, 0xf, 0, 0x80, 0, 420), + 0x80, 0xf, 0x80, 0, 420), CPCAP_REG(VHVIO, CPCAP_REG_VHVIOC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VHVIO_SEL, vhvio_val_tbl, - 0x17, 0, 0, 0x2, 0, 0), + 0x17, 0, 0x2, 0, 0), CPCAP_REG(VSDIO, CPCAP_REG_VSDIOC, CPCAP_REG_ASSIGN2, CPCAP_BIT_VSDIO_SEL, vsdio_val_tbl, - 0x87, 0x38, 3, 0x2, 0, 420), + 0x87, 0x38, 0x2, 0, 420), CPCAP_REG(VPLL, CPCAP_REG_VPLLC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VPLL_SEL, vpll_val_tbl, - 0x43, 0x18, 3, 0x1, 0, 420), + 0x43, 0x18, 0x1, 0, 420), CPCAP_REG(VRF1, CPCAP_REG_VRF1C, CPCAP_REG_ASSIGN3, CPCAP_BIT_VRF1_SEL, vrf1_val_tbl, - 0xac, 0x2, 1, 0xc, 0, 10), + 0xac, 0x2, 0xc, 0, 10), CPCAP_REG(VRF2, CPCAP_REG_VRF2C, CPCAP_REG_ASSIGN3, CPCAP_BIT_VRF2_SEL, vrf2_val_tbl, - 0x23, 0x8, 3, 0x3, 0, 10), + 0x23, 0x8, 0x3, 0, 10), CPCAP_REG(VRFREF, CPCAP_REG_VRFREFC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VRFREF_SEL, vrfref_val_tbl, - 0x23, 0x8, 3, 0x3, 0, 420), + 0x23, 0x8, 0x3, 0, 420), CPCAP_REG(VWLAN1, CPCAP_REG_VWLAN1C, CPCAP_REG_ASSIGN3, CPCAP_BIT_VWLAN1_SEL, vwlan1_val_tbl, - 0x47, 0x10, 4, 0x5, 0, 420), + 0x47, 0x10, 0x5, 0, 420), CPCAP_REG(VWLAN2, CPCAP_REG_VWLAN2C, CPCAP_REG_ASSIGN3, CPCAP_BIT_VWLAN2_SEL, vwlan2_val_tbl, - 0x20c, 0xc0, 6, 0x8, 0, 420), + 0x20c, 0xc0, 0x8, 0, 420), CPCAP_REG(VSIM, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3, 0xffff, vsim_val_tbl, - 0x23, 0x8, 3, 0x3, 0, 420), + 0x23, 0x8, 0x3, 0, 420), CPCAP_REG(VSIMCARD, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3, 0xffff, vsimcard_val_tbl, - 0x1e80, 0x8, 3, 0x1e00, 0, 420), + 0x1e80, 0x8, 0x1e00, 0, 420), CPCAP_REG(VVIB, CPCAP_REG_VVIBC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VVIB_SEL, vvib_val_tbl, - 0x1, 0xc, 2, 0, 0x1, 500), + 0x1, 0xc, 0, 0x1, 500), CPCAP_REG(VUSB, CPCAP_REG_VUSBC, CPCAP_REG_ASSIGN3, CPCAP_BIT_VUSB_SEL, vusb_val_tbl, - 0x11c, 0x40, 6, 0xc, 0, 0), + 0x11c, 0x40, 0xc, 0, 0), CPCAP_REG(VAUDIO, CPCAP_REG_VAUDIOC, CPCAP_REG_ASSIGN4, CPCAP_BIT_VAUDIO_SEL, vaudio_val_tbl, - 0x16, 0x1, 0, 0x4, 0, 0), + 0x16, 0x1, 0x4, 0, 0), { /* sentinel */ }, }; diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index 37e4025203e3..cefa3558236d 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -290,10 +290,10 @@ static const struct regulator_ops da9052_ldo_ops = { .disable = regulator_disable_regmap, }; -#define DA9052_LDO(_id, step, min, max, sbits, ebits, abits) \ +#define DA9052_LDO(_id, _name, step, min, max, sbits, ebits, abits) \ {\ .reg_desc = {\ - .name = #_id,\ + .name = #_name,\ .ops = &da9052_ldo_ops,\ .type = REGULATOR_VOLTAGE,\ .id = DA9052_ID_##_id,\ @@ -310,10 +310,10 @@ static const struct regulator_ops da9052_ldo_ops = { .activate_bit = (abits),\ } -#define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \ +#define DA9052_DCDC(_id, _name, step, min, max, sbits, ebits, abits) \ {\ .reg_desc = {\ - .name = #_id,\ + .name = #_name,\ .ops = &da9052_dcdc_ops,\ .type = REGULATOR_VOLTAGE,\ .id = DA9052_ID_##_id,\ @@ -331,37 +331,37 @@ static const struct regulator_ops da9052_ldo_ops = { } static struct da9052_regulator_info da9052_regulator_info[] = { - DA9052_DCDC(BUCK1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), - DA9052_DCDC(BUCK2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), - DA9052_DCDC(BUCK3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), - DA9052_DCDC(BUCK4, 50, 1800, 3600, 5, 6, 0), - DA9052_LDO(LDO1, 50, 600, 1800, 5, 6, 0), - DA9052_LDO(LDO2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), - DA9052_LDO(LDO3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), - DA9052_LDO(LDO4, 25, 1725, 3300, 6, 6, 0), - DA9052_LDO(LDO5, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO6, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO7, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO8, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO9, 50, 1250, 3650, 6, 6, 0), - DA9052_LDO(LDO10, 50, 1200, 3600, 6, 6, 0), + DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), + DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), + DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), + DA9052_DCDC(BUCK4, buck4, 50, 1800, 3600, 5, 6, 0), + DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0), + DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), + DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), + DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0), + DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0), + DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0), }; static struct da9052_regulator_info da9053_regulator_info[] = { - DA9052_DCDC(BUCK1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), - DA9052_DCDC(BUCK2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), - DA9052_DCDC(BUCK3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), - DA9052_DCDC(BUCK4, 25, 950, 2525, 6, 6, 0), - DA9052_LDO(LDO1, 50, 600, 1800, 5, 6, 0), - DA9052_LDO(LDO2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), - DA9052_LDO(LDO3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), - DA9052_LDO(LDO4, 25, 1725, 3300, 6, 6, 0), - DA9052_LDO(LDO5, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO6, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO7, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO8, 50, 1200, 3600, 6, 6, 0), - DA9052_LDO(LDO9, 50, 1250, 3650, 6, 6, 0), - DA9052_LDO(LDO10, 50, 1200, 3600, 6, 6, 0), + DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), + DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), + DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), + DA9052_DCDC(BUCK4, buck4, 25, 950, 2525, 6, 6, 0), + DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0), + DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), + DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), + DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0), + DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0), + DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0), }; static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id, @@ -435,7 +435,7 @@ static int da9052_regulator_probe(struct platform_device *pdev) return -ENODEV; for_each_child_of_node(nproot, np) { - if (!of_node_cmp(np->name, + if (of_node_name_eq(np, regulator->info->reg_desc.name)) { config.init_data = of_get_regulator_init_data( &pdev->dev, np, diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c index 588c3d2445cf..3c6fac793658 100644 --- a/drivers/regulator/da9055-regulator.c +++ b/drivers/regulator/da9055-regulator.c @@ -48,7 +48,9 @@ #define DA9055_ID_LDO6 7 /* DA9055 BUCK current limit */ -static const int da9055_current_limits[] = { 500000, 600000, 700000, 800000 }; +static const unsigned int da9055_current_limits[] = { + 500000, 600000, 700000, 800000 +}; struct da9055_conf_reg { int reg; @@ -169,39 +171,6 @@ static int da9055_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode) val << volt.sl_shift); } -static int da9055_buck_get_current_limit(struct regulator_dev *rdev) -{ - struct da9055_regulator *regulator = rdev_get_drvdata(rdev); - struct da9055_regulator_info *info = regulator->info; - int ret; - - ret = da9055_reg_read(regulator->da9055, DA9055_REG_BUCK_LIM); - if (ret < 0) - return ret; - - ret &= info->mode.mask; - return da9055_current_limits[ret >> info->mode.shift]; -} - -static int da9055_buck_set_current_limit(struct regulator_dev *rdev, int min_uA, - int max_uA) -{ - struct da9055_regulator *regulator = rdev_get_drvdata(rdev); - struct da9055_regulator_info *info = regulator->info; - int i; - - for (i = ARRAY_SIZE(da9055_current_limits) - 1; i >= 0; i--) { - if ((min_uA <= da9055_current_limits[i]) && - (da9055_current_limits[i] <= max_uA)) - return da9055_reg_update(regulator->da9055, - DA9055_REG_BUCK_LIM, - info->mode.mask, - i << info->mode.shift); - } - - return -EINVAL; -} - static int da9055_regulator_get_voltage_sel(struct regulator_dev *rdev) { struct da9055_regulator *regulator = rdev_get_drvdata(rdev); @@ -329,8 +298,8 @@ static const struct regulator_ops da9055_buck_ops = { .get_mode = da9055_buck_get_mode, .set_mode = da9055_buck_set_mode, - .get_current_limit = da9055_buck_get_current_limit, - .set_current_limit = da9055_buck_set_current_limit, + .get_current_limit = regulator_get_current_limit_regmap, + .set_current_limit = regulator_set_current_limit_regmap, .get_voltage_sel = da9055_regulator_get_voltage_sel, .set_voltage_sel = da9055_regulator_set_voltage_sel, @@ -407,6 +376,10 @@ static const struct regulator_ops da9055_ldo_ops = { .uV_step = (step) * 1000,\ .linear_min_sel = (voffset),\ .owner = THIS_MODULE,\ + .curr_table = da9055_current_limits,\ + .n_current_limits = ARRAY_SIZE(da9055_current_limits),\ + .csel_reg = DA9055_REG_BUCK_LIM,\ + .csel_mask = (mbits),\ },\ .conf = {\ .reg = DA9055_REG_BCORE_CONT + DA9055_ID_##_id, \ @@ -457,7 +430,6 @@ static int da9055_gpio_init(struct da9055_regulator *regulator, int gpio_mux = pdata->gpio_ren[id]; config->ena_gpiod = pdata->ena_gpiods[id]; - config->ena_gpio_invert = 1; /* * GPI pin is muxed with regulator to control the diff --git a/drivers/regulator/da9062-regulator.c b/drivers/regulator/da9062-regulator.c index 34a70d9dc450..b064d8a19d4c 100644 --- a/drivers/regulator/da9062-regulator.c +++ b/drivers/regulator/da9062-regulator.c @@ -126,7 +126,7 @@ static int da9062_set_current_limit(struct regulator_dev *rdev, const struct da9062_regulator_info *rinfo = regl->info; int n, tval; - for (n = 0; n < rinfo->n_current_limits; n++) { + for (n = rinfo->n_current_limits - 1; n >= 0; n--) { tval = rinfo->current_limits[n]; if (tval >= min_ua && tval <= max_ua) return regmap_field_write(regl->ilimit, n); @@ -992,7 +992,6 @@ static int da9062_regulator_probe(struct platform_device *pdev) struct regulator_config config = { }; const struct da9062_regulator_info *rinfo; int irq, n, ret; - size_t size; int max_regulators; switch (chip->chip_type) { @@ -1010,9 +1009,8 @@ static int da9062_regulator_probe(struct platform_device *pdev) } /* Allocate memory required by usable regulators */ - size = sizeof(struct da9062_regulators) + - max_regulators * sizeof(struct da9062_regulator); - regulators = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + regulators = devm_kzalloc(&pdev->dev, struct_size(regulators, regulator, + max_regulators), GFP_KERNEL); if (!regulators) return -ENOMEM; @@ -1029,31 +1027,50 @@ static int da9062_regulator_probe(struct platform_device *pdev) regl->desc.type = REGULATOR_VOLTAGE; regl->desc.owner = THIS_MODULE; - if (regl->info->mode.reg) + if (regl->info->mode.reg) { regl->mode = devm_regmap_field_alloc( &pdev->dev, chip->regmap, regl->info->mode); - if (regl->info->suspend.reg) + if (IS_ERR(regl->mode)) + return PTR_ERR(regl->mode); + } + + if (regl->info->suspend.reg) { regl->suspend = devm_regmap_field_alloc( &pdev->dev, chip->regmap, regl->info->suspend); - if (regl->info->sleep.reg) + if (IS_ERR(regl->suspend)) + return PTR_ERR(regl->suspend); + } + + if (regl->info->sleep.reg) { regl->sleep = devm_regmap_field_alloc( &pdev->dev, chip->regmap, regl->info->sleep); - if (regl->info->suspend_sleep.reg) + if (IS_ERR(regl->sleep)) + return PTR_ERR(regl->sleep); + } + + if (regl->info->suspend_sleep.reg) { regl->suspend_sleep = devm_regmap_field_alloc( &pdev->dev, chip->regmap, regl->info->suspend_sleep); - if (regl->info->ilimit.reg) + if (IS_ERR(regl->suspend_sleep)) + return PTR_ERR(regl->suspend_sleep); + } + + if (regl->info->ilimit.reg) { regl->ilimit = devm_regmap_field_alloc( &pdev->dev, chip->regmap, regl->info->ilimit); + if (IS_ERR(regl->ilimit)) + return PTR_ERR(regl->ilimit); + } /* Register regulator */ memset(&config, 0, sizeof(config)); diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 8cbcd2a3eb20..2b0c7a85306a 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -167,7 +167,7 @@ static int da9063_set_current_limit(struct regulator_dev *rdev, const struct da9063_regulator_info *rinfo = regl->info; int n, tval; - for (n = 0; n < rinfo->n_current_limits; n++) { + for (n = rinfo->n_current_limits - 1; n >= 0; n--) { tval = rinfo->current_limits[n]; if (tval >= min_uA && tval <= max_uA) return regmap_field_write(regl->ilimit, n); @@ -739,7 +739,6 @@ static int da9063_regulator_probe(struct platform_device *pdev) struct regulator_config config; bool bcores_merged, bmem_bio_merged; int id, irq, n, n_regulators, ret, val; - size_t size; regl_pdata = da9063_pdata ? da9063_pdata->regulators_pdata : NULL; @@ -784,9 +783,8 @@ static int da9063_regulator_probe(struct platform_device *pdev) n_regulators--; /* remove BMEM_BIO_MERGED */ /* Allocate memory required by usable regulators */ - size = sizeof(struct da9063_regulators) + - n_regulators * sizeof(struct da9063_regulator); - regulators = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + regulators = devm_kzalloc(&pdev->dev, struct_size(regulators, + regulator, n_regulators), GFP_KERNEL); if (!regulators) return -ENOMEM; @@ -835,21 +833,40 @@ static int da9063_regulator_probe(struct platform_device *pdev) regl->desc.type = REGULATOR_VOLTAGE; regl->desc.owner = THIS_MODULE; - if (regl->info->mode.reg) + if (regl->info->mode.reg) { regl->mode = devm_regmap_field_alloc(&pdev->dev, da9063->regmap, regl->info->mode); - if (regl->info->suspend.reg) + if (IS_ERR(regl->mode)) + return PTR_ERR(regl->mode); + } + + if (regl->info->suspend.reg) { regl->suspend = devm_regmap_field_alloc(&pdev->dev, da9063->regmap, regl->info->suspend); - if (regl->info->sleep.reg) + if (IS_ERR(regl->suspend)) + return PTR_ERR(regl->suspend); + } + + if (regl->info->sleep.reg) { regl->sleep = devm_regmap_field_alloc(&pdev->dev, da9063->regmap, regl->info->sleep); - if (regl->info->suspend_sleep.reg) + if (IS_ERR(regl->sleep)) + return PTR_ERR(regl->sleep); + } + + if (regl->info->suspend_sleep.reg) { regl->suspend_sleep = devm_regmap_field_alloc(&pdev->dev, da9063->regmap, regl->info->suspend_sleep); - if (regl->info->ilimit.reg) + if (IS_ERR(regl->suspend_sleep)) + return PTR_ERR(regl->suspend_sleep); + } + + if (regl->info->ilimit.reg) { regl->ilimit = devm_regmap_field_alloc(&pdev->dev, da9063->regmap, regl->info->ilimit); + if (IS_ERR(regl->ilimit)) + return PTR_ERR(regl->ilimit); + } /* Register regulator */ memset(&config, 0, sizeof(config)); diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index d0496d6b0934..528303771723 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -41,10 +41,6 @@ static const struct regmap_config da9210_regmap_config = { .val_bits = 8, }; -static int da9210_set_current_limit(struct regulator_dev *rdev, int min_uA, - int max_uA); -static int da9210_get_current_limit(struct regulator_dev *rdev); - static const struct regulator_ops da9210_buck_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -52,8 +48,8 @@ static const struct regulator_ops da9210_buck_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, - .set_current_limit = da9210_set_current_limit, - .get_current_limit = da9210_get_current_limit, + .set_current_limit = regulator_set_current_limit_regmap, + .get_current_limit = regulator_get_current_limit_regmap, }; /* Default limits measured in millivolts and milliamps */ @@ -62,7 +58,7 @@ static const struct regulator_ops da9210_buck_ops = { #define DA9210_STEP_MV 10 /* Current limits for buck (uA) indices corresponds with register values */ -static const int da9210_buck_limits[] = { +static const unsigned int da9210_buck_limits[] = { 1600000, 1800000, 2000000, 2200000, 2400000, 2600000, 2800000, 3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, 4600000 }; @@ -80,47 +76,12 @@ static const struct regulator_desc da9210_reg = { .enable_reg = DA9210_REG_BUCK_CONT, .enable_mask = DA9210_BUCK_EN, .owner = THIS_MODULE, + .curr_table = da9210_buck_limits, + .n_current_limits = ARRAY_SIZE(da9210_buck_limits), + .csel_reg = DA9210_REG_BUCK_ILIM, + .csel_mask = DA9210_BUCK_ILIM_MASK, }; -static int da9210_set_current_limit(struct regulator_dev *rdev, int min_uA, - int max_uA) -{ - struct da9210 *chip = rdev_get_drvdata(rdev); - unsigned int sel; - int i; - - /* search for closest to maximum */ - for (i = ARRAY_SIZE(da9210_buck_limits)-1; i >= 0; i--) { - if (min_uA <= da9210_buck_limits[i] && - max_uA >= da9210_buck_limits[i]) { - sel = i; - sel = sel << DA9210_BUCK_ILIM_SHIFT; - return regmap_update_bits(chip->regmap, - DA9210_REG_BUCK_ILIM, - DA9210_BUCK_ILIM_MASK, sel); - } - } - - return -EINVAL; -} - -static int da9210_get_current_limit(struct regulator_dev *rdev) -{ - struct da9210 *chip = rdev_get_drvdata(rdev); - unsigned int data; - unsigned int sel; - int ret; - - ret = regmap_read(chip->regmap, DA9210_REG_BUCK_ILIM, &data); - if (ret < 0) - return ret; - - /* select one of 16 values: 0000 (1600mA) to 1111 (4600mA) */ - sel = (data & DA9210_BUCK_ILIM_MASK) >> DA9210_BUCK_ILIM_SHIFT; - - return da9210_buck_limits[sel]; -} - static irqreturn_t da9210_irq_handler(int irq, void *data) { struct da9210 *chip = data; @@ -131,7 +92,7 @@ static irqreturn_t da9210_irq_handler(int irq, void *data) if (error < 0) goto error_i2c; - mutex_lock(&chip->rdev->mutex); + regulator_lock(chip->rdev); if (val & DA9210_E_OVCURR) { regulator_notifier_call_chain(chip->rdev, @@ -157,7 +118,7 @@ static irqreturn_t da9210_irq_handler(int irq, void *data) handled |= DA9210_E_VMAX; } - mutex_unlock(&chip->rdev->mutex); + regulator_unlock(chip->rdev); if (handled) { /* Clear handled events */ diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index 8f68c7a05d27..109ee12d4362 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -389,6 +389,12 @@ static int da9211_regulator_init(struct da9211 *chip) else config.ena_gpiod = NULL; + /* + * Hand the GPIO descriptor management over to the regulator + * core, remove it from GPIO devres management. + */ + if (config.ena_gpiod) + devm_gpiod_unhinge(chip->dev, config.ena_gpiod); chip->rdev[i] = devm_regulator_register(chip->dev, &da9211_regulators[i], &config); if (IS_ERR(chip->rdev[i])) { diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c index 8976141c1438..308e3ff0a1bd 100644 --- a/drivers/regulator/dbx500-prcmu.c +++ b/drivers/regulator/dbx500-prcmu.c @@ -75,7 +75,7 @@ static struct ux500_regulator_debug { u8 *state_after_suspend; } rdebug; -static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p) +static int ux500_regulator_power_state_cnt_show(struct seq_file *s, void *p) { /* print power state count */ seq_printf(s, "ux500-regulator power state count: %i\n", @@ -83,23 +83,9 @@ static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p) return 0; } +DEFINE_SHOW_ATTRIBUTE(ux500_regulator_power_state_cnt); -static int ux500_regulator_power_state_cnt_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ux500_regulator_power_state_cnt_print, - inode->i_private); -} - -static const struct file_operations ux500_regulator_power_state_cnt_fops = { - .open = ux500_regulator_power_state_cnt_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ux500_regulator_status_print(struct seq_file *s, void *p) +static int ux500_regulator_status_show(struct seq_file *s, void *p) { int i; @@ -122,20 +108,7 @@ static int ux500_regulator_status_print(struct seq_file *s, void *p) return 0; } - -static int ux500_regulator_status_open(struct inode *inode, struct file *file) -{ - return single_open(file, ux500_regulator_status_print, - inode->i_private); -} - -static const struct file_operations ux500_regulator_status_fops = { - .open = ux500_regulator_status_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(ux500_regulator_status); int __attribute__((weak)) dbx500_regulator_testcase( struct dbx500_regulator_info *regulator_info, diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index a3bc8037153e..771a06d1900d 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -40,7 +40,6 @@ /* VSEL bit definitions */ #define VSEL_BUCK_EN (1 << 7) #define VSEL_MODE (1 << 6) -#define VSEL_NSEL_MASK 0x3F /* Chip ID and Verison */ #define DIE_ID 0x0F /* ID1 */ #define DIE_REV 0x0F /* ID2 */ @@ -49,14 +48,26 @@ #define CTL_SLEW_MASK (0x7 << 4) #define CTL_SLEW_SHIFT 4 #define CTL_RESET (1 << 2) +#define CTL_MODE_VSEL0_MODE BIT(0) +#define CTL_MODE_VSEL1_MODE BIT(1) #define FAN53555_NVOLTAGES 64 /* Numbers of voltages */ +#define FAN53526_NVOLTAGES 128 enum fan53555_vendor { - FAN53555_VENDOR_FAIRCHILD = 0, + FAN53526_VENDOR_FAIRCHILD = 0, + FAN53555_VENDOR_FAIRCHILD, FAN53555_VENDOR_SILERGY, }; +enum { + FAN53526_CHIP_ID_01 = 1, +}; + +enum { + FAN53526_CHIP_REV_08 = 8, +}; + /* IC Type */ enum { FAN53555_CHIP_ID_00 = 0, @@ -94,8 +105,12 @@ struct fan53555_device_info { /* Voltage range and step(linear) */ unsigned int vsel_min; unsigned int vsel_step; + unsigned int vsel_count; /* Voltage slew rate limiting */ unsigned int slew_rate; + /* Mode */ + unsigned int mode_reg; + unsigned int mode_mask; /* Sleep voltage cache */ unsigned int sleep_vol_cache; }; @@ -111,7 +126,7 @@ static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) if (ret < 0) return ret; ret = regmap_update_bits(di->regmap, di->sleep_reg, - VSEL_NSEL_MASK, ret); + di->desc.vsel_mask, ret); if (ret < 0) return ret; /* Cache the sleep voltage setting. @@ -143,11 +158,11 @@ static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode) switch (mode) { case REGULATOR_MODE_FAST: - regmap_update_bits(di->regmap, di->vol_reg, - VSEL_MODE, VSEL_MODE); + regmap_update_bits(di->regmap, di->mode_reg, + di->mode_mask, di->mode_mask); break; case REGULATOR_MODE_NORMAL: - regmap_update_bits(di->regmap, di->vol_reg, VSEL_MODE, 0); + regmap_update_bits(di->regmap, di->vol_reg, di->mode_mask, 0); break; default: return -EINVAL; @@ -161,10 +176,10 @@ static unsigned int fan53555_get_mode(struct regulator_dev *rdev) unsigned int val; int ret = 0; - ret = regmap_read(di->regmap, di->vol_reg, &val); + ret = regmap_read(di->regmap, di->mode_reg, &val); if (ret < 0) return ret; - if (val & VSEL_MODE) + if (val & di->mode_mask) return REGULATOR_MODE_FAST; else return REGULATOR_MODE_NORMAL; @@ -219,6 +234,34 @@ static const struct regulator_ops fan53555_regulator_ops = { .set_suspend_disable = fan53555_set_suspend_disable, }; +static int fan53526_voltages_setup_fairchild(struct fan53555_device_info *di) +{ + /* Init voltage range and step */ + switch (di->chip_id) { + case FAN53526_CHIP_ID_01: + switch (di->chip_rev) { + case FAN53526_CHIP_REV_08: + di->vsel_min = 600000; + di->vsel_step = 6250; + break; + default: + dev_err(di->dev, + "Chip ID %d with rev %d not supported!\n", + di->chip_id, di->chip_rev); + return -EINVAL; + } + break; + default: + dev_err(di->dev, + "Chip ID %d not supported!\n", di->chip_id); + return -EINVAL; + } + + di->vsel_count = FAN53526_NVOLTAGES; + + return 0; +} + static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di) { /* Init voltage range and step */ @@ -257,6 +300,8 @@ static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di) return -EINVAL; } + di->vsel_count = FAN53555_NVOLTAGES; + return 0; } @@ -274,6 +319,8 @@ static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di) return -EINVAL; } + di->vsel_count = FAN53555_NVOLTAGES; + return 0; } @@ -302,7 +349,35 @@ static int fan53555_device_setup(struct fan53555_device_info *di, return -EINVAL; } + /* Setup mode control register */ + switch (di->vendor) { + case FAN53526_VENDOR_FAIRCHILD: + di->mode_reg = FAN53555_CONTROL; + + switch (pdata->sleep_vsel_id) { + case FAN53555_VSEL_ID_0: + di->mode_mask = CTL_MODE_VSEL1_MODE; + break; + case FAN53555_VSEL_ID_1: + di->mode_mask = CTL_MODE_VSEL0_MODE; + break; + } + break; + case FAN53555_VENDOR_FAIRCHILD: + case FAN53555_VENDOR_SILERGY: + di->mode_reg = di->vol_reg; + di->mode_mask = VSEL_MODE; + break; + default: + dev_err(di->dev, "vendor %d not supported!\n", di->vendor); + return -EINVAL; + } + + /* Setup voltage range */ switch (di->vendor) { + case FAN53526_VENDOR_FAIRCHILD: + ret = fan53526_voltages_setup_fairchild(di); + break; case FAN53555_VENDOR_FAIRCHILD: ret = fan53555_voltages_setup_fairchild(di); break; @@ -326,13 +401,13 @@ static int fan53555_regulator_register(struct fan53555_device_info *di, rdesc->supply_name = "vin"; rdesc->ops = &fan53555_regulator_ops; rdesc->type = REGULATOR_VOLTAGE; - rdesc->n_voltages = FAN53555_NVOLTAGES; + rdesc->n_voltages = di->vsel_count; rdesc->enable_reg = di->vol_reg; rdesc->enable_mask = VSEL_BUCK_EN; rdesc->min_uV = di->vsel_min; rdesc->uV_step = di->vsel_step; rdesc->vsel_reg = di->vol_reg; - rdesc->vsel_mask = VSEL_NSEL_MASK; + rdesc->vsel_mask = di->vsel_count - 1; rdesc->owner = THIS_MODULE; di->rdev = devm_regulator_register(di->dev, &di->desc, config); @@ -368,6 +443,9 @@ static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev, static const struct of_device_id fan53555_dt_ids[] = { { + .compatible = "fcs,fan53526", + .data = (void *)FAN53526_VENDOR_FAIRCHILD, + }, { .compatible = "fcs,fan53555", .data = (void *)FAN53555_VENDOR_FAIRCHILD }, { @@ -412,11 +490,13 @@ static int fan53555_regulator_probe(struct i2c_client *client, } else { /* if no ramp constraint set, get the pdata ramp_delay */ if (!di->regulator->constraints.ramp_delay) { - int slew_idx = (pdata->slew_rate & 0x7) - ? pdata->slew_rate : 0; + if (pdata->slew_rate >= ARRAY_SIZE(slew_rates)) { + dev_err(&client->dev, "Invalid slew_rate\n"); + return -EINVAL; + } di->regulator->constraints.ramp_delay - = slew_rates[slew_idx]; + = slew_rates[pdata->slew_rate]; } di->vendor = id->driver_data; @@ -467,6 +547,9 @@ static int fan53555_regulator_probe(struct i2c_client *client, static const struct i2c_device_id fan53555_id[] = { { + .name = "fan53526", + .driver_data = FAN53526_VENDOR_FAIRCHILD + }, { .name = "fan53555", .driver_data = FAN53555_VENDOR_FAIRCHILD }, { diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index ccc29038f19a..b5afc9db2c61 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -79,15 +79,6 @@ of_get_fixed_voltage_config(struct device *dev, of_property_read_u32(np, "startup-delay-us", &config->startup_delay); - /* - * FIXME: we pulled active low/high and open drain handling into - * gpiolib so it will be handled there. Delete this in the second - * step when we also remove the custom inversion handling for all - * legacy boardfiles. - */ - config->enable_high = 1; - config->gpio_is_open_drain = 0; - if (of_find_property(np, "vin-supply", NULL)) config->input_supply = "vin"; @@ -151,24 +142,14 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) drvdata->desc.fixed_uV = config->microvolts; - cfg.ena_gpio_invert = !config->enable_high; - if (config->enabled_at_boot) { - if (config->enable_high) - gflags = GPIOD_OUT_HIGH; - else - gflags = GPIOD_OUT_LOW; - } else { - if (config->enable_high) - gflags = GPIOD_OUT_LOW; - else - gflags = GPIOD_OUT_HIGH; - } - if (config->gpio_is_open_drain) { - if (gflags == GPIOD_OUT_HIGH) - gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; - else - gflags = GPIOD_OUT_LOW_OPEN_DRAIN; - } + /* + * The signal will be inverted by the GPIO core if flagged so in the + * decriptor. + */ + if (config->enabled_at_boot) + gflags = GPIOD_OUT_HIGH; + else + gflags = GPIOD_OUT_LOW; /* * Some fixed regulators share the enable line between two @@ -183,7 +164,11 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) */ gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE; - cfg.ena_gpiod = devm_gpiod_get_optional(&pdev->dev, NULL, gflags); + /* + * Do not use devm* here: the regulator core takes over the + * lifecycle management of the GPIO descriptor. + */ + cfg.ena_gpiod = gpiod_get_optional(&pdev->dev, NULL, gflags); if (IS_ERR(cfg.ena_gpiod)) return PTR_ERR(cfg.ena_gpiod); diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index b2f5ec4f658a..6157001df0a4 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -30,16 +30,15 @@ #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> #include <linux/regulator/gpio-regulator.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/of_gpio.h> struct gpio_regulator_data { struct regulator_desc desc; struct regulator_dev *dev; - struct gpio *gpios; + struct gpio_desc **gpiods; int nr_gpios; struct gpio_regulator_state *states; @@ -82,7 +81,7 @@ static int gpio_regulator_set_voltage(struct regulator_dev *dev, for (ptr = 0; ptr < data->nr_gpios; ptr++) { state = (target & (1 << ptr)) >> ptr; - gpio_set_value_cansleep(data->gpios[ptr].gpio, state); + gpiod_set_value_cansleep(data->gpiods[ptr], state); } data->state = target; @@ -119,7 +118,7 @@ static int gpio_regulator_set_current_limit(struct regulator_dev *dev, for (ptr = 0; ptr < data->nr_gpios; ptr++) { state = (target & (1 << ptr)) >> ptr; - gpio_set_value_cansleep(data->gpios[ptr].gpio, state); + gpiod_set_value_cansleep(data->gpiods[ptr], state); } data->state = target; @@ -138,7 +137,8 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np, { struct gpio_regulator_config *config; const char *regtype; - int proplen, gpio, i; + int proplen, i; + int ngpios; int ret; config = devm_kzalloc(dev, @@ -153,59 +153,36 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np, config->supply_name = config->init_data->constraints.name; - if (of_property_read_bool(np, "enable-active-high")) - config->enable_high = true; - if (of_property_read_bool(np, "enable-at-boot")) config->enabled_at_boot = true; of_property_read_u32(np, "startup-delay-us", &config->startup_delay); - config->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0); - if (config->enable_gpio < 0 && config->enable_gpio != -ENOENT) - return ERR_PTR(config->enable_gpio); - - /* Fetch GPIOs. - optional property*/ - ret = of_gpio_count(np); - if ((ret < 0) && (ret != -ENOENT)) - return ERR_PTR(ret); - - if (ret > 0) { - config->nr_gpios = ret; - config->gpios = devm_kcalloc(dev, - config->nr_gpios, sizeof(struct gpio), - GFP_KERNEL); - if (!config->gpios) + /* Fetch GPIO init levels */ + ngpios = gpiod_count(dev, NULL); + if (ngpios > 0) { + config->gflags = devm_kzalloc(dev, + sizeof(enum gpiod_flags) + * ngpios, + GFP_KERNEL); + if (!config->gflags) return ERR_PTR(-ENOMEM); - proplen = of_property_count_u32_elems(np, "gpios-states"); - /* optional property */ - if (proplen < 0) - proplen = 0; + for (i = 0; i < ngpios; i++) { + u32 val; - if (proplen > 0 && proplen != config->nr_gpios) { - dev_warn(dev, "gpios <-> gpios-states mismatch\n"); - proplen = 0; - } + ret = of_property_read_u32_index(np, "gpios-states", i, + &val); - for (i = 0; i < config->nr_gpios; i++) { - gpio = of_get_named_gpio(np, "gpios", i); - if (gpio < 0) { - if (gpio != -ENOENT) - return ERR_PTR(gpio); - break; - } - config->gpios[i].gpio = gpio; - config->gpios[i].label = config->supply_name; - if (proplen > 0) { - of_property_read_u32_index(np, "gpios-states", - i, &ret); - if (ret) - config->gpios[i].flags = - GPIOF_OUT_INIT_HIGH; - } + /* Default to high per specification */ + if (ret) + config->gflags[i] = GPIOD_OUT_HIGH; + else + config->gflags[i] = + val ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; } } + config->ngpios = ngpios; /* Fetch states. */ proplen = of_property_count_u32_elems(np, "states"); @@ -251,59 +228,56 @@ static struct regulator_ops gpio_regulator_current_ops = { static int gpio_regulator_probe(struct platform_device *pdev) { - struct gpio_regulator_config *config = dev_get_platdata(&pdev->dev); - struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct gpio_regulator_config *config = dev_get_platdata(dev); + struct device_node *np = dev->of_node; struct gpio_regulator_data *drvdata; struct regulator_config cfg = { }; - int ptr, ret, state; + enum gpiod_flags gflags; + int ptr, ret, state, i; - drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data), + drvdata = devm_kzalloc(dev, sizeof(struct gpio_regulator_data), GFP_KERNEL); if (drvdata == NULL) return -ENOMEM; if (np) { - config = of_get_gpio_regulator_config(&pdev->dev, np, + config = of_get_gpio_regulator_config(dev, np, &drvdata->desc); if (IS_ERR(config)) return PTR_ERR(config); } - drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); + drvdata->desc.name = devm_kstrdup(dev, config->supply_name, GFP_KERNEL); if (drvdata->desc.name == NULL) { - dev_err(&pdev->dev, "Failed to allocate supply name\n"); + dev_err(dev, "Failed to allocate supply name\n"); return -ENOMEM; } - if (config->nr_gpios != 0) { - drvdata->gpios = kmemdup(config->gpios, - config->nr_gpios * sizeof(struct gpio), - GFP_KERNEL); - if (drvdata->gpios == NULL) { - dev_err(&pdev->dev, "Failed to allocate gpio data\n"); - ret = -ENOMEM; - goto err_name; - } - - drvdata->nr_gpios = config->nr_gpios; - ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "Could not obtain regulator setting GPIOs: %d\n", - ret); - goto err_memgpio; - } + drvdata->gpiods = devm_kzalloc(dev, sizeof(struct gpio_desc *), + GFP_KERNEL); + if (!drvdata->gpiods) + return -ENOMEM; + for (i = 0; i < config->ngpios; i++) { + drvdata->gpiods[i] = devm_gpiod_get_index(dev, + NULL, + i, + config->gflags[i]); + if (IS_ERR(drvdata->gpiods[i])) + return PTR_ERR(drvdata->gpiods[i]); + /* This is good to know */ + gpiod_set_consumer_name(drvdata->gpiods[i], drvdata->desc.name); } + drvdata->nr_gpios = config->ngpios; - drvdata->states = kmemdup(config->states, - config->nr_states * - sizeof(struct gpio_regulator_state), - GFP_KERNEL); + drvdata->states = devm_kmemdup(dev, + config->states, + config->nr_states * + sizeof(struct gpio_regulator_state), + GFP_KERNEL); if (drvdata->states == NULL) { - dev_err(&pdev->dev, "Failed to allocate state data\n"); - ret = -ENOMEM; - goto err_stategpio; + dev_err(dev, "Failed to allocate state data\n"); + return -ENOMEM; } drvdata->nr_states = config->nr_states; @@ -322,61 +296,46 @@ static int gpio_regulator_probe(struct platform_device *pdev) drvdata->desc.ops = &gpio_regulator_current_ops; break; default: - dev_err(&pdev->dev, "No regulator type set\n"); - ret = -EINVAL; - goto err_memstate; + dev_err(dev, "No regulator type set\n"); + return -EINVAL; } /* build initial state from gpio init data. */ state = 0; for (ptr = 0; ptr < drvdata->nr_gpios; ptr++) { - if (config->gpios[ptr].flags & GPIOF_OUT_INIT_HIGH) + if (config->gflags[ptr] == GPIOD_OUT_HIGH) state |= (1 << ptr); } drvdata->state = state; - cfg.dev = &pdev->dev; + cfg.dev = dev; cfg.init_data = config->init_data; cfg.driver_data = drvdata; cfg.of_node = np; - if (gpio_is_valid(config->enable_gpio)) { - cfg.ena_gpio = config->enable_gpio; - cfg.ena_gpio_initialized = true; - } - cfg.ena_gpio_invert = !config->enable_high; - if (config->enabled_at_boot) { - if (config->enable_high) - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; - else - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; - } else { - if (config->enable_high) - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW; - else - cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH; - } + /* + * The signal will be inverted by the GPIO core if flagged so in the + * decriptor. + */ + if (config->enabled_at_boot) + gflags = GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE; + else + gflags = GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE; + + cfg.ena_gpiod = gpiod_get_optional(dev, "enable", gflags); + if (IS_ERR(cfg.ena_gpiod)) + return PTR_ERR(cfg.ena_gpiod); drvdata->dev = regulator_register(&drvdata->desc, &cfg); if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); - dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); - goto err_memstate; + dev_err(dev, "Failed to register regulator: %d\n", ret); + return ret; } platform_set_drvdata(pdev, drvdata); return 0; - -err_memstate: - kfree(drvdata->states); -err_stategpio: - gpio_free_array(drvdata->gpios, drvdata->nr_gpios); -err_memgpio: - kfree(drvdata->gpios); -err_name: - kfree(drvdata->desc.name); - return ret; } static int gpio_regulator_remove(struct platform_device *pdev) @@ -385,13 +344,6 @@ static int gpio_regulator_remove(struct platform_device *pdev) regulator_unregister(drvdata->dev); - gpio_free_array(drvdata->gpios, drvdata->nr_gpios); - - kfree(drvdata->states); - kfree(drvdata->gpios); - - kfree(drvdata->desc.name); - return 0; } diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index 5686a1335bd3..32d3f0499e2d 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -594,28 +594,30 @@ int regulator_list_voltage_pickable_linear_range(struct regulator_dev *rdev, EXPORT_SYMBOL_GPL(regulator_list_voltage_pickable_linear_range); /** - * regulator_list_voltage_linear_range - List voltages for linear ranges + * regulator_desc_list_voltage_linear_range - List voltages for linear ranges * - * @rdev: Regulator device + * @desc: Regulator desc for regulator which volatges are to be listed * @selector: Selector to convert into a voltage * * Regulators with a series of simple linear mappings between voltages - * and selectors can set linear_ranges in the regulator descriptor and - * then use this function as their list_voltage() operation, + * and selectors who have set linear_ranges in the regulator descriptor + * can use this function prior regulator registration to list voltages. + * This is useful when voltages need to be listed during device-tree + * parsing. */ -int regulator_list_voltage_linear_range(struct regulator_dev *rdev, - unsigned int selector) +int regulator_desc_list_voltage_linear_range(const struct regulator_desc *desc, + unsigned int selector) { const struct regulator_linear_range *range; int i; - if (!rdev->desc->n_linear_ranges) { - BUG_ON(!rdev->desc->n_linear_ranges); + if (!desc->n_linear_ranges) { + BUG_ON(!desc->n_linear_ranges); return -EINVAL; } - for (i = 0; i < rdev->desc->n_linear_ranges; i++) { - range = &rdev->desc->linear_ranges[i]; + for (i = 0; i < desc->n_linear_ranges; i++) { + range = &desc->linear_ranges[i]; if (!(selector >= range->min_sel && selector <= range->max_sel)) @@ -628,6 +630,23 @@ int regulator_list_voltage_linear_range(struct regulator_dev *rdev, return -EINVAL; } +EXPORT_SYMBOL_GPL(regulator_desc_list_voltage_linear_range); + +/** + * regulator_list_voltage_linear_range - List voltages for linear ranges + * + * @rdev: Regulator device + * @selector: Selector to convert into a voltage + * + * Regulators with a series of simple linear mappings between voltages + * and selectors can set linear_ranges in the regulator descriptor and + * then use this function as their list_voltage() operation, + */ +int regulator_list_voltage_linear_range(struct regulator_dev *rdev, + unsigned int selector) +{ + return regulator_desc_list_voltage_linear_range(rdev->desc, selector); +} EXPORT_SYMBOL_GPL(regulator_list_voltage_linear_range); /** @@ -761,3 +780,89 @@ int regulator_set_active_discharge_regmap(struct regulator_dev *rdev, rdev->desc->active_discharge_mask, val); } EXPORT_SYMBOL_GPL(regulator_set_active_discharge_regmap); + +/** + * regulator_set_current_limit_regmap - set_current_limit for regmap users + * + * @rdev: regulator to operate on + * @min_uA: Lower bound for current limit + * @max_uA: Upper bound for current limit + * + * Regulators that use regmap for their register I/O can set curr_table, + * csel_reg and csel_mask fields in their descriptor and then use this + * as their set_current_limit operation, saving some code. + */ +int regulator_set_current_limit_regmap(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + unsigned int n_currents = rdev->desc->n_current_limits; + int i, sel = -1; + + if (n_currents == 0) + return -EINVAL; + + if (rdev->desc->curr_table) { + const unsigned int *curr_table = rdev->desc->curr_table; + bool ascend = curr_table[n_currents - 1] > curr_table[0]; + + /* search for closest to maximum */ + if (ascend) { + for (i = n_currents - 1; i >= 0; i--) { + if (min_uA <= curr_table[i] && + curr_table[i] <= max_uA) { + sel = i; + break; + } + } + } else { + for (i = 0; i < n_currents; i++) { + if (min_uA <= curr_table[i] && + curr_table[i] <= max_uA) { + sel = i; + break; + } + } + } + } + + if (sel < 0) + return -EINVAL; + + sel <<= ffs(rdev->desc->csel_mask) - 1; + + return regmap_update_bits(rdev->regmap, rdev->desc->csel_reg, + rdev->desc->csel_mask, sel); +} +EXPORT_SYMBOL_GPL(regulator_set_current_limit_regmap); + +/** + * regulator_get_current_limit_regmap - get_current_limit for regmap users + * + * @rdev: regulator to operate on + * + * Regulators that use regmap for their register I/O can set the + * csel_reg and csel_mask fields in their descriptor and then use this + * as their get_current_limit operation, saving some code. + */ +int regulator_get_current_limit_regmap(struct regulator_dev *rdev) +{ + unsigned int val; + int ret; + + ret = regmap_read(rdev->regmap, rdev->desc->csel_reg, &val); + if (ret != 0) + return ret; + + val &= rdev->desc->csel_mask; + val >>= ffs(rdev->desc->csel_mask) - 1; + + if (rdev->desc->curr_table) { + if (val >= rdev->desc->n_current_limits) + return -EINVAL; + + return rdev->desc->curr_table[val]; + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(regulator_get_current_limit_regmap); diff --git a/drivers/regulator/hi655x-regulator.c b/drivers/regulator/hi655x-regulator.c index 36ae54b53814..bba24a6fdb1e 100644 --- a/drivers/regulator/hi655x-regulator.c +++ b/drivers/regulator/hi655x-regulator.c @@ -28,7 +28,6 @@ struct hi655x_regulator { unsigned int disable_reg; unsigned int status_reg; - unsigned int ctrl_regs; unsigned int ctrl_mask; struct regulator_desc rdesc; }; diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h index 943926a156f2..6017f15c5d75 100644 --- a/drivers/regulator/internal.h +++ b/drivers/regulator/internal.h @@ -42,6 +42,8 @@ struct regulator { unsigned int always_on:1; unsigned int bypass:1; int uA_load; + unsigned int enable_count; + unsigned int deferred_disables; struct regulator_voltage voltage[REGULATOR_STATES_NUM]; const char *supply_name; struct device_attribute dev_attr; diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index 4abd8e9c81e5..6f28bba81d13 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -31,7 +31,6 @@ /* PMIC details */ struct isl_pmic { struct i2c_client *client; - struct regulator_dev *rdev[3]; struct mutex mtx; }; @@ -66,14 +65,14 @@ static int isl6271a_set_voltage_sel(struct regulator_dev *dev, return err; } -static struct regulator_ops isl_core_ops = { +static const struct regulator_ops isl_core_ops = { .get_voltage_sel = isl6271a_get_voltage_sel, .set_voltage_sel = isl6271a_set_voltage_sel, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, }; -static struct regulator_ops isl_fixed_ops = { +static const struct regulator_ops isl_fixed_ops = { .list_voltage = regulator_list_voltage_linear, }; @@ -109,6 +108,7 @@ static const struct regulator_desc isl_rd[] = { static int isl6271a_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct regulator_dev *rdev; struct regulator_config config = { }; struct regulator_init_data *init_data = dev_get_platdata(&i2c->dev); struct isl_pmic *pmic; @@ -133,11 +133,10 @@ static int isl6271a_probe(struct i2c_client *i2c, config.init_data = NULL; config.driver_data = pmic; - pmic->rdev[i] = devm_regulator_register(&i2c->dev, &isl_rd[i], - &config); - if (IS_ERR(pmic->rdev[i])) { + rdev = devm_regulator_register(&i2c->dev, &isl_rd[i], &config); + if (IS_ERR(rdev)) { dev_err(&i2c->dev, "failed to register %s\n", id->name); - return PTR_ERR(pmic->rdev[i]); + return PTR_ERR(rdev); } } diff --git a/drivers/regulator/lm363x-regulator.c b/drivers/regulator/lm363x-regulator.c index bbedb08d257b..c876e161052a 100644 --- a/drivers/regulator/lm363x-regulator.c +++ b/drivers/regulator/lm363x-regulator.c @@ -224,13 +224,15 @@ static struct gpio_desc *lm363x_regulator_of_get_enable_gpio(struct device *dev, /* * Check LCM_EN1/2_GPIO is configured. * Those pins are used for enabling VPOS/VNEG LDOs. + * Do not use devm* here: the regulator core takes over the + * lifecycle management of the GPIO descriptor. */ switch (id) { case LM3632_LDO_POS: - return devm_gpiod_get_index_optional(dev, "enable", 0, + return gpiod_get_index_optional(dev, "enable", 0, GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); case LM3632_LDO_NEG: - return devm_gpiod_get_index_optional(dev, "enable", 1, + return gpiod_get_index_optional(dev, "enable", 1, GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); default: return NULL; @@ -256,6 +258,9 @@ static int lm363x_regulator_probe(struct platform_device *pdev) * Register update is required if the pin is used. */ gpiod = lm363x_regulator_of_get_enable_gpio(dev, id); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + if (gpiod) { cfg.ena_gpiod = gpiod; @@ -263,6 +268,7 @@ static int lm363x_regulator_probe(struct platform_device *pdev) LM3632_EXT_EN_MASK, LM3632_EXT_EN_MASK); if (ret) { + gpiod_put(gpiod); dev_err(dev, "External pin err: %d\n", ret); return ret; } diff --git a/drivers/regulator/lochnagar-regulator.c b/drivers/regulator/lochnagar-regulator.c index 2b5073b9ff86..ff97cc50f2eb 100644 --- a/drivers/regulator/lochnagar-regulator.c +++ b/drivers/regulator/lochnagar-regulator.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/regulator/driver.h> @@ -20,6 +21,8 @@ #include <linux/regulator/of_regulator.h> #include <linux/mfd/lochnagar.h> +#include <linux/mfd/lochnagar1_regs.h> +#include <linux/mfd/lochnagar2_regs.h> static const struct regulator_ops lochnagar_micvdd_ops = { .enable = regulator_enable_regmap, @@ -191,7 +194,7 @@ static const struct regulator_desc lochnagar_regulators[] = { .name = "VDDCORE", .supply_name = "SYSVDD", .type = REGULATOR_VOLTAGE, - .n_voltages = 57, + .n_voltages = 66, .ops = &lochnagar_vddcore_ops, .id = LOCHNAGAR_VDDCORE, @@ -212,28 +215,53 @@ static const struct regulator_desc lochnagar_regulators[] = { }, }; +static const struct of_device_id lochnagar_of_match[] = { + { + .compatible = "cirrus,lochnagar2-micvdd", + .data = &lochnagar_regulators[LOCHNAGAR_MICVDD], + }, + { + .compatible = "cirrus,lochnagar2-mic1vdd", + .data = &lochnagar_regulators[LOCHNAGAR_MIC1VDD], + }, + { + .compatible = "cirrus,lochnagar2-mic2vdd", + .data = &lochnagar_regulators[LOCHNAGAR_MIC2VDD], + }, + { + .compatible = "cirrus,lochnagar2-vddcore", + .data = &lochnagar_regulators[LOCHNAGAR_VDDCORE], + }, + {} +}; +MODULE_DEVICE_TABLE(of, lochnagar_of_match); + static int lochnagar_regulator_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct lochnagar *lochnagar = dev_get_drvdata(dev->parent); struct regulator_config config = { }; + const struct of_device_id *of_id; + const struct regulator_desc *desc; struct regulator_dev *rdev; - int ret, i; + int ret; - config.dev = lochnagar->dev; + config.dev = dev; config.regmap = lochnagar->regmap; config.driver_data = lochnagar; - for (i = 0; i < ARRAY_SIZE(lochnagar_regulators); i++) { - const struct regulator_desc *desc = &lochnagar_regulators[i]; + of_id = of_match_device(lochnagar_of_match, dev); + if (!of_id) + return -EINVAL; - rdev = devm_regulator_register(dev, desc, &config); - if (IS_ERR(rdev)) { - ret = PTR_ERR(rdev); - dev_err(dev, "Failed to register %s regulator: %d\n", - desc->name, ret); - return ret; - } + desc = of_id->data; + + rdev = devm_regulator_register(dev, desc, &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(dev, "Failed to register %s regulator: %d\n", + desc->name, ret); + return ret; } return 0; @@ -242,6 +270,7 @@ static int lochnagar_regulator_probe(struct platform_device *pdev) static struct platform_driver lochnagar_regulator_driver = { .driver = { .name = "lochnagar-regulator", + .of_match_table = of_match_ptr(lochnagar_of_match), }, .probe = lochnagar_regulator_probe, diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 204b5c5270e0..9e45112658ba 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -159,7 +159,7 @@ static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev, selector << LDO_VOL_CONTR_SHIFT(ldo)); } -static struct regulator_ops lp3971_ldo_ops = { +static const struct regulator_ops lp3971_ldo_ops = { .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .is_enabled = lp3971_ldo_is_enabled, @@ -233,7 +233,7 @@ static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev, 0 << BUCK_VOL_CHANGE_SHIFT(buck)); } -static struct regulator_ops lp3971_dcdc_ops = { +static const struct regulator_ops lp3971_dcdc_ops = { .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .is_enabled = lp3971_dcdc_is_enabled, diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index ff0c275f902e..fb098198b688 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -305,7 +305,7 @@ static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev, return ret; } -static struct regulator_ops lp3972_ldo_ops = { +static const struct regulator_ops lp3972_ldo_ops = { .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .is_enabled = lp3972_ldo_is_enabled, @@ -386,7 +386,7 @@ static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev, LP3972_VOL_CHANGE_FLAG_MASK, 0); } -static struct regulator_ops lp3972_dcdc_ops = { +static const struct regulator_ops lp3972_dcdc_ops = { .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .is_enabled = lp3972_dcdc_is_enabled, diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 38992112fd6e..ca95257ce252 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -353,64 +353,6 @@ static int lp872x_buck_get_voltage_sel(struct regulator_dev *rdev) return val & LP872X_VOUT_M; } -static int lp8725_buck_set_current_limit(struct regulator_dev *rdev, - int min_uA, int max_uA) -{ - struct lp872x *lp = rdev_get_drvdata(rdev); - enum lp872x_regulator_id buck = rdev_get_id(rdev); - int i; - u8 addr; - - switch (buck) { - case LP8725_ID_BUCK1: - addr = LP8725_BUCK1_VOUT2; - break; - case LP8725_ID_BUCK2: - addr = LP8725_BUCK2_VOUT2; - break; - default: - return -EINVAL; - } - - for (i = ARRAY_SIZE(lp8725_buck_uA) - 1; i >= 0; i--) { - if (lp8725_buck_uA[i] >= min_uA && - lp8725_buck_uA[i] <= max_uA) - return lp872x_update_bits(lp, addr, - LP8725_BUCK_CL_M, - i << LP8725_BUCK_CL_S); - } - - return -EINVAL; -} - -static int lp8725_buck_get_current_limit(struct regulator_dev *rdev) -{ - struct lp872x *lp = rdev_get_drvdata(rdev); - enum lp872x_regulator_id buck = rdev_get_id(rdev); - u8 addr, val; - int ret; - - switch (buck) { - case LP8725_ID_BUCK1: - addr = LP8725_BUCK1_VOUT2; - break; - case LP8725_ID_BUCK2: - addr = LP8725_BUCK2_VOUT2; - break; - default: - return -EINVAL; - } - - ret = lp872x_read_byte(lp, addr, &val); - if (ret) - return ret; - - val = (val & LP8725_BUCK_CL_M) >> LP8725_BUCK_CL_S; - - return (val < ARRAY_SIZE(lp8725_buck_uA)) ? - lp8725_buck_uA[val] : -EINVAL; -} - static int lp872x_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct lp872x *lp = rdev_get_drvdata(rdev); @@ -478,7 +420,7 @@ static unsigned int lp872x_buck_get_mode(struct regulator_dev *rdev) return val & mask ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; } -static struct regulator_ops lp872x_ldo_ops = { +static const struct regulator_ops lp872x_ldo_ops = { .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -489,7 +431,7 @@ static struct regulator_ops lp872x_ldo_ops = { .enable_time = lp872x_regulator_enable_time, }; -static struct regulator_ops lp8720_buck_ops = { +static const struct regulator_ops lp8720_buck_ops = { .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = lp872x_buck_set_voltage_sel, @@ -502,7 +444,7 @@ static struct regulator_ops lp8720_buck_ops = { .get_mode = lp872x_buck_get_mode, }; -static struct regulator_ops lp8725_buck_ops = { +static const struct regulator_ops lp8725_buck_ops = { .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = lp872x_buck_set_voltage_sel, @@ -513,11 +455,11 @@ static struct regulator_ops lp8725_buck_ops = { .enable_time = lp872x_regulator_enable_time, .set_mode = lp872x_buck_set_mode, .get_mode = lp872x_buck_get_mode, - .set_current_limit = lp8725_buck_set_current_limit, - .get_current_limit = lp8725_buck_get_current_limit, + .set_current_limit = regulator_set_current_limit_regmap, + .get_current_limit = regulator_get_current_limit_regmap, }; -static struct regulator_desc lp8720_regulator_desc[] = { +static const struct regulator_desc lp8720_regulator_desc[] = { { .name = "ldo1", .of_match = of_match_ptr("ldo1"), @@ -602,7 +544,7 @@ static struct regulator_desc lp8720_regulator_desc[] = { }, }; -static struct regulator_desc lp8725_regulator_desc[] = { +static const struct regulator_desc lp8725_regulator_desc[] = { { .name = "ldo1", .of_match = of_match_ptr("ldo1"), @@ -712,6 +654,10 @@ static struct regulator_desc lp8725_regulator_desc[] = { .owner = THIS_MODULE, .enable_reg = LP872X_GENERAL_CFG, .enable_mask = LP8725_BUCK1_EN_M, + .curr_table = lp8725_buck_uA, + .n_current_limits = ARRAY_SIZE(lp8725_buck_uA), + .csel_reg = LP8725_BUCK1_VOUT2, + .csel_mask = LP8725_BUCK_CL_M, }, { .name = "buck2", @@ -724,6 +670,10 @@ static struct regulator_desc lp8725_regulator_desc[] = { .owner = THIS_MODULE, .enable_reg = LP872X_GENERAL_CFG, .enable_mask = LP8725_BUCK2_EN_M, + .curr_table = lp8725_buck_uA, + .n_current_limits = ARRAY_SIZE(lp8725_buck_uA), + .csel_reg = LP8725_BUCK2_VOUT2, + .csel_mask = LP8725_BUCK_CL_M, }, }; @@ -820,7 +770,7 @@ static struct regulator_init_data static int lp872x_regulator_register(struct lp872x *lp) { - struct regulator_desc *desc; + const struct regulator_desc *desc; struct regulator_config cfg = { }; struct regulator_dev *rdev; int i; diff --git a/drivers/regulator/lp873x-regulator.c b/drivers/regulator/lp873x-regulator.c index 70e3df653381..b55de293ca7a 100644 --- a/drivers/regulator/lp873x-regulator.c +++ b/drivers/regulator/lp873x-regulator.c @@ -39,6 +39,10 @@ .ramp_delay = _delay, \ .linear_ranges = _lr, \ .n_linear_ranges = ARRAY_SIZE(_lr), \ + .curr_table = lp873x_buck_uA, \ + .n_current_limits = ARRAY_SIZE(lp873x_buck_uA), \ + .csel_reg = (_cr), \ + .csel_mask = LP873X_BUCK0_CTRL_2_BUCK0_ILIM,\ }, \ .ctrl2_reg = _cr, \ } @@ -61,7 +65,7 @@ static const struct regulator_linear_range ldo0_ldo1_ranges[] = { REGULATOR_LINEAR_RANGE(800000, 0x0, 0x19, 100000), }; -static unsigned int lp873x_buck_ramp_delay[] = { +static const unsigned int lp873x_buck_ramp_delay[] = { 30000, 15000, 10000, 7500, 3800, 1900, 940, 470 }; @@ -108,45 +112,8 @@ static int lp873x_buck_set_ramp_delay(struct regulator_dev *rdev, return 0; } -static int lp873x_buck_set_current_limit(struct regulator_dev *rdev, - int min_uA, int max_uA) -{ - int id = rdev_get_id(rdev); - struct lp873x *lp873 = rdev_get_drvdata(rdev); - int i; - - for (i = ARRAY_SIZE(lp873x_buck_uA) - 1; i >= 0; i--) { - if (lp873x_buck_uA[i] >= min_uA && - lp873x_buck_uA[i] <= max_uA) - return regmap_update_bits(lp873->regmap, - regulators[id].ctrl2_reg, - LP873X_BUCK0_CTRL_2_BUCK0_ILIM, - i << __ffs(LP873X_BUCK0_CTRL_2_BUCK0_ILIM)); - } - - return -EINVAL; -} - -static int lp873x_buck_get_current_limit(struct regulator_dev *rdev) -{ - int id = rdev_get_id(rdev); - struct lp873x *lp873 = rdev_get_drvdata(rdev); - int ret; - unsigned int val; - - ret = regmap_read(lp873->regmap, regulators[id].ctrl2_reg, &val); - if (ret) - return ret; - - val = (val & LP873X_BUCK0_CTRL_2_BUCK0_ILIM) >> - __ffs(LP873X_BUCK0_CTRL_2_BUCK0_ILIM); - - return (val < ARRAY_SIZE(lp873x_buck_uA)) ? - lp873x_buck_uA[val] : -EINVAL; -} - /* Operations permitted on BUCK0, BUCK1 */ -static struct regulator_ops lp873x_buck01_ops = { +static const struct regulator_ops lp873x_buck01_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -156,12 +123,12 @@ static struct regulator_ops lp873x_buck01_ops = { .map_voltage = regulator_map_voltage_linear_range, .set_voltage_time_sel = regulator_set_voltage_time_sel, .set_ramp_delay = lp873x_buck_set_ramp_delay, - .set_current_limit = lp873x_buck_set_current_limit, - .get_current_limit = lp873x_buck_get_current_limit, + .set_current_limit = regulator_set_current_limit_regmap, + .get_current_limit = regulator_get_current_limit_regmap, }; /* Operations permitted on LDO0 and LDO1 */ -static struct regulator_ops lp873x_ldo01_ops = { +static const struct regulator_ops lp873x_ldo01_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c index 244822bb63cd..14fd38807134 100644 --- a/drivers/regulator/lp8755.c +++ b/drivers/regulator/lp8755.c @@ -315,7 +315,7 @@ out_i2c_error: .vsel_mask = LP8755_BUCK_VOUT_M,\ } -static struct regulator_desc lp8755_regulators[] = { +static const struct regulator_desc lp8755_regulators[] = { lp8755_buck_desc(0), lp8755_buck_desc(1), lp8755_buck_desc(2), @@ -386,7 +386,7 @@ static irqreturn_t lp8755_irq_handler(int irq, void *data) if (ret < 0) goto err_i2c; - /* send OCP event to all regualtor devices */ + /* send OCP event to all regulator devices */ if ((flag1 & 0x01) && (pchip->irqmask & 0x01)) for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) if (pchip->rdev[icnt] != NULL) @@ -394,7 +394,7 @@ static irqreturn_t lp8755_irq_handler(int irq, void *data) LP8755_EVENT_OCP, NULL); - /* send OVP event to all regualtor devices */ + /* send OVP event to all regulator devices */ if ((flag1 & 0x02) && (pchip->irqmask & 0x02)) for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) if (pchip->rdev[icnt] != NULL) diff --git a/drivers/regulator/lp87565-regulator.c b/drivers/regulator/lp87565-regulator.c index c192357d1dea..4ed41731a5b1 100644 --- a/drivers/regulator/lp87565-regulator.c +++ b/drivers/regulator/lp87565-regulator.c @@ -51,7 +51,7 @@ static const struct regulator_linear_range buck0_1_2_3_ranges[] = { REGULATOR_LINEAR_RANGE(1420000, 0x9e, 0xff, 20000), }; -static unsigned int lp87565_buck_ramp_delay[] = { +static const unsigned int lp87565_buck_ramp_delay[] = { 30000, 15000, 10000, 7500, 3800, 1900, 940, 470 }; @@ -140,7 +140,7 @@ static int lp87565_buck_get_current_limit(struct regulator_dev *rdev) } /* Operations permitted on BUCK0, BUCK1 */ -static struct regulator_ops lp87565_buck_ops = { +static const struct regulator_ops lp87565_buck_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c index ec46290b647e..a7d30550bb5f 100644 --- a/drivers/regulator/lp8788-buck.c +++ b/drivers/regulator/lp8788-buck.c @@ -95,12 +95,10 @@ struct lp8788_buck { void *dvs; }; -/* BUCK 1 ~ 4 voltage table */ -static const int lp8788_buck_vtbl[] = { - 500000, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, - 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, - 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, - 1950000, 2000000, +/* BUCK 1 ~ 4 voltage ranges */ +static const struct regulator_linear_range buck_volt_ranges[] = { + REGULATOR_LINEAR_RANGE(500000, 0, 0, 0), + REGULATOR_LINEAR_RANGE(800000, 1, 25, 50000), }; static void lp8788_buck1_set_dvs(struct lp8788_buck *buck) @@ -345,8 +343,8 @@ static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev) } static const struct regulator_ops lp8788_buck12_ops = { - .list_voltage = regulator_list_voltage_table, - .map_voltage = regulator_map_voltage_ascend, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, .set_voltage_sel = lp8788_buck12_set_voltage_sel, .get_voltage_sel = lp8788_buck12_get_voltage_sel, .enable = regulator_enable_regmap, @@ -358,8 +356,8 @@ static const struct regulator_ops lp8788_buck12_ops = { }; static const struct regulator_ops lp8788_buck34_ops = { - .list_voltage = regulator_list_voltage_table, - .map_voltage = regulator_map_voltage_ascend, + .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, .enable = regulator_enable_regmap, @@ -370,13 +368,14 @@ static const struct regulator_ops lp8788_buck34_ops = { .get_mode = lp8788_buck_get_mode, }; -static struct regulator_desc lp8788_buck_desc[] = { +static const struct regulator_desc lp8788_buck_desc[] = { { .name = "buck1", .id = BUCK1, .ops = &lp8788_buck12_ops, - .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), - .volt_table = lp8788_buck_vtbl, + .n_voltages = 26, + .linear_ranges = buck_volt_ranges, + .n_linear_ranges = ARRAY_SIZE(buck_volt_ranges), .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, .enable_reg = LP8788_EN_BUCK, @@ -386,8 +385,9 @@ static struct regulator_desc lp8788_buck_desc[] = { .name = "buck2", .id = BUCK2, .ops = &lp8788_buck12_ops, - .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), - .volt_table = lp8788_buck_vtbl, + .n_voltages = 26, + .linear_ranges = buck_volt_ranges, + .n_linear_ranges = ARRAY_SIZE(buck_volt_ranges), .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, .enable_reg = LP8788_EN_BUCK, @@ -397,8 +397,9 @@ static struct regulator_desc lp8788_buck_desc[] = { .name = "buck3", .id = BUCK3, .ops = &lp8788_buck34_ops, - .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), - .volt_table = lp8788_buck_vtbl, + .n_voltages = 26, + .linear_ranges = buck_volt_ranges, + .n_linear_ranges = ARRAY_SIZE(buck_volt_ranges), .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, .vsel_reg = LP8788_BUCK3_VOUT, @@ -410,8 +411,9 @@ static struct regulator_desc lp8788_buck_desc[] = { .name = "buck4", .id = BUCK4, .ops = &lp8788_buck34_ops, - .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl), - .volt_table = lp8788_buck_vtbl, + .n_voltages = 26, + .linear_ranges = buck_volt_ranges, + .n_linear_ranges = ARRAY_SIZE(buck_volt_ranges), .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, .vsel_reg = LP8788_BUCK4_VOUT, diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c index 553b4790050f..a2ef146e6b3a 100644 --- a/drivers/regulator/lp8788-ldo.c +++ b/drivers/regulator/lp8788-ldo.c @@ -186,7 +186,7 @@ static const struct regulator_ops lp8788_ldo_voltage_fixed_ops = { .enable_time = lp8788_ldo_enable_time, }; -static struct regulator_desc lp8788_dldo_desc[] = { +static const struct regulator_desc lp8788_dldo_desc[] = { { .name = "dldo1", .id = DLDO1, @@ -343,7 +343,7 @@ static struct regulator_desc lp8788_dldo_desc[] = { }, }; -static struct regulator_desc lp8788_aldo_desc[] = { +static const struct regulator_desc lp8788_aldo_desc[] = { { .name = "aldo1", .id = ALDO1, @@ -501,8 +501,12 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev, return 0; } - /* FIXME: check default mode for GPIO here: high or low? */ - ldo->ena_gpiod = devm_gpiod_get_index_optional(&pdev->dev, + /* + * Do not use devm* here: the regulator core takes over the + * lifecycle management of the GPIO descriptor. + * FIXME: check default mode for GPIO here: high or low? + */ + ldo->ena_gpiod = gpiod_get_index_optional(&pdev->dev, "enable", enable_id, GPIOD_OUT_HIGH | diff --git a/drivers/regulator/ltc3676.c b/drivers/regulator/ltc3676.c index 71fd0f2a4b76..e6d66e492b85 100644 --- a/drivers/regulator/ltc3676.c +++ b/drivers/regulator/ltc3676.c @@ -241,61 +241,10 @@ static struct regulator_desc ltc3676_regulators[LTC3676_NUM_REGULATORS] = { LTC3676_FIXED_REG(LDO4, ldo4, LDOB, 2), }; -static bool ltc3676_writeable_reg(struct device *dev, unsigned int reg) +static bool ltc3676_readable_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { - case LTC3676_IRQSTAT: - case LTC3676_BUCK1: - case LTC3676_BUCK2: - case LTC3676_BUCK3: - case LTC3676_BUCK4: - case LTC3676_LDOA: - case LTC3676_LDOB: - case LTC3676_SQD1: - case LTC3676_SQD2: - case LTC3676_CNTRL: - case LTC3676_DVB1A: - case LTC3676_DVB1B: - case LTC3676_DVB2A: - case LTC3676_DVB2B: - case LTC3676_DVB3A: - case LTC3676_DVB3B: - case LTC3676_DVB4A: - case LTC3676_DVB4B: - case LTC3676_MSKIRQ: - case LTC3676_MSKPG: - case LTC3676_USER: - case LTC3676_HRST: - case LTC3676_CLIRQ: - return true; - } - return false; -} - -static bool ltc3676_readable_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case LTC3676_IRQSTAT: - case LTC3676_BUCK1: - case LTC3676_BUCK2: - case LTC3676_BUCK3: - case LTC3676_BUCK4: - case LTC3676_LDOA: - case LTC3676_LDOB: - case LTC3676_SQD1: - case LTC3676_SQD2: - case LTC3676_CNTRL: - case LTC3676_DVB1A: - case LTC3676_DVB1B: - case LTC3676_DVB2A: - case LTC3676_DVB2B: - case LTC3676_DVB3A: - case LTC3676_DVB3B: - case LTC3676_DVB4A: - case LTC3676_DVB4B: - case LTC3676_MSKIRQ: - case LTC3676_MSKPG: - case LTC3676_USER: + case LTC3676_BUCK1 ... LTC3676_IRQSTAT: case LTC3676_HRST: case LTC3676_CLIRQ: return true; @@ -306,9 +255,7 @@ static bool ltc3676_readable_reg(struct device *dev, unsigned int reg) static bool ltc3676_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { - case LTC3676_IRQSTAT: - case LTC3676_PGSTATL: - case LTC3676_PGSTATRT: + case LTC3676_IRQSTAT ... LTC3676_PGSTATRT: return true; } return false; @@ -317,8 +264,8 @@ static bool ltc3676_volatile_reg(struct device *dev, unsigned int reg) static const struct regmap_config ltc3676_regmap_config = { .reg_bits = 8, .val_bits = 8, - .writeable_reg = ltc3676_writeable_reg, - .readable_reg = ltc3676_readable_reg, + .writeable_reg = ltc3676_readable_writeable_reg, + .readable_reg = ltc3676_readable_writeable_reg, .volatile_reg = ltc3676_volatile_reg, .max_register = LTC3676_CLIRQ, .use_single_read = true, @@ -442,5 +389,5 @@ static struct i2c_driver ltc3676_driver = { module_i2c_driver(ltc3676_driver); MODULE_AUTHOR("Tim Harvey <tharvey@gateworks.com>"); -MODULE_DESCRIPTION("Regulator driver for Linear Technology LTC1376"); +MODULE_DESCRIPTION("Regulator driver for Linear Technology LTC3676"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/max14577-regulator.c b/drivers/regulator/max14577-regulator.c index bc7f4751bf9c..85a88a9e4d42 100644 --- a/drivers/regulator/max14577-regulator.c +++ b/drivers/regulator/max14577-regulator.c @@ -324,4 +324,3 @@ module_exit(max14577_regulator_exit); MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>"); MODULE_DESCRIPTION("Maxim 14577/77836 regulator driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:max14577-regulator"); diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c index b94e3a721721..1607ac673e44 100644 --- a/drivers/regulator/max77620-regulator.c +++ b/drivers/regulator/max77620-regulator.c @@ -1,7 +1,7 @@ /* * Maxim MAX77620 Regulator driver * - * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved. * * Author: Mallikarjun Kasoju <mkasoju@nvidia.com> * Laxman Dewangan <ldewangan@nvidia.com> @@ -690,6 +690,7 @@ static const struct regulator_ops max77620_regulator_ops = { .active_discharge_mask = MAX77620_SD_CFG1_ADE_MASK, \ .active_discharge_reg = MAX77620_REG_##_id##_CFG, \ .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ }, \ } @@ -721,6 +722,7 @@ static const struct regulator_ops max77620_regulator_ops = { .active_discharge_mask = MAX77620_LDO_CFG2_ADE_MASK, \ .active_discharge_reg = MAX77620_REG_##_id##_CFG2, \ .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ }, \ } @@ -803,6 +805,14 @@ static int max77620_regulator_probe(struct platform_device *pdev) rdesc = &rinfo[id].desc; pmic->rinfo[id] = &max77620_regs_info[id]; pmic->enable_power_mode[id] = MAX77620_POWER_MODE_NORMAL; + pmic->reg_pdata[id].active_fps_src = -1; + pmic->reg_pdata[id].active_fps_pd_slot = -1; + pmic->reg_pdata[id].active_fps_pu_slot = -1; + pmic->reg_pdata[id].suspend_fps_src = -1; + pmic->reg_pdata[id].suspend_fps_pd_slot = -1; + pmic->reg_pdata[id].suspend_fps_pu_slot = -1; + pmic->reg_pdata[id].power_ok = -1; + pmic->reg_pdata[id].ramp_rate_setting = -1; ret = max77620_read_slew_rate(pmic, id); if (ret < 0) diff --git a/drivers/regulator/max77650-regulator.c b/drivers/regulator/max77650-regulator.c new file mode 100644 index 000000000000..31ebf34b01ec --- /dev/null +++ b/drivers/regulator/max77650-regulator.c @@ -0,0 +1,498 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2018 BayLibre SAS +// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> +// +// Regulator driver for MAXIM 77650/77651 charger/power-supply. + +#include <linux/of.h> +#include <linux/mfd/max77650.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> + +#define MAX77650_REGULATOR_EN_CTRL_MASK GENMASK(3, 0) +#define MAX77650_REGULATOR_EN_CTRL_BITS(_reg) \ + ((_reg) & MAX77650_REGULATOR_EN_CTRL_MASK) +#define MAX77650_REGULATOR_ENABLED GENMASK(2, 1) +#define MAX77650_REGULATOR_DISABLED BIT(2) + +#define MAX77650_REGULATOR_V_LDO_MASK GENMASK(6, 0) +#define MAX77650_REGULATOR_V_SBB_MASK GENMASK(5, 0) + +#define MAX77650_REGULATOR_AD_MASK BIT(3) +#define MAX77650_REGULATOR_AD_DISABLED 0x00 +#define MAX77650_REGULATOR_AD_ENABLED BIT(3) + +#define MAX77650_REGULATOR_CURR_LIM_MASK GENMASK(7, 6) + +enum { + MAX77650_REGULATOR_ID_LDO = 0, + MAX77650_REGULATOR_ID_SBB0, + MAX77650_REGULATOR_ID_SBB1, + MAX77650_REGULATOR_ID_SBB2, + MAX77650_REGULATOR_NUM_REGULATORS, +}; + +struct max77650_regulator_desc { + struct regulator_desc desc; + unsigned int regA; + unsigned int regB; +}; + +static const u32 max77651_sbb1_regulator_volt_table[] = { + 2400000, 3200000, 4000000, 4800000, + 2450000, 3250000, 4050000, 4850000, + 2500000, 3300000, 4100000, 4900000, + 2550000, 3350000, 4150000, 4950000, + 2600000, 3400000, 4200000, 5000000, + 2650000, 3450000, 4250000, 5050000, + 2700000, 3500000, 4300000, 5100000, + 2750000, 3550000, 4350000, 5150000, + 2800000, 3600000, 4400000, 5200000, + 2850000, 3650000, 4450000, 5250000, + 2900000, 3700000, 4500000, 0, + 2950000, 3750000, 4550000, 0, + 3000000, 3800000, 4600000, 0, + 3050000, 3850000, 4650000, 0, + 3100000, 3900000, 4700000, 0, + 3150000, 3950000, 4750000, 0, +}; + +#define MAX77651_REGULATOR_SBB1_SEL_DEC(_val) \ + (((_val & 0x3c) >> 2) | ((_val & 0x03) << 4)) +#define MAX77651_REGULATOR_SBB1_SEL_ENC(_val) \ + (((_val & 0x30) >> 4) | ((_val & 0x0f) << 2)) + +#define MAX77650_REGULATOR_SBB1_SEL_DECR(_val) \ + do { \ + _val = MAX77651_REGULATOR_SBB1_SEL_DEC(_val); \ + _val--; \ + _val = MAX77651_REGULATOR_SBB1_SEL_ENC(_val); \ + } while (0) + +#define MAX77650_REGULATOR_SBB1_SEL_INCR(_val) \ + do { \ + _val = MAX77651_REGULATOR_SBB1_SEL_DEC(_val); \ + _val++; \ + _val = MAX77651_REGULATOR_SBB1_SEL_ENC(_val); \ + } while (0) + +static const unsigned int max77650_current_limit_table[] = { + 1000000, 866000, 707000, 500000, +}; + +static int max77650_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct max77650_regulator_desc *rdesc; + struct regmap *map; + int val, rv, en; + + rdesc = rdev_get_drvdata(rdev); + map = rdev_get_regmap(rdev); + + rv = regmap_read(map, rdesc->regB, &val); + if (rv) + return rv; + + en = MAX77650_REGULATOR_EN_CTRL_BITS(val); + + return en != MAX77650_REGULATOR_DISABLED; +} + +static int max77650_regulator_enable(struct regulator_dev *rdev) +{ + struct max77650_regulator_desc *rdesc; + struct regmap *map; + + rdesc = rdev_get_drvdata(rdev); + map = rdev_get_regmap(rdev); + + return regmap_update_bits(map, rdesc->regB, + MAX77650_REGULATOR_EN_CTRL_MASK, + MAX77650_REGULATOR_ENABLED); +} + +static int max77650_regulator_disable(struct regulator_dev *rdev) +{ + struct max77650_regulator_desc *rdesc; + struct regmap *map; + + rdesc = rdev_get_drvdata(rdev); + map = rdev_get_regmap(rdev); + + return regmap_update_bits(map, rdesc->regB, + MAX77650_REGULATOR_EN_CTRL_MASK, + MAX77650_REGULATOR_DISABLED); +} + +static int max77650_regulator_set_voltage_sel(struct regulator_dev *rdev, + unsigned int sel) +{ + int rv = 0, curr, diff; + bool ascending; + + /* + * If the regulator is disabled, we can program the desired + * voltage right away. + */ + if (!max77650_regulator_is_enabled(rdev)) + return regulator_set_voltage_sel_regmap(rdev, sel); + + /* + * Otherwise we need to manually ramp the output voltage up/down + * one step at a time. + */ + + curr = regulator_get_voltage_sel_regmap(rdev); + if (curr < 0) + return curr; + + diff = curr - sel; + if (diff == 0) + return 0; /* Already there. */ + else if (diff > 0) + ascending = false; + else + ascending = true; + + /* + * Make sure we'll get to the right voltage and break the loop even if + * the selector equals 0. + */ + for (ascending ? curr++ : curr--;; ascending ? curr++ : curr--) { + rv = regulator_set_voltage_sel_regmap(rdev, curr); + if (rv) + return rv; + + if (curr == sel) + break; + } + + return 0; +} + +/* + * Special case: non-linear voltage table for max77651 SBB1 - software + * must ensure the voltage is ramped in 50mV increments. + */ +static int max77651_regulator_sbb1_set_voltage_sel(struct regulator_dev *rdev, + unsigned int sel) +{ + int rv = 0, curr, vcurr, vdest, vdiff; + + /* + * If the regulator is disabled, we can program the desired + * voltage right away. + */ + if (!max77650_regulator_is_enabled(rdev)) + return regulator_set_voltage_sel_regmap(rdev, sel); + + curr = regulator_get_voltage_sel_regmap(rdev); + if (curr < 0) + return curr; + + if (curr == sel) + return 0; /* Already there. */ + + vcurr = max77651_sbb1_regulator_volt_table[curr]; + vdest = max77651_sbb1_regulator_volt_table[sel]; + vdiff = vcurr - vdest; + + for (;;) { + if (vdiff > 0) + MAX77650_REGULATOR_SBB1_SEL_DECR(curr); + else + MAX77650_REGULATOR_SBB1_SEL_INCR(curr); + + rv = regulator_set_voltage_sel_regmap(rdev, curr); + if (rv) + return rv; + + if (curr == sel) + break; + }; + + return 0; +} + +static const struct regulator_ops max77650_regulator_LDO_ops = { + .is_enabled = max77650_regulator_is_enabled, + .enable = max77650_regulator_enable, + .disable = max77650_regulator_disable, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = max77650_regulator_set_voltage_sel, + .set_active_discharge = regulator_set_active_discharge_regmap, +}; + +static const struct regulator_ops max77650_regulator_SBB_ops = { + .is_enabled = max77650_regulator_is_enabled, + .enable = max77650_regulator_enable, + .disable = max77650_regulator_disable, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = max77650_regulator_set_voltage_sel, + .get_current_limit = regulator_get_current_limit_regmap, + .set_current_limit = regulator_set_current_limit_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, +}; + +/* Special case for max77651 SBB1 - non-linear voltage mapping. */ +static const struct regulator_ops max77651_SBB1_regulator_ops = { + .is_enabled = max77650_regulator_is_enabled, + .enable = max77650_regulator_enable, + .disable = max77650_regulator_disable, + .list_voltage = regulator_list_voltage_table, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = max77651_regulator_sbb1_set_voltage_sel, + .get_current_limit = regulator_get_current_limit_regmap, + .set_current_limit = regulator_set_current_limit_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, +}; + +static struct max77650_regulator_desc max77650_LDO_desc = { + .desc = { + .name = "ldo", + .of_match = of_match_ptr("ldo"), + .regulators_node = of_match_ptr("regulators"), + .supply_name = "in-ldo", + .id = MAX77650_REGULATOR_ID_LDO, + .ops = &max77650_regulator_LDO_ops, + .min_uV = 1350000, + .uV_step = 12500, + .n_voltages = 128, + .vsel_mask = MAX77650_REGULATOR_V_LDO_MASK, + .vsel_reg = MAX77650_REG_CNFG_LDO_A, + .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, + .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED, + .active_discharge_mask = MAX77650_REGULATOR_AD_MASK, + .active_discharge_reg = MAX77650_REG_CNFG_LDO_B, + .enable_time = 100, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + .regA = MAX77650_REG_CNFG_LDO_A, + .regB = MAX77650_REG_CNFG_LDO_B, +}; + +static struct max77650_regulator_desc max77650_SBB0_desc = { + .desc = { + .name = "sbb0", + .of_match = of_match_ptr("sbb0"), + .regulators_node = of_match_ptr("regulators"), + .supply_name = "in-sbb0", + .id = MAX77650_REGULATOR_ID_SBB0, + .ops = &max77650_regulator_SBB_ops, + .min_uV = 800000, + .uV_step = 25000, + .n_voltages = 64, + .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, + .vsel_reg = MAX77650_REG_CNFG_SBB0_A, + .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, + .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED, + .active_discharge_mask = MAX77650_REGULATOR_AD_MASK, + .active_discharge_reg = MAX77650_REG_CNFG_SBB0_B, + .enable_time = 100, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .csel_reg = MAX77650_REG_CNFG_SBB0_A, + .csel_mask = MAX77650_REGULATOR_CURR_LIM_MASK, + .curr_table = max77650_current_limit_table, + .n_current_limits = ARRAY_SIZE(max77650_current_limit_table), + }, + .regA = MAX77650_REG_CNFG_SBB0_A, + .regB = MAX77650_REG_CNFG_SBB0_B, +}; + +static struct max77650_regulator_desc max77650_SBB1_desc = { + .desc = { + .name = "sbb1", + .of_match = of_match_ptr("sbb1"), + .regulators_node = of_match_ptr("regulators"), + .supply_name = "in-sbb1", + .id = MAX77650_REGULATOR_ID_SBB1, + .ops = &max77650_regulator_SBB_ops, + .min_uV = 800000, + .uV_step = 12500, + .n_voltages = 64, + .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, + .vsel_reg = MAX77650_REG_CNFG_SBB1_A, + .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, + .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED, + .active_discharge_mask = MAX77650_REGULATOR_AD_MASK, + .active_discharge_reg = MAX77650_REG_CNFG_SBB1_B, + .enable_time = 100, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .csel_reg = MAX77650_REG_CNFG_SBB1_A, + .csel_mask = MAX77650_REGULATOR_CURR_LIM_MASK, + .curr_table = max77650_current_limit_table, + .n_current_limits = ARRAY_SIZE(max77650_current_limit_table), + }, + .regA = MAX77650_REG_CNFG_SBB1_A, + .regB = MAX77650_REG_CNFG_SBB1_B, +}; + +static struct max77650_regulator_desc max77651_SBB1_desc = { + .desc = { + .name = "sbb1", + .of_match = of_match_ptr("sbb1"), + .regulators_node = of_match_ptr("regulators"), + .supply_name = "in-sbb1", + .id = MAX77650_REGULATOR_ID_SBB1, + .ops = &max77651_SBB1_regulator_ops, + .volt_table = max77651_sbb1_regulator_volt_table, + .n_voltages = ARRAY_SIZE(max77651_sbb1_regulator_volt_table), + .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, + .vsel_reg = MAX77650_REG_CNFG_SBB1_A, + .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, + .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED, + .active_discharge_mask = MAX77650_REGULATOR_AD_MASK, + .active_discharge_reg = MAX77650_REG_CNFG_SBB1_B, + .enable_time = 100, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .csel_reg = MAX77650_REG_CNFG_SBB1_A, + .csel_mask = MAX77650_REGULATOR_CURR_LIM_MASK, + .curr_table = max77650_current_limit_table, + .n_current_limits = ARRAY_SIZE(max77650_current_limit_table), + }, + .regA = MAX77650_REG_CNFG_SBB1_A, + .regB = MAX77650_REG_CNFG_SBB1_B, +}; + +static struct max77650_regulator_desc max77650_SBB2_desc = { + .desc = { + .name = "sbb2", + .of_match = of_match_ptr("sbb2"), + .regulators_node = of_match_ptr("regulators"), + .supply_name = "in-sbb0", + .id = MAX77650_REGULATOR_ID_SBB2, + .ops = &max77650_regulator_SBB_ops, + .min_uV = 800000, + .uV_step = 50000, + .n_voltages = 64, + .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, + .vsel_reg = MAX77650_REG_CNFG_SBB2_A, + .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, + .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED, + .active_discharge_mask = MAX77650_REGULATOR_AD_MASK, + .active_discharge_reg = MAX77650_REG_CNFG_SBB2_B, + .enable_time = 100, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .csel_reg = MAX77650_REG_CNFG_SBB2_A, + .csel_mask = MAX77650_REGULATOR_CURR_LIM_MASK, + .curr_table = max77650_current_limit_table, + .n_current_limits = ARRAY_SIZE(max77650_current_limit_table), + }, + .regA = MAX77650_REG_CNFG_SBB2_A, + .regB = MAX77650_REG_CNFG_SBB2_B, +}; + +static struct max77650_regulator_desc max77651_SBB2_desc = { + .desc = { + .name = "sbb2", + .of_match = of_match_ptr("sbb2"), + .regulators_node = of_match_ptr("regulators"), + .supply_name = "in-sbb0", + .id = MAX77650_REGULATOR_ID_SBB2, + .ops = &max77650_regulator_SBB_ops, + .min_uV = 2400000, + .uV_step = 50000, + .n_voltages = 64, + .vsel_mask = MAX77650_REGULATOR_V_SBB_MASK, + .vsel_reg = MAX77650_REG_CNFG_SBB2_A, + .active_discharge_off = MAX77650_REGULATOR_AD_DISABLED, + .active_discharge_on = MAX77650_REGULATOR_AD_ENABLED, + .active_discharge_mask = MAX77650_REGULATOR_AD_MASK, + .active_discharge_reg = MAX77650_REG_CNFG_SBB2_B, + .enable_time = 100, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .csel_reg = MAX77650_REG_CNFG_SBB2_A, + .csel_mask = MAX77650_REGULATOR_CURR_LIM_MASK, + .curr_table = max77650_current_limit_table, + .n_current_limits = ARRAY_SIZE(max77650_current_limit_table), + }, + .regA = MAX77650_REG_CNFG_SBB2_A, + .regB = MAX77650_REG_CNFG_SBB2_B, +}; + +static int max77650_regulator_probe(struct platform_device *pdev) +{ + struct max77650_regulator_desc **rdescs; + struct max77650_regulator_desc *rdesc; + struct regulator_config config = { }; + struct device *dev, *parent; + struct regulator_dev *rdev; + struct regmap *map; + unsigned int val; + int i, rv; + + dev = &pdev->dev; + parent = dev->parent; + + if (!dev->of_node) + dev->of_node = parent->of_node; + + rdescs = devm_kcalloc(dev, MAX77650_REGULATOR_NUM_REGULATORS, + sizeof(*rdescs), GFP_KERNEL); + if (!rdescs) + return -ENOMEM; + + map = dev_get_regmap(parent, NULL); + if (!map) + return -ENODEV; + + rv = regmap_read(map, MAX77650_REG_CID, &val); + if (rv) + return rv; + + rdescs[MAX77650_REGULATOR_ID_LDO] = &max77650_LDO_desc; + rdescs[MAX77650_REGULATOR_ID_SBB0] = &max77650_SBB0_desc; + + switch (MAX77650_CID_BITS(val)) { + case MAX77650_CID_77650A: + case MAX77650_CID_77650C: + rdescs[MAX77650_REGULATOR_ID_SBB1] = &max77650_SBB1_desc; + rdescs[MAX77650_REGULATOR_ID_SBB2] = &max77650_SBB2_desc; + break; + case MAX77650_CID_77651A: + case MAX77650_CID_77651B: + rdescs[MAX77650_REGULATOR_ID_SBB1] = &max77651_SBB1_desc; + rdescs[MAX77650_REGULATOR_ID_SBB2] = &max77651_SBB2_desc; + break; + default: + return -ENODEV; + } + + config.dev = parent; + + for (i = 0; i < MAX77650_REGULATOR_NUM_REGULATORS; i++) { + rdesc = rdescs[i]; + config.driver_data = rdesc; + + rdev = devm_regulator_register(dev, &rdesc->desc, &config); + if (IS_ERR(rdev)) + return PTR_ERR(rdev); + } + + return 0; +} + +static struct platform_driver max77650_regulator_driver = { + .driver = { + .name = "max77650-regulator", + }, + .probe = max77650_regulator_probe, +}; +module_platform_driver(max77650_regulator_driver); + +MODULE_DESCRIPTION("MAXIM 77650/77651 regulator driver"); +MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/max77686-regulator.c b/drivers/regulator/max77686-regulator.c index bee060937f56..8020eb57374a 100644 --- a/drivers/regulator/max77686-regulator.c +++ b/drivers/regulator/max77686-regulator.c @@ -11,8 +11,7 @@ #include <linux/kernel.h> #include <linux/bug.h> #include <linux/err.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> @@ -76,6 +75,7 @@ enum max77686_ramp_rate { }; struct max77686_data { + struct device *dev; DECLARE_BITMAP(gpio_enabled, MAX77686_REGULATORS); /* Array indexed by regulator id */ @@ -250,26 +250,34 @@ static int max77686_of_parse_cb(struct device_node *np, struct regulator_config *config) { struct max77686_data *max77686 = config->driver_data; + int ret; switch (desc->id) { case MAX77686_BUCK8: case MAX77686_BUCK9: case MAX77686_LDO20 ... MAX77686_LDO22: - config->ena_gpio = of_get_named_gpio(np, - "maxim,ena-gpios", 0); - config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH; - config->ena_gpio_initialized = true; + config->ena_gpiod = gpiod_get_from_of_node(np, + "maxim,ena", + 0, + GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, + "max77686-regulator"); + if (IS_ERR(config->ena_gpiod)) + config->ena_gpiod = NULL; break; default: return 0; } - if (gpio_is_valid(config->ena_gpio)) { + if (config->ena_gpiod) { set_bit(desc->id, max77686->gpio_enabled); - return regmap_update_bits(config->regmap, desc->enable_reg, - desc->enable_mask, - MAX77686_GPIO_CONTROL); + ret = regmap_update_bits(config->regmap, desc->enable_reg, + desc->enable_mask, + MAX77686_GPIO_CONTROL); + if (ret) { + gpiod_put(config->ena_gpiod); + config->ena_gpiod = NULL; + } } return 0; @@ -507,6 +515,7 @@ static int max77686_pmic_probe(struct platform_device *pdev) if (!max77686) return -ENOMEM; + max77686->dev = &pdev->dev; config.dev = iodev->dev; config.regmap = iodev->regmap; config.driver_data = max77686; diff --git a/drivers/regulator/max77802-regulator.c b/drivers/regulator/max77802-regulator.c index c30cf5c9f2de..ea7b50397300 100644 --- a/drivers/regulator/max77802-regulator.c +++ b/drivers/regulator/max77802-regulator.c @@ -248,9 +248,9 @@ static int max77802_set_ramp_delay_2bit(struct regulator_dev *rdev, unsigned int ramp_value; if (id > MAX77802_BUCK4) { - dev_warn(&rdev->dev, - "%s: regulator: ramp delay not supported\n", - rdev->desc->name); + dev_warn(&rdev->dev, + "%s: regulator: ramp delay not supported\n", + rdev->desc->name); return -EINVAL; } ramp_value = max77802_find_ramp_value(rdev, ramp_table_77802_2bit, diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 6c39fff73b8a..cf2a2912cb1b 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -231,9 +231,13 @@ static int max8952_pmic_probe(struct i2c_client *client, else gflags = GPIOD_OUT_LOW; gflags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE; - gpiod = devm_gpiod_get_optional(&client->dev, - "max8952,en", - gflags); + /* + * Do not use devm* here: the regulator core takes over the + * lifecycle management of the GPIO descriptor. + */ + gpiod = gpiod_get_optional(&client->dev, + "max8952,en", + gflags); if (IS_ERR(gpiod)) return PTR_ERR(gpiod); if (gpiod) diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index e7a58b509032..9aee1444181d 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -808,7 +808,13 @@ static int max8973_probe(struct i2c_client *client, config.of_node = client->dev.of_node; config.regmap = max->regmap; - /* Register the regulators */ + /* + * Register the regulators + * Turn the GPIO descriptor over to the regulator core for + * lifecycle management if we pass an ena_gpiod. + */ + if (config.ena_gpiod) + devm_gpiod_unhinge(&client->dev, config.ena_gpiod); rdev = devm_regulator_register(&client->dev, &max->desc, &config); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); diff --git a/drivers/regulator/max8997-regulator.c b/drivers/regulator/max8997-regulator.c index 3bf5ddfaaea8..4d2487279a0a 100644 --- a/drivers/regulator/max8997-regulator.c +++ b/drivers/regulator/max8997-regulator.c @@ -925,7 +925,7 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev, pdata->regulators = rdata; for_each_child_of_node(regulators_np, reg_np) { for (i = 0; i < ARRAY_SIZE(regulators); i++) - if (!of_node_cmp(reg_np->name, regulators[i].name)) + if (of_node_name_eq(reg_np, regulators[i].name)) break; if (i == ARRAY_SIZE(regulators)) { diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 8fd1adc9c9a9..ab558b26cd7c 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -226,69 +226,69 @@ static const unsigned int mc13783_pwgtdrv_val[] = { 5500000, }; -static struct regulator_ops mc13783_gpo_regulator_ops; +static const struct regulator_ops mc13783_gpo_regulator_ops; -#define MC13783_DEFINE(prefix, name, reg, vsel_reg, voltages) \ - MC13xxx_DEFINE(MC13783_REG_, name, reg, vsel_reg, voltages, \ +#define MC13783_DEFINE(prefix, name, node, reg, vsel_reg, voltages) \ + MC13xxx_DEFINE(MC13783_REG_, name, node, reg, vsel_reg, voltages, \ mc13xxx_regulator_ops) -#define MC13783_FIXED_DEFINE(prefix, name, reg, voltages) \ - MC13xxx_FIXED_DEFINE(MC13783_REG_, name, reg, voltages, \ +#define MC13783_FIXED_DEFINE(prefix, name, node, reg, voltages) \ + MC13xxx_FIXED_DEFINE(MC13783_REG_, name, node, reg, voltages, \ mc13xxx_fixed_regulator_ops) -#define MC13783_GPO_DEFINE(prefix, name, reg, voltages) \ - MC13xxx_GPO_DEFINE(MC13783_REG_, name, reg, voltages, \ +#define MC13783_GPO_DEFINE(prefix, name, node, reg, voltages) \ + MC13xxx_GPO_DEFINE(MC13783_REG_, name, node, reg, voltages, \ mc13783_gpo_regulator_ops) -#define MC13783_DEFINE_SW(_name, _reg, _vsel_reg, _voltages) \ - MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages) -#define MC13783_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages) \ - MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages) +#define MC13783_DEFINE_SW(_name, _node, _reg, _vsel_reg, _voltages) \ + MC13783_DEFINE(REG, _name, _node, _reg, _vsel_reg, _voltages) +#define MC13783_DEFINE_REGU(_name, _node, _reg, _vsel_reg, _voltages) \ + MC13783_DEFINE(REG, _name, _node, _reg, _vsel_reg, _voltages) static struct mc13xxx_regulator mc13783_regulators[] = { - MC13783_DEFINE_SW(SW1A, SWITCHERS0, SWITCHERS0, mc13783_sw1x_val), - MC13783_DEFINE_SW(SW1B, SWITCHERS1, SWITCHERS1, mc13783_sw1x_val), - MC13783_DEFINE_SW(SW2A, SWITCHERS2, SWITCHERS2, mc13783_sw2x_val), - MC13783_DEFINE_SW(SW2B, SWITCHERS3, SWITCHERS3, mc13783_sw2x_val), - MC13783_DEFINE_SW(SW3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val), - - 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_SW(SW1A, sw1a, SWITCHERS0, SWITCHERS0, mc13783_sw1x_val), + MC13783_DEFINE_SW(SW1B, sw1b, SWITCHERS1, SWITCHERS1, mc13783_sw1x_val), + MC13783_DEFINE_SW(SW2A, sw2a, SWITCHERS2, SWITCHERS2, mc13783_sw2x_val), + MC13783_DEFINE_SW(SW2B, sw2b, SWITCHERS3, SWITCHERS3, mc13783_sw2x_val), + MC13783_DEFINE_SW(SW3, sw3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val), + + MC13783_FIXED_DEFINE(REG, VAUDIO, vaudio, REGULATORMODE0, mc13783_vaudio_val), + MC13783_FIXED_DEFINE(REG, VIOHI, viohi, REGULATORMODE0, mc13783_viohi_val), + MC13783_DEFINE_REGU(VIOLO, violo, REGULATORMODE0, REGULATORSETTING0, mc13783_violo_val), - MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, + MC13783_DEFINE_REGU(VDIG, vdig, REGULATORMODE0, REGULATORSETTING0, mc13783_vdig_val), - MC13783_DEFINE_REGU(VGEN, REGULATORMODE0, REGULATORSETTING0, + MC13783_DEFINE_REGU(VGEN, vgen, REGULATORMODE0, REGULATORSETTING0, mc13783_vgen_val), - MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0, REGULATORSETTING0, + MC13783_DEFINE_REGU(VRFDIG, vrfdig, REGULATORMODE0, REGULATORSETTING0, mc13783_vrfdig_val), - MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0, REGULATORSETTING0, + MC13783_DEFINE_REGU(VRFREF, vrfref, REGULATORMODE0, REGULATORSETTING0, mc13783_vrfref_val), - MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0, REGULATORSETTING0, + MC13783_DEFINE_REGU(VRFCP, vrfcp, REGULATORMODE0, REGULATORSETTING0, mc13783_vrfcp_val), - MC13783_DEFINE_REGU(VSIM, REGULATORMODE1, REGULATORSETTING0, + MC13783_DEFINE_REGU(VSIM, vsim, REGULATORMODE1, REGULATORSETTING0, mc13783_vsim_val), - MC13783_DEFINE_REGU(VESIM, REGULATORMODE1, REGULATORSETTING0, + MC13783_DEFINE_REGU(VESIM, vesim, REGULATORMODE1, REGULATORSETTING0, mc13783_vesim_val), - MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, + MC13783_DEFINE_REGU(VCAM, vcam, REGULATORMODE1, REGULATORSETTING0, mc13783_vcam_val), - MC13783_FIXED_DEFINE(REG, VRFBG, REGULATORMODE1, mc13783_vrfbg_val), - MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1, + MC13783_FIXED_DEFINE(REG, VRFBG, vrfbg, REGULATORMODE1, mc13783_vrfbg_val), + MC13783_DEFINE_REGU(VVIB, vvib, REGULATORMODE1, REGULATORSETTING1, mc13783_vvib_val), - MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1, + MC13783_DEFINE_REGU(VRF1, vrf1, REGULATORMODE1, REGULATORSETTING1, mc13783_vrf_val), - MC13783_DEFINE_REGU(VRF2, REGULATORMODE1, REGULATORSETTING1, + MC13783_DEFINE_REGU(VRF2, vrf2, REGULATORMODE1, REGULATORSETTING1, mc13783_vrf_val), - MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1, REGULATORSETTING1, + MC13783_DEFINE_REGU(VMMC1, vmmc1, REGULATORMODE1, REGULATORSETTING1, mc13783_vmmc_val), - MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1, + MC13783_DEFINE_REGU(VMMC2, vmmc2, REGULATORMODE1, REGULATORSETTING1, mc13783_vmmc_val), - MC13783_GPO_DEFINE(REG, GPO1, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REG, GPO2, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REG, GPO3, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REG, GPO4, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REG, PWGT1SPI, POWERMISC, mc13783_pwgtdrv_val), - MC13783_GPO_DEFINE(REG, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val), + MC13783_GPO_DEFINE(REG, GPO1, gpo1, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, GPO2, gpo1, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, GPO3, gpo1, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, GPO4, gpo1, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, PWGT1SPI, pwgt1spi, POWERMISC, mc13783_pwgtdrv_val), + MC13783_GPO_DEFINE(REG, PWGT2SPI, pwgt2spi, POWERMISC, mc13783_pwgtdrv_val), }; static int mc13783_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, @@ -380,7 +380,7 @@ static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev) return (val & mc13xxx_regulators[id].enable_bit) != 0; } -static struct regulator_ops mc13783_gpo_regulator_ops = { +static const struct regulator_ops mc13783_gpo_regulator_ops = { .enable = mc13783_gpo_regulator_enable, .disable = mc13783_gpo_regulator_disable, .is_enabled = mc13783_gpo_regulator_is_enabled, diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index f3fba1cc1379..a731e826a037 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -242,61 +242,61 @@ static const unsigned int mc13892_pwgtdrv[] = { 5000000, }; -static struct regulator_ops mc13892_gpo_regulator_ops; -static struct regulator_ops mc13892_sw_regulator_ops; +static const struct regulator_ops mc13892_gpo_regulator_ops; +static const struct regulator_ops mc13892_sw_regulator_ops; -#define MC13892_FIXED_DEFINE(name, reg, voltages) \ - MC13xxx_FIXED_DEFINE(MC13892_, name, reg, voltages, \ +#define MC13892_FIXED_DEFINE(name, node, reg, voltages) \ + MC13xxx_FIXED_DEFINE(MC13892_, name, node, reg, voltages, \ mc13xxx_fixed_regulator_ops) -#define MC13892_GPO_DEFINE(name, reg, voltages) \ - MC13xxx_GPO_DEFINE(MC13892_, name, reg, voltages, \ +#define MC13892_GPO_DEFINE(name, node, reg, voltages) \ + MC13xxx_GPO_DEFINE(MC13892_, name, node, reg, voltages, \ mc13892_gpo_regulator_ops) -#define MC13892_SW_DEFINE(name, reg, vsel_reg, voltages) \ - MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \ +#define MC13892_SW_DEFINE(name, node, reg, vsel_reg, voltages) \ + MC13xxx_DEFINE(MC13892_, name, node, reg, vsel_reg, voltages, \ mc13892_sw_regulator_ops) -#define MC13892_DEFINE_REGU(name, reg, vsel_reg, voltages) \ - MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \ +#define MC13892_DEFINE_REGU(name, node, reg, vsel_reg, voltages) \ + MC13xxx_DEFINE(MC13892_, name, node, reg, vsel_reg, voltages, \ mc13xxx_regulator_ops) static struct mc13xxx_regulator mc13892_regulators[] = { - MC13892_DEFINE_REGU(VCOINCELL, POWERCTL0, POWERCTL0, mc13892_vcoincell), - MC13892_SW_DEFINE(SW1, SWITCHERS0, SWITCHERS0, mc13892_sw1), - MC13892_SW_DEFINE(SW2, SWITCHERS1, SWITCHERS1, mc13892_sw), - MC13892_SW_DEFINE(SW3, SWITCHERS2, SWITCHERS2, mc13892_sw), - MC13892_SW_DEFINE(SW4, SWITCHERS3, SWITCHERS3, mc13892_sw), - MC13892_FIXED_DEFINE(SWBST, SWITCHERS5, mc13892_swbst), - MC13892_FIXED_DEFINE(VIOHI, REGULATORMODE0, mc13892_viohi), - MC13892_DEFINE_REGU(VPLL, REGULATORMODE0, REGULATORSETTING0, + MC13892_DEFINE_REGU(VCOINCELL, vcoincell, POWERCTL0, POWERCTL0, mc13892_vcoincell), + MC13892_SW_DEFINE(SW1, sw1, SWITCHERS0, SWITCHERS0, mc13892_sw1), + MC13892_SW_DEFINE(SW2, sw2, SWITCHERS1, SWITCHERS1, mc13892_sw), + MC13892_SW_DEFINE(SW3, sw3, SWITCHERS2, SWITCHERS2, mc13892_sw), + MC13892_SW_DEFINE(SW4, sw4, SWITCHERS3, SWITCHERS3, mc13892_sw), + MC13892_FIXED_DEFINE(SWBST, swbst, SWITCHERS5, mc13892_swbst), + MC13892_FIXED_DEFINE(VIOHI, viohi, REGULATORMODE0, mc13892_viohi), + MC13892_DEFINE_REGU(VPLL, vpll, REGULATORMODE0, REGULATORSETTING0, mc13892_vpll), - MC13892_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, + MC13892_DEFINE_REGU(VDIG, vdig, REGULATORMODE0, REGULATORSETTING0, mc13892_vdig), - MC13892_DEFINE_REGU(VSD, REGULATORMODE1, REGULATORSETTING1, + MC13892_DEFINE_REGU(VSD, vsd, REGULATORMODE1, REGULATORSETTING1, mc13892_vsd), - MC13892_DEFINE_REGU(VUSB2, REGULATORMODE0, REGULATORSETTING0, + MC13892_DEFINE_REGU(VUSB2, vusb2, REGULATORMODE0, REGULATORSETTING0, mc13892_vusb2), - MC13892_DEFINE_REGU(VVIDEO, REGULATORMODE1, REGULATORSETTING1, + MC13892_DEFINE_REGU(VVIDEO, vvideo, REGULATORMODE1, REGULATORSETTING1, mc13892_vvideo), - MC13892_DEFINE_REGU(VAUDIO, REGULATORMODE1, REGULATORSETTING1, + MC13892_DEFINE_REGU(VAUDIO, vaudio, REGULATORMODE1, REGULATORSETTING1, mc13892_vaudio), - MC13892_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, + MC13892_DEFINE_REGU(VCAM, vcam, REGULATORMODE1, REGULATORSETTING0, mc13892_vcam), - MC13892_DEFINE_REGU(VGEN1, REGULATORMODE0, REGULATORSETTING0, + MC13892_DEFINE_REGU(VGEN1, vgen1, REGULATORMODE0, REGULATORSETTING0, mc13892_vgen1), - MC13892_DEFINE_REGU(VGEN2, REGULATORMODE0, REGULATORSETTING0, + MC13892_DEFINE_REGU(VGEN2, vgen2, REGULATORMODE0, REGULATORSETTING0, mc13892_vgen2), - MC13892_DEFINE_REGU(VGEN3, REGULATORMODE1, REGULATORSETTING0, + MC13892_DEFINE_REGU(VGEN3, vgen3, REGULATORMODE1, REGULATORSETTING0, mc13892_vgen3), - MC13892_FIXED_DEFINE(VUSB, USB1, mc13892_vusb), - MC13892_GPO_DEFINE(GPO1, POWERMISC, mc13892_gpo), - MC13892_GPO_DEFINE(GPO2, POWERMISC, mc13892_gpo), - MC13892_GPO_DEFINE(GPO3, POWERMISC, mc13892_gpo), - MC13892_GPO_DEFINE(GPO4, POWERMISC, mc13892_gpo), - MC13892_GPO_DEFINE(PWGT1SPI, POWERMISC, mc13892_pwgtdrv), - MC13892_GPO_DEFINE(PWGT2SPI, POWERMISC, mc13892_pwgtdrv), + MC13892_FIXED_DEFINE(VUSB, vusb, USB1, mc13892_vusb), + MC13892_GPO_DEFINE(GPO1, gpo1, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(GPO2, gpo2, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(GPO3, gpo3, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(GPO4, gpo4, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(PWGT1SPI, pwgt1spi, POWERMISC, mc13892_pwgtdrv), + MC13892_GPO_DEFINE(PWGT2SPI, pwgt2spi, POWERMISC, mc13892_pwgtdrv), }; static int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, @@ -387,7 +387,7 @@ static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev) } -static struct regulator_ops mc13892_gpo_regulator_ops = { +static const struct regulator_ops mc13892_gpo_regulator_ops = { .enable = mc13892_gpo_regulator_enable, .disable = mc13892_gpo_regulator_disable, .is_enabled = mc13892_gpo_regulator_is_enabled, @@ -479,7 +479,7 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev, return ret; } -static struct regulator_ops mc13892_sw_regulator_ops = { +static const struct regulator_ops mc13892_sw_regulator_ops = { .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = mc13892_sw_regulator_set_voltage_sel, diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index 65eb1e0350cf..8ff19150ca92 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -99,7 +99,7 @@ static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev) return rdev->desc->volt_table[val]; } -struct regulator_ops mc13xxx_regulator_ops = { +const struct regulator_ops mc13xxx_regulator_ops = { .enable = mc13xxx_regulator_enable, .disable = mc13xxx_regulator_disable, .is_enabled = mc13xxx_regulator_is_enabled, @@ -127,7 +127,7 @@ int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, } EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_set_voltage); -struct regulator_ops mc13xxx_fixed_regulator_ops = { +const struct regulator_ops mc13xxx_fixed_regulator_ops = { .enable = mc13xxx_regulator_enable, .disable = mc13xxx_regulator_disable, .is_enabled = mc13xxx_regulator_is_enabled, @@ -186,7 +186,7 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( for (i = 0; i < num_regulators; i++) { if (!regulators[i].desc.name) continue; - if (!of_node_cmp(child->name, + if (of_node_name_eq(child, regulators[i].desc.name)) { p->id = i; p->init_data = of_get_regulator_init_data( diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h index 2ab9bfd93b4e..ba7eff1070bd 100644 --- a/drivers/regulator/mc13xxx.h +++ b/drivers/regulator/mc13xxx.h @@ -53,13 +53,13 @@ static inline struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( } #endif -extern struct regulator_ops mc13xxx_regulator_ops; -extern struct regulator_ops mc13xxx_fixed_regulator_ops; +extern const struct regulator_ops mc13xxx_regulator_ops; +extern const struct regulator_ops mc13xxx_fixed_regulator_ops; -#define MC13xxx_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages, _ops) \ +#define MC13xxx_DEFINE(prefix, _name, _node, _reg, _vsel_reg, _voltages, _ops) \ [prefix ## _name] = { \ .desc = { \ - .name = #_name, \ + .name = #_node, \ .n_voltages = ARRAY_SIZE(_voltages), \ .volt_table = _voltages, \ .ops = &_ops, \ @@ -74,10 +74,10 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops; .vsel_mask = prefix ## _vsel_reg ## _ ## _name ## VSEL_M,\ } -#define MC13xxx_FIXED_DEFINE(prefix, _name, _reg, _voltages, _ops) \ +#define MC13xxx_FIXED_DEFINE(prefix, _name, _node, _reg, _voltages, _ops) \ [prefix ## _name] = { \ .desc = { \ - .name = #_name, \ + .name = #_node, \ .n_voltages = ARRAY_SIZE(_voltages), \ .volt_table = _voltages, \ .ops = &_ops, \ @@ -89,10 +89,10 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops; .enable_bit = prefix ## _reg ## _ ## _name ## EN, \ } -#define MC13xxx_GPO_DEFINE(prefix, _name, _reg, _voltages, _ops) \ +#define MC13xxx_GPO_DEFINE(prefix, _name, _node, _reg, _voltages, _ops) \ [prefix ## _name] = { \ .desc = { \ - .name = #_name, \ + .name = #_node, \ .n_voltages = ARRAY_SIZE(_voltages), \ .volt_table = _voltages, \ .ops = &_ops, \ @@ -104,9 +104,9 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops; .enable_bit = prefix ## _reg ## _ ## _name ## EN, \ } -#define MC13xxx_DEFINE_SW(_name, _reg, _vsel_reg, _voltages, ops) \ - MC13xxx_DEFINE(SW, _name, _reg, _vsel_reg, _voltages, ops) -#define MC13xxx_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages, ops) \ - MC13xxx_DEFINE(REGU, _name, _reg, _vsel_reg, _voltages, ops) +#define MC13xxx_DEFINE_SW(_name, _node, _reg, _vsel_reg, _voltages, ops) \ + MC13xxx_DEFINE(SW, _name, _node, _reg, _vsel_reg, _voltages, ops) +#define MC13xxx_DEFINE_REGU(_name, _node, _reg, _vsel_reg, _voltages, ops) \ + MC13xxx_DEFINE(REGU, _name, _node, _reg, _vsel_reg, _voltages, ops) #endif diff --git a/drivers/regulator/mcp16502.c b/drivers/regulator/mcp16502.c new file mode 100644 index 000000000000..3a8004abe044 --- /dev/null +++ b/drivers/regulator/mcp16502.c @@ -0,0 +1,552 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MCP16502 PMIC driver +// +// Copyright (C) 2018 Microchip Technology Inc. and its subsidiaries +// +// Author: Andrei Stefanescu <andrei.stefanescu@microchip.com> +// +// Inspired from tps65086-regulator.c + +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/suspend.h> +#include <linux/gpio/consumer.h> + +#define VDD_LOW_SEL 0x0D +#define VDD_HIGH_SEL 0x3F + +#define MCP16502_FLT BIT(7) +#define MCP16502_ENS BIT(0) + +/* + * The PMIC has four sets of registers corresponding to four power modes: + * Performance, Active, Low-power, Hibernate. + * + * Registers: + * Each regulator has a register for each power mode. To access a register + * for a specific regulator and mode BASE_* and OFFSET_* need to be added. + * + * Operating modes: + * In order for the PMIC to transition to operating modes it has to be + * controlled via GPIO lines called LPM and HPM. + * + * The registers are fully configurable such that you can put all regulators in + * a low-power state while the PMIC is in Active mode. They are supposed to be + * configured at startup and then simply transition to/from a global low-power + * state by setting the GPIO lpm pin high/low. + * + * This driver keeps the PMIC in Active mode, Low-power state is set for the + * regulators by enabling/disabling operating mode (FPWM or Auto PFM). + * + * The PMIC's Low-power and Hibernate modes are used during standby/suspend. + * To enter standby/suspend the PMIC will go to Low-power mode. From there, it + * will transition to Hibernate when the PWRHLD line is set to low by the MPU. + */ + +/* + * This function is useful for iterating over all regulators and accessing their + * registers in a generic way or accessing a regulator device by its id. + */ +#define MCP16502_BASE(i) (((i) + 1) << 4) +#define MCP16502_STAT_BASE(i) ((i) + 5) + +#define MCP16502_OFFSET_MODE_A 0 +#define MCP16502_OFFSET_MODE_LPM 1 +#define MCP16502_OFFSET_MODE_HIB 2 + +#define MCP16502_OPMODE_ACTIVE REGULATOR_MODE_NORMAL +#define MCP16502_OPMODE_LPM REGULATOR_MODE_IDLE +#define MCP16502_OPMODE_HIB REGULATOR_MODE_STANDBY + +#define MCP16502_MODE_AUTO_PFM 0 +#define MCP16502_MODE_FPWM BIT(6) + +#define MCP16502_VSEL 0x3F +#define MCP16502_EN BIT(7) +#define MCP16502_MODE BIT(6) + +#define MCP16502_MIN_REG 0x0 +#define MCP16502_MAX_REG 0x65 + +static unsigned int mcp16502_of_map_mode(unsigned int mode) +{ + if (mode == REGULATOR_MODE_NORMAL || mode == REGULATOR_MODE_IDLE) + return mode; + + return REGULATOR_MODE_INVALID; +} + +#define MCP16502_REGULATOR(_name, _id, _ranges, _ops) \ + [_id] = { \ + .name = _name, \ + .regulators_node = of_match_ptr("regulators"), \ + .id = _id, \ + .ops = &(_ops), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .n_voltages = MCP16502_VSEL + 1, \ + .linear_ranges = _ranges, \ + .n_linear_ranges = ARRAY_SIZE(_ranges), \ + .of_match = of_match_ptr(_name), \ + .of_map_mode = mcp16502_of_map_mode, \ + .vsel_reg = (((_id) + 1) << 4), \ + .vsel_mask = MCP16502_VSEL, \ + .enable_reg = (((_id) + 1) << 4), \ + .enable_mask = MCP16502_EN, \ + } + +enum { + BUCK1 = 0, + BUCK2, + BUCK3, + BUCK4, + LDO1, + LDO2, + NUM_REGULATORS +}; + +/* + * struct mcp16502 - PMIC representation + * @rdev: the regulators belonging to this chip + * @rmap: regmap to be used for I2C communication + * @lpm: LPM GPIO descriptor + */ +struct mcp16502 { + struct regulator_dev *rdev[NUM_REGULATORS]; + struct regmap *rmap; + struct gpio_desc *lpm; +}; + +/* + * mcp16502_gpio_set_mode() - set the GPIO corresponding value + * + * Used to prepare transitioning into hibernate or resuming from it. + */ +static void mcp16502_gpio_set_mode(struct mcp16502 *mcp, int mode) +{ + switch (mode) { + case MCP16502_OPMODE_ACTIVE: + gpiod_set_value(mcp->lpm, 0); + break; + case MCP16502_OPMODE_LPM: + case MCP16502_OPMODE_HIB: + gpiod_set_value(mcp->lpm, 1); + break; + default: + pr_err("%s: %d invalid\n", __func__, mode); + } +} + +/* + * mcp16502_get_reg() - get the PMIC's configuration register for opmode + * + * @rdev: the regulator whose register we are searching + * @opmode: the PMIC's operating mode ACTIVE, Low-power, Hibernate + */ +static int mcp16502_get_reg(struct regulator_dev *rdev, int opmode) +{ + int reg = MCP16502_BASE(rdev_get_id(rdev)); + + switch (opmode) { + case MCP16502_OPMODE_ACTIVE: + return reg + MCP16502_OFFSET_MODE_A; + case MCP16502_OPMODE_LPM: + return reg + MCP16502_OFFSET_MODE_LPM; + case MCP16502_OPMODE_HIB: + return reg + MCP16502_OFFSET_MODE_HIB; + default: + return -EINVAL; + } +} + +/* + * mcp16502_get_mode() - return the current operating mode of a regulator + * + * Note: all functions that are not part of entering/exiting standby/suspend + * use the Active mode registers. + * + * Note: this is different from the PMIC's operatig mode, it is the + * MODE bit from the regulator's register. + */ +static unsigned int mcp16502_get_mode(struct regulator_dev *rdev) +{ + unsigned int val; + int ret, reg; + struct mcp16502 *mcp = rdev_get_drvdata(rdev); + + reg = mcp16502_get_reg(rdev, MCP16502_OPMODE_ACTIVE); + if (reg < 0) + return reg; + + ret = regmap_read(mcp->rmap, reg, &val); + if (ret) + return ret; + + switch (val & MCP16502_MODE) { + case MCP16502_MODE_FPWM: + return REGULATOR_MODE_NORMAL; + case MCP16502_MODE_AUTO_PFM: + return REGULATOR_MODE_IDLE; + default: + return REGULATOR_MODE_INVALID; + } +} + +/* + * _mcp16502_set_mode() - helper for set_mode and set_suspend_mode + * + * @rdev: the regulator for which we are setting the mode + * @mode: the regulator's mode (the one from MODE bit) + * @opmode: the PMIC's operating mode: Active/Low-power/Hibernate + */ +static int _mcp16502_set_mode(struct regulator_dev *rdev, unsigned int mode, + unsigned int op_mode) +{ + int val; + int reg; + struct mcp16502 *mcp = rdev_get_drvdata(rdev); + + reg = mcp16502_get_reg(rdev, op_mode); + if (reg < 0) + return reg; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + val = MCP16502_MODE_FPWM; + break; + case REGULATOR_MODE_IDLE: + val = MCP16502_MODE_AUTO_PFM; + break; + default: + return -EINVAL; + } + + reg = regmap_update_bits(mcp->rmap, reg, MCP16502_MODE, val); + return reg; +} + +/* + * mcp16502_set_mode() - regulator_ops set_mode + */ +static int mcp16502_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + return _mcp16502_set_mode(rdev, mode, MCP16502_OPMODE_ACTIVE); +} + +/* + * mcp16502_get_status() - regulator_ops get_status + */ +static int mcp16502_get_status(struct regulator_dev *rdev) +{ + int ret; + unsigned int val; + struct mcp16502 *mcp = rdev_get_drvdata(rdev); + + ret = regmap_read(mcp->rmap, MCP16502_STAT_BASE(rdev_get_id(rdev)), + &val); + if (ret) + return ret; + + if (val & MCP16502_FLT) + return REGULATOR_STATUS_ERROR; + else if (val & MCP16502_ENS) + return REGULATOR_STATUS_ON; + else if (!(val & MCP16502_ENS)) + return REGULATOR_STATUS_OFF; + + return REGULATOR_STATUS_UNDEFINED; +} + +#ifdef CONFIG_SUSPEND +/* + * mcp16502_suspend_get_target_reg() - get the reg of the target suspend PMIC + * mode + */ +static int mcp16502_suspend_get_target_reg(struct regulator_dev *rdev) +{ + switch (pm_suspend_target_state) { + case PM_SUSPEND_STANDBY: + return mcp16502_get_reg(rdev, MCP16502_OPMODE_LPM); + case PM_SUSPEND_ON: + case PM_SUSPEND_MEM: + return mcp16502_get_reg(rdev, MCP16502_OPMODE_HIB); + default: + dev_err(&rdev->dev, "invalid suspend target: %d\n", + pm_suspend_target_state); + } + + return -EINVAL; +} + +/* + * mcp16502_set_suspend_voltage() - regulator_ops set_suspend_voltage + */ +static int mcp16502_set_suspend_voltage(struct regulator_dev *rdev, int uV) +{ + struct mcp16502 *mcp = rdev_get_drvdata(rdev); + int sel = regulator_map_voltage_linear_range(rdev, uV, uV); + int reg = mcp16502_suspend_get_target_reg(rdev); + + if (sel < 0) + return sel; + + if (reg < 0) + return reg; + + return regmap_update_bits(mcp->rmap, reg, MCP16502_VSEL, sel); +} + +/* + * mcp16502_set_suspend_mode() - regulator_ops set_suspend_mode + */ +static int mcp16502_set_suspend_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + switch (pm_suspend_target_state) { + case PM_SUSPEND_STANDBY: + return _mcp16502_set_mode(rdev, mode, MCP16502_OPMODE_LPM); + case PM_SUSPEND_ON: + case PM_SUSPEND_MEM: + return _mcp16502_set_mode(rdev, mode, MCP16502_OPMODE_HIB); + default: + dev_err(&rdev->dev, "invalid suspend target: %d\n", + pm_suspend_target_state); + } + + return -EINVAL; +} + +/* + * mcp16502_set_suspend_enable() - regulator_ops set_suspend_enable + */ +static int mcp16502_set_suspend_enable(struct regulator_dev *rdev) +{ + struct mcp16502 *mcp = rdev_get_drvdata(rdev); + int reg = mcp16502_suspend_get_target_reg(rdev); + + if (reg < 0) + return reg; + + return regmap_update_bits(mcp->rmap, reg, MCP16502_EN, MCP16502_EN); +} + +/* + * mcp16502_set_suspend_disable() - regulator_ops set_suspend_disable + */ +static int mcp16502_set_suspend_disable(struct regulator_dev *rdev) +{ + struct mcp16502 *mcp = rdev_get_drvdata(rdev); + int reg = mcp16502_suspend_get_target_reg(rdev); + + if (reg < 0) + return reg; + + return regmap_update_bits(mcp->rmap, reg, MCP16502_EN, 0); +} +#endif /* CONFIG_SUSPEND */ + +static const struct regulator_ops mcp16502_buck_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mcp16502_get_status, + + .set_mode = mcp16502_set_mode, + .get_mode = mcp16502_get_mode, + +#ifdef CONFIG_SUSPEND + .set_suspend_voltage = mcp16502_set_suspend_voltage, + .set_suspend_mode = mcp16502_set_suspend_mode, + .set_suspend_enable = mcp16502_set_suspend_enable, + .set_suspend_disable = mcp16502_set_suspend_disable, +#endif /* CONFIG_SUSPEND */ +}; + +/* + * LDOs cannot change operating modes. + */ +static const struct regulator_ops mcp16502_ldo_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mcp16502_get_status, + +#ifdef CONFIG_SUSPEND + .set_suspend_voltage = mcp16502_set_suspend_voltage, + .set_suspend_enable = mcp16502_set_suspend_enable, + .set_suspend_disable = mcp16502_set_suspend_disable, +#endif /* CONFIG_SUSPEND */ +}; + +static const struct of_device_id mcp16502_ids[] = { + { .compatible = "microchip,mcp16502", }, + {} +}; +MODULE_DEVICE_TABLE(of, mcp16502_ids); + +static const struct regulator_linear_range b1l12_ranges[] = { + REGULATOR_LINEAR_RANGE(1200000, VDD_LOW_SEL, VDD_HIGH_SEL, 50000), +}; + +static const struct regulator_linear_range b234_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, VDD_LOW_SEL, VDD_HIGH_SEL, 25000), +}; + +static const struct regulator_desc mcp16502_desc[] = { + /* MCP16502_REGULATOR(_name, _id, ranges, regulator_ops) */ + MCP16502_REGULATOR("VDD_IO", BUCK1, b1l12_ranges, mcp16502_buck_ops), + MCP16502_REGULATOR("VDD_DDR", BUCK2, b234_ranges, mcp16502_buck_ops), + MCP16502_REGULATOR("VDD_CORE", BUCK3, b234_ranges, mcp16502_buck_ops), + MCP16502_REGULATOR("VDD_OTHER", BUCK4, b234_ranges, mcp16502_buck_ops), + MCP16502_REGULATOR("LDO1", LDO1, b1l12_ranges, mcp16502_ldo_ops), + MCP16502_REGULATOR("LDO2", LDO2, b1l12_ranges, mcp16502_ldo_ops) +}; + +static const struct regmap_range mcp16502_ranges[] = { + regmap_reg_range(MCP16502_MIN_REG, MCP16502_MAX_REG) +}; + +static const struct regmap_access_table mcp16502_yes_reg_table = { + .yes_ranges = mcp16502_ranges, + .n_yes_ranges = ARRAY_SIZE(mcp16502_ranges), +}; + +static const struct regmap_config mcp16502_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MCP16502_MAX_REG, + .cache_type = REGCACHE_NONE, + .rd_table = &mcp16502_yes_reg_table, + .wr_table = &mcp16502_yes_reg_table, +}; + +/* + * set_up_regulators() - initialize all regulators + */ +static int setup_regulators(struct mcp16502 *mcp, struct device *dev, + struct regulator_config config) +{ + int i; + + for (i = 0; i < NUM_REGULATORS; i++) { + mcp->rdev[i] = devm_regulator_register(dev, + &mcp16502_desc[i], + &config); + if (IS_ERR(mcp->rdev[i])) { + dev_err(dev, + "failed to register %s regulator %ld\n", + mcp16502_desc[i].name, PTR_ERR(mcp->rdev[i])); + return PTR_ERR(mcp->rdev[i]); + } + } + + return 0; +} + +static int mcp16502_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regulator_config config = { }; + struct device *dev; + struct mcp16502 *mcp; + int ret = 0; + + dev = &client->dev; + config.dev = dev; + + mcp = devm_kzalloc(dev, sizeof(*mcp), GFP_KERNEL); + if (!mcp) + return -ENOMEM; + + mcp->rmap = devm_regmap_init_i2c(client, &mcp16502_regmap_config); + if (IS_ERR(mcp->rmap)) { + ret = PTR_ERR(mcp->rmap); + dev_err(dev, "regmap init failed: %d\n", ret); + return ret; + } + + i2c_set_clientdata(client, mcp); + config.regmap = mcp->rmap; + config.driver_data = mcp; + + mcp->lpm = devm_gpiod_get(dev, "lpm", GPIOD_OUT_LOW); + if (IS_ERR(mcp->lpm)) { + dev_err(dev, "failed to get lpm pin: %ld\n", PTR_ERR(mcp->lpm)); + return PTR_ERR(mcp->lpm); + } + + ret = setup_regulators(mcp, dev, config); + if (ret != 0) + return ret; + + mcp16502_gpio_set_mode(mcp, MCP16502_OPMODE_ACTIVE); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mcp16502_suspend_noirq(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mcp16502 *mcp = i2c_get_clientdata(client); + + mcp16502_gpio_set_mode(mcp, MCP16502_OPMODE_LPM); + + return 0; +} + +static int mcp16502_resume_noirq(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mcp16502 *mcp = i2c_get_clientdata(client); + + mcp16502_gpio_set_mode(mcp, MCP16502_OPMODE_ACTIVE); + + return 0; +} +#endif + +#ifdef CONFIG_PM +static const struct dev_pm_ops mcp16502_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mcp16502_suspend_noirq, + mcp16502_resume_noirq) +}; +#endif +static const struct i2c_device_id mcp16502_i2c_id[] = { + { "mcp16502", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mcp16502_i2c_id); + +static struct i2c_driver mcp16502_drv = { + .probe = mcp16502_probe, + .driver = { + .name = "mcp16502-regulator", + .of_match_table = of_match_ptr(mcp16502_ids), +#ifdef CONFIG_PM + .pm = &mcp16502_pm_ops, +#endif + }, + .id_table = mcp16502_i2c_id, +}; + +module_i2c_driver(mcp16502_drv); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MCP16502 PMIC driver"); +MODULE_AUTHOR("Andrei Stefanescu andrei.stefanescu@microchip.com"); diff --git a/drivers/regulator/mt6311-regulator.c b/drivers/regulator/mt6311-regulator.c index 0495716fd35f..01d69f43d2b0 100644 --- a/drivers/regulator/mt6311-regulator.c +++ b/drivers/regulator/mt6311-regulator.c @@ -38,13 +38,9 @@ static const struct regmap_config mt6311_regmap_config = { #define MT6311_MAX_UV 1393750 #define MT6311_STEP_UV 6250 -static const struct regulator_linear_range buck_volt_range[] = { - REGULATOR_LINEAR_RANGE(MT6311_MIN_UV, 0, 0x7f, MT6311_STEP_UV), -}; - static const struct regulator_ops mt6311_buck_ops = { - .list_voltage = regulator_list_voltage_linear_range, - .map_voltage = regulator_map_voltage_linear_range, + .list_voltage = regulator_list_voltage_linear, + .map_voltage = regulator_map_voltage_linear, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, @@ -71,8 +67,6 @@ static const struct regulator_ops mt6311_ldo_ops = { .min_uV = MT6311_MIN_UV,\ .uV_step = MT6311_STEP_UV,\ .owner = THIS_MODULE,\ - .linear_ranges = buck_volt_range, \ - .n_linear_ranges = ARRAY_SIZE(buck_volt_range), \ .enable_reg = MT6311_VDVFS11_CON9,\ .enable_mask = MT6311_PMIC_VDVFS11_EN_MASK,\ .vsel_reg = MT6311_VDVFS11_CON12,\ diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index c4223b3e0dff..7b6bf3536271 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -20,6 +20,7 @@ #include "internal.h" static const char *const regulator_states[PM_SUSPEND_MAX + 1] = { + [PM_SUSPEND_STANDBY] = "regulator-state-standby", [PM_SUSPEND_MEM] = "regulator-state-mem", [PM_SUSPEND_MAX] = "regulator-state-disk", }; @@ -170,6 +171,10 @@ static void of_get_regulation_constraints(struct device_node *np, &pval)) constraints->max_spread = pval; + if (!of_property_read_u32(np, "regulator-max-step-microvolt", + &pval)) + constraints->max_uV_step = pval; + constraints->over_current_protection = of_property_read_bool(np, "regulator-over-current-protection"); @@ -181,9 +186,11 @@ static void of_get_regulation_constraints(struct device_node *np, case PM_SUSPEND_MAX: suspend_state = &constraints->state_disk; break; + case PM_SUSPEND_STANDBY: + suspend_state = &constraints->state_standby; + break; case PM_SUSPEND_ON: case PM_SUSPEND_TO_IDLE: - case PM_SUSPEND_STANDBY: default: continue; } @@ -248,7 +255,7 @@ static void of_get_regulation_constraints(struct device_node *np, * @desc: regulator description * * Populates regulator_init_data structure by extracting data from device - * tree node, returns a pointer to the populated struture or NULL if memory + * tree node, returns a pointer to the populated structure or NULL if memory * alloc fails. */ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, @@ -364,24 +371,25 @@ int of_regulator_match(struct device *dev, struct device_node *node, } EXPORT_SYMBOL_GPL(of_regulator_match); -struct regulator_init_data *regulator_of_get_init_data(struct device *dev, - const struct regulator_desc *desc, - struct regulator_config *config, - struct device_node **node) +struct device_node *regulator_of_get_init_node(struct device *dev, + const struct regulator_desc *desc) { struct device_node *search, *child; - struct regulator_init_data *init_data = NULL; const char *name; if (!dev->of_node || !desc->of_match) return NULL; - if (desc->regulators_node) + if (desc->regulators_node) { search = of_get_child_by_name(dev->of_node, desc->regulators_node); - else + } else { search = of_node_get(dev->of_node); + if (!strcmp(desc->of_match, search->name)) + return search; + } + if (!search) { dev_dbg(dev, "Failed to find regulator container node '%s'\n", desc->regulators_node); @@ -393,35 +401,48 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev, if (!name) name = child->name; - if (strcmp(desc->of_match, name)) - continue; + if (!strcmp(desc->of_match, name)) + return of_node_get(child); + } - init_data = of_get_regulator_init_data(dev, child, desc); - if (!init_data) { - dev_err(dev, - "failed to parse DT for regulator %pOFn\n", - child); - break; - } + of_node_put(search); - if (desc->of_parse_cb) { - if (desc->of_parse_cb(child, desc, config)) { - dev_err(dev, - "driver callback failed to parse DT for regulator %pOFn\n", - child); - init_data = NULL; - break; - } - } + return NULL; +} + +struct regulator_init_data *regulator_of_get_init_data(struct device *dev, + const struct regulator_desc *desc, + struct regulator_config *config, + struct device_node **node) +{ + struct device_node *child; + struct regulator_init_data *init_data = NULL; - of_node_get(child); - *node = child; - break; + child = regulator_of_get_init_node(dev, desc); + if (!child) + return NULL; + + init_data = of_get_regulator_init_data(dev, child, desc); + if (!init_data) { + dev_err(dev, "failed to parse DT for regulator %pOFn\n", child); + goto error; } - of_node_put(search); + if (desc->of_parse_cb && desc->of_parse_cb(child, desc, config)) { + dev_err(dev, + "driver callback failed to parse DT for regulator %pOFn\n", + child); + goto error; + } + + *node = child; return init_data; + +error: + of_node_put(child); + + return NULL; } static int of_node_match(struct device *dev, const void *data) @@ -526,7 +547,7 @@ bool of_check_coupling_data(struct regulator_dev *rdev) NULL); if (c_n_phandles != n_phandles) { - dev_err(&rdev->dev, "number of couped reg phandles mismatch\n"); + dev_err(&rdev->dev, "number of coupled reg phandles mismatch\n"); ret = false; goto clean; } diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index bb5ab7d78895..7fb9e8dd834e 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -382,7 +382,7 @@ static struct palmas_sleep_requestor_info tps65917_sleep_req_info[] = { EXTERNAL_REQUESTOR_TPS65917(LDO5, 2, 4), }; -static unsigned int palmas_smps_ramp_delay[4] = {0, 10000, 5000, 2500}; +static const unsigned int palmas_smps_ramp_delay[4] = {0, 10000, 5000, 2500}; #define SMPS_CTRL_MODE_OFF 0x00 #define SMPS_CTRL_MODE_ON 0x01 @@ -443,13 +443,16 @@ static int palmas_ldo_write(struct palmas *palmas, unsigned int reg, static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode) { int id = rdev_get_id(dev); + int ret; struct palmas_pmic *pmic = rdev_get_drvdata(dev); struct palmas_pmic_driver_data *ddata = pmic->palmas->pmic_ddata; struct palmas_regs_info *rinfo = &ddata->palmas_regs_info[id]; unsigned int reg; bool rail_enable = true; - palmas_smps_read(pmic->palmas, rinfo->ctrl_addr, ®); + ret = palmas_smps_read(pmic->palmas, rinfo->ctrl_addr, ®); + if (ret) + return ret; reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK; diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index dd41a9bb3f5c..df5df1c495ad 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -370,6 +370,7 @@ static struct pfuze_regulator pfuze100_regulators[] = { PFUZE100_VGEN_REG(PFUZE100, VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000), PFUZE100_VGEN_REG(PFUZE100, VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), PFUZE100_VGEN_REG(PFUZE100, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), + PFUZE100_COIN_REG(PFUZE100, COIN, PFUZE100_COINVOL, 0x7, pfuze100_coin), }; static struct pfuze_regulator pfuze200_regulators[] = { @@ -436,6 +437,7 @@ static struct of_regulator_match pfuze100_matches[] = { { .name = "vgen4", }, { .name = "vgen5", }, { .name = "vgen6", }, + { .name = "coin", }, }; /* PFUZE200 */ diff --git a/drivers/regulator/pv88060-regulator.c b/drivers/regulator/pv88060-regulator.c index a9446056435f..1600f9821891 100644 --- a/drivers/regulator/pv88060-regulator.c +++ b/drivers/regulator/pv88060-regulator.c @@ -53,10 +53,6 @@ enum { struct pv88060_regulator { struct regulator_desc desc; - /* Current limiting */ - unsigned n_current_limits; - const int *current_limits; - unsigned int limit_mask; unsigned int conf; /* buck configuration register */ }; @@ -75,7 +71,7 @@ static const struct regmap_config pv88060_regmap_config = { * Entry indexes corresponds to register values. */ -static const int pv88060_buck1_limits[] = { +static const unsigned int pv88060_buck1_limits[] = { 1496000, 2393000, 3291000, 4189000 }; @@ -128,40 +124,6 @@ static int pv88060_buck_set_mode(struct regulator_dev *rdev, PV88060_BUCK_MODE_MASK, val); } -static int pv88060_set_current_limit(struct regulator_dev *rdev, int min, - int max) -{ - struct pv88060_regulator *info = rdev_get_drvdata(rdev); - int i; - - /* search for closest to maximum */ - for (i = info->n_current_limits; i >= 0; i--) { - if (min <= info->current_limits[i] - && max >= info->current_limits[i]) { - return regmap_update_bits(rdev->regmap, - info->conf, - info->limit_mask, - i << PV88060_BUCK_ILIM_SHIFT); - } - } - - return -EINVAL; -} - -static int pv88060_get_current_limit(struct regulator_dev *rdev) -{ - struct pv88060_regulator *info = rdev_get_drvdata(rdev); - unsigned int data; - int ret; - - ret = regmap_read(rdev->regmap, info->conf, &data); - if (ret < 0) - return ret; - - data = (data & info->limit_mask) >> PV88060_BUCK_ILIM_SHIFT; - return info->current_limits[data]; -} - static const struct regulator_ops pv88060_buck_ops = { .get_mode = pv88060_buck_get_mode, .set_mode = pv88060_buck_set_mode, @@ -171,8 +133,8 @@ static const struct regulator_ops pv88060_buck_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, - .set_current_limit = pv88060_set_current_limit, - .get_current_limit = pv88060_get_current_limit, + .set_current_limit = regulator_set_current_limit_regmap, + .get_current_limit = regulator_get_current_limit_regmap, }; static const struct regulator_ops pv88060_ldo_ops = { @@ -184,6 +146,12 @@ static const struct regulator_ops pv88060_ldo_ops = { .list_voltage = regulator_list_voltage_linear, }; +static const struct regulator_ops pv88060_sw_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + #define PV88060_BUCK(chip, regl_name, min, step, max, limits_array) \ {\ .desc = {\ @@ -201,10 +169,11 @@ static const struct regulator_ops pv88060_ldo_ops = { .enable_mask = PV88060_BUCK_EN, \ .vsel_reg = PV88060_REG_##regl_name##_CONF0,\ .vsel_mask = PV88060_VBUCK_MASK,\ + .curr_table = limits_array,\ + .n_current_limits = ARRAY_SIZE(limits_array),\ + .csel_reg = PV88060_REG_##regl_name##_CONF1,\ + .csel_mask = PV88060_BUCK_ILIM_MASK,\ },\ - .current_limits = limits_array,\ - .n_current_limits = ARRAY_SIZE(limits_array),\ - .limit_mask = PV88060_BUCK_ILIM_MASK, \ .conf = PV88060_REG_##regl_name##_CONF1,\ } @@ -237,9 +206,8 @@ static const struct regulator_ops pv88060_ldo_ops = { .regulators_node = of_match_ptr("regulators"),\ .type = REGULATOR_VOLTAGE,\ .owner = THIS_MODULE,\ - .ops = &pv88060_ldo_ops,\ - .min_uV = max,\ - .uV_step = 0,\ + .ops = &pv88060_sw_ops,\ + .fixed_uV = max,\ .n_voltages = 1,\ .enable_reg = PV88060_REG_##regl_name##_CONF,\ .enable_mask = PV88060_SW_EN,\ diff --git a/drivers/regulator/pv88080-regulator.c b/drivers/regulator/pv88080-regulator.c index 9a08cb2de501..bdddacdbeb99 100644 --- a/drivers/regulator/pv88080-regulator.c +++ b/drivers/regulator/pv88080-regulator.c @@ -45,12 +45,7 @@ enum pv88080_types { struct pv88080_regulator { struct regulator_desc desc; - /* Current limiting */ - unsigned int n_current_limits; - const int *current_limits; - unsigned int limit_mask; unsigned int mode_reg; - unsigned int limit_reg; unsigned int conf2; unsigned int conf5; }; @@ -102,11 +97,11 @@ static const struct regmap_config pv88080_regmap_config = { * Entry indexes corresponds to register values. */ -static const int pv88080_buck1_limits[] = { +static const unsigned int pv88080_buck1_limits[] = { 3230000, 5130000, 6960000, 8790000 }; -static const int pv88080_buck23_limits[] = { +static const unsigned int pv88080_buck23_limits[] = { 1496000, 2393000, 3291000, 4189000 }; @@ -272,40 +267,6 @@ static int pv88080_buck_set_mode(struct regulator_dev *rdev, PV88080_BUCK1_MODE_MASK, val); } -static int pv88080_set_current_limit(struct regulator_dev *rdev, int min, - int max) -{ - struct pv88080_regulator *info = rdev_get_drvdata(rdev); - int i; - - /* search for closest to maximum */ - for (i = info->n_current_limits; i >= 0; i--) { - if (min <= info->current_limits[i] - && max >= info->current_limits[i]) { - return regmap_update_bits(rdev->regmap, - info->limit_reg, - info->limit_mask, - i << PV88080_BUCK1_ILIM_SHIFT); - } - } - - return -EINVAL; -} - -static int pv88080_get_current_limit(struct regulator_dev *rdev) -{ - struct pv88080_regulator *info = rdev_get_drvdata(rdev); - unsigned int data; - int ret; - - ret = regmap_read(rdev->regmap, info->limit_reg, &data); - if (ret < 0) - return ret; - - data = (data & info->limit_mask) >> PV88080_BUCK1_ILIM_SHIFT; - return info->current_limits[data]; -} - static const struct regulator_ops pv88080_buck_ops = { .get_mode = pv88080_buck_get_mode, .set_mode = pv88080_buck_set_mode, @@ -315,8 +276,8 @@ static const struct regulator_ops pv88080_buck_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, - .set_current_limit = pv88080_set_current_limit, - .get_current_limit = pv88080_get_current_limit, + .set_current_limit = regulator_set_current_limit_regmap, + .get_current_limit = regulator_get_current_limit_regmap, }; static const struct regulator_ops pv88080_hvbuck_ops = { @@ -341,9 +302,9 @@ static const struct regulator_ops pv88080_hvbuck_ops = { .min_uV = min, \ .uV_step = step, \ .n_voltages = ((max) - (min))/(step) + 1, \ + .curr_table = limits_array, \ + .n_current_limits = ARRAY_SIZE(limits_array), \ },\ - .current_limits = limits_array, \ - .n_current_limits = ARRAY_SIZE(limits_array), \ } #define PV88080_HVBUCK(chip, regl_name, min, step, max) \ @@ -521,9 +482,9 @@ static int pv88080_i2c_probe(struct i2c_client *i2c, if (init_data) config.init_data = &init_data[i]; - pv88080_regulator_info[i].limit_reg + pv88080_regulator_info[i].desc.csel_reg = regmap_config->buck_regmap[i].buck_limit_reg; - pv88080_regulator_info[i].limit_mask + pv88080_regulator_info[i].desc.csel_mask = regmap_config->buck_regmap[i].buck_limit_mask; pv88080_regulator_info[i].mode_reg = regmap_config->buck_regmap[i].buck_mode_reg; diff --git a/drivers/regulator/pv88090-regulator.c b/drivers/regulator/pv88090-regulator.c index 7a0c15957bd0..6e97cc6df2ee 100644 --- a/drivers/regulator/pv88090-regulator.c +++ b/drivers/regulator/pv88090-regulator.c @@ -42,10 +42,6 @@ enum { struct pv88090_regulator { struct regulator_desc desc; - /* Current limiting */ - unsigned int n_current_limits; - const int *current_limits; - unsigned int limit_mask; unsigned int conf; unsigned int conf2; }; @@ -71,14 +67,14 @@ static const struct regmap_config pv88090_regmap_config = { * Entry indexes corresponds to register values. */ -static const int pv88090_buck1_limits[] = { +static const unsigned int pv88090_buck1_limits[] = { 220000, 440000, 660000, 880000, 1100000, 1320000, 1540000, 1760000, 1980000, 2200000, 2420000, 2640000, 2860000, 3080000, 3300000, 3520000, 3740000, 3960000, 4180000, 4400000, 4620000, 4840000, 5060000, 5280000, 5500000, 5720000, 5940000, 6160000, 6380000, 6600000, 6820000, 7040000 }; -static const int pv88090_buck23_limits[] = { +static const unsigned int pv88090_buck23_limits[] = { 1496000, 2393000, 3291000, 4189000 }; @@ -150,40 +146,6 @@ static int pv88090_buck_set_mode(struct regulator_dev *rdev, PV88090_BUCK1_MODE_MASK, val); } -static int pv88090_set_current_limit(struct regulator_dev *rdev, int min, - int max) -{ - struct pv88090_regulator *info = rdev_get_drvdata(rdev); - int i; - - /* search for closest to maximum */ - for (i = info->n_current_limits; i >= 0; i--) { - if (min <= info->current_limits[i] - && max >= info->current_limits[i]) { - return regmap_update_bits(rdev->regmap, - info->conf, - info->limit_mask, - i << PV88090_BUCK1_ILIM_SHIFT); - } - } - - return -EINVAL; -} - -static int pv88090_get_current_limit(struct regulator_dev *rdev) -{ - struct pv88090_regulator *info = rdev_get_drvdata(rdev); - unsigned int data; - int ret; - - ret = regmap_read(rdev->regmap, info->conf, &data); - if (ret < 0) - return ret; - - data = (data & info->limit_mask) >> PV88090_BUCK1_ILIM_SHIFT; - return info->current_limits[data]; -} - static const struct regulator_ops pv88090_buck_ops = { .get_mode = pv88090_buck_get_mode, .set_mode = pv88090_buck_set_mode, @@ -193,8 +155,8 @@ static const struct regulator_ops pv88090_buck_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, - .set_current_limit = pv88090_set_current_limit, - .get_current_limit = pv88090_get_current_limit, + .set_current_limit = regulator_set_current_limit_regmap, + .get_current_limit = regulator_get_current_limit_regmap, }; static const struct regulator_ops pv88090_ldo_ops = { @@ -223,10 +185,11 @@ static const struct regulator_ops pv88090_ldo_ops = { .enable_mask = PV88090_##regl_name##_EN, \ .vsel_reg = PV88090_REG_##regl_name##_CONF0, \ .vsel_mask = PV88090_V##regl_name##_MASK, \ + .curr_table = limits_array, \ + .n_current_limits = ARRAY_SIZE(limits_array), \ + .csel_reg = PV88090_REG_##regl_name##_CONF1, \ + .csel_mask = PV88090_##regl_name##_ILIM_MASK, \ },\ - .current_limits = limits_array, \ - .n_current_limits = ARRAY_SIZE(limits_array), \ - .limit_mask = PV88090_##regl_name##_ILIM_MASK, \ .conf = PV88090_REG_##regl_name##_CONF1, \ .conf2 = PV88090_REG_##regl_name##_CONF2, \ } diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index a2fd140eff81..3f53f9134b32 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -40,9 +40,6 @@ struct pwm_regulator_data { /* regulator descriptor */ struct regulator_desc desc; - /* Regulator ops */ - struct regulator_ops ops; - int state; /* Enable GPIO */ @@ -231,7 +228,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, return 0; } -static struct regulator_ops pwm_regulator_voltage_table_ops = { +static const struct regulator_ops pwm_regulator_voltage_table_ops = { .set_voltage_sel = pwm_regulator_set_voltage_sel, .get_voltage_sel = pwm_regulator_get_voltage_sel, .list_voltage = pwm_regulator_list_voltage, @@ -241,7 +238,7 @@ static struct regulator_ops pwm_regulator_voltage_table_ops = { .is_enabled = pwm_regulator_is_enabled, }; -static struct regulator_ops pwm_regulator_voltage_continuous_ops = { +static const struct regulator_ops pwm_regulator_voltage_continuous_ops = { .get_voltage = pwm_regulator_get_voltage, .set_voltage = pwm_regulator_set_voltage, .enable = pwm_regulator_enable, @@ -249,7 +246,7 @@ static struct regulator_ops pwm_regulator_voltage_continuous_ops = { .is_enabled = pwm_regulator_is_enabled, }; -static struct regulator_desc pwm_regulator_desc = { +static const struct regulator_desc pwm_regulator_desc = { .name = "pwm-regulator", .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, @@ -287,9 +284,7 @@ static int pwm_regulator_init_table(struct platform_device *pdev, drvdata->state = -EINVAL; drvdata->duty_cycle_table = duty_cycle_table; - memcpy(&drvdata->ops, &pwm_regulator_voltage_table_ops, - sizeof(drvdata->ops)); - drvdata->desc.ops = &drvdata->ops; + drvdata->desc.ops = &pwm_regulator_voltage_table_ops; drvdata->desc.n_voltages = length / sizeof(*duty_cycle_table); return 0; @@ -301,9 +296,7 @@ static int pwm_regulator_init_continuous(struct platform_device *pdev, u32 dutycycle_range[2] = { 0, 100 }; u32 dutycycle_unit = 100; - memcpy(&drvdata->ops, &pwm_regulator_voltage_continuous_ops, - sizeof(drvdata->ops)); - drvdata->desc.ops = &drvdata->ops; + drvdata->desc.ops = &pwm_regulator_voltage_continuous_ops; drvdata->desc.continuous_voltage_range = true; of_property_read_u32_array(pdev->dev.of_node, diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 39ccf53fdeb3..b2c2d01d1637 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -410,7 +410,7 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev, vreg->dev = dev; for (rpmh_data = pmic_rpmh_data; rpmh_data->name; rpmh_data++) - if (!strcmp(rpmh_data->name, node->name)) + if (of_node_name_eq(node, rpmh_data->name)) break; if (!rpmh_data->name) { diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index f5bca77d67c1..68bc23df4213 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -31,6 +31,11 @@ struct qcom_rpm_reg { int is_enabled; int uV; + u32 load; + + unsigned int enabled_updated:1; + unsigned int uv_updated:1; + unsigned int load_updated:1; }; struct rpm_regulator_req { @@ -43,30 +48,59 @@ struct rpm_regulator_req { #define RPM_KEY_UV 0x00007675 /* "uv" */ #define RPM_KEY_MA 0x0000616d /* "ma" */ -static int rpm_reg_write_active(struct qcom_rpm_reg *vreg, - struct rpm_regulator_req *req, - size_t size) +static int rpm_reg_write_active(struct qcom_rpm_reg *vreg) { - return qcom_rpm_smd_write(vreg->rpm, - QCOM_SMD_RPM_ACTIVE_STATE, - vreg->type, - vreg->id, - req, size); + struct rpm_regulator_req req[3]; + int reqlen = 0; + int ret; + + if (vreg->enabled_updated) { + req[reqlen].key = cpu_to_le32(RPM_KEY_SWEN); + req[reqlen].nbytes = cpu_to_le32(sizeof(u32)); + req[reqlen].value = cpu_to_le32(vreg->is_enabled); + reqlen++; + } + + if (vreg->uv_updated && vreg->is_enabled) { + req[reqlen].key = cpu_to_le32(RPM_KEY_UV); + req[reqlen].nbytes = cpu_to_le32(sizeof(u32)); + req[reqlen].value = cpu_to_le32(vreg->uV); + reqlen++; + } + + if (vreg->load_updated && vreg->is_enabled) { + req[reqlen].key = cpu_to_le32(RPM_KEY_MA); + req[reqlen].nbytes = cpu_to_le32(sizeof(u32)); + req[reqlen].value = cpu_to_le32(vreg->load / 1000); + reqlen++; + } + + if (!reqlen) + return 0; + + ret = qcom_rpm_smd_write(vreg->rpm, QCOM_SMD_RPM_ACTIVE_STATE, + vreg->type, vreg->id, + req, sizeof(req[0]) * reqlen); + if (!ret) { + vreg->enabled_updated = 0; + vreg->uv_updated = 0; + vreg->load_updated = 0; + } + + return ret; } static int rpm_reg_enable(struct regulator_dev *rdev) { struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); - struct rpm_regulator_req req; int ret; - req.key = cpu_to_le32(RPM_KEY_SWEN); - req.nbytes = cpu_to_le32(sizeof(u32)); - req.value = cpu_to_le32(1); + vreg->is_enabled = 1; + vreg->enabled_updated = 1; - ret = rpm_reg_write_active(vreg, &req, sizeof(req)); - if (!ret) - vreg->is_enabled = 1; + ret = rpm_reg_write_active(vreg); + if (ret) + vreg->is_enabled = 0; return ret; } @@ -81,16 +115,14 @@ static int rpm_reg_is_enabled(struct regulator_dev *rdev) static int rpm_reg_disable(struct regulator_dev *rdev) { struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); - struct rpm_regulator_req req; int ret; - req.key = cpu_to_le32(RPM_KEY_SWEN); - req.nbytes = cpu_to_le32(sizeof(u32)); - req.value = 0; + vreg->is_enabled = 0; + vreg->enabled_updated = 1; - ret = rpm_reg_write_active(vreg, &req, sizeof(req)); - if (!ret) - vreg->is_enabled = 0; + ret = rpm_reg_write_active(vreg); + if (ret) + vreg->is_enabled = 1; return ret; } @@ -108,16 +140,15 @@ static int rpm_reg_set_voltage(struct regulator_dev *rdev, unsigned *selector) { struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); - struct rpm_regulator_req req; - int ret = 0; + int ret; + int old_uV = vreg->uV; - req.key = cpu_to_le32(RPM_KEY_UV); - req.nbytes = cpu_to_le32(sizeof(u32)); - req.value = cpu_to_le32(min_uV); + vreg->uV = min_uV; + vreg->uv_updated = 1; - ret = rpm_reg_write_active(vreg, &req, sizeof(req)); - if (!ret) - vreg->uV = min_uV; + ret = rpm_reg_write_active(vreg); + if (ret) + vreg->uV = old_uV; return ret; } @@ -125,13 +156,16 @@ static int rpm_reg_set_voltage(struct regulator_dev *rdev, static int rpm_reg_set_load(struct regulator_dev *rdev, int load_uA) { struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); - struct rpm_regulator_req req; + u32 old_load = vreg->load; + int ret; - req.key = cpu_to_le32(RPM_KEY_MA); - req.nbytes = cpu_to_le32(sizeof(u32)); - req.value = cpu_to_le32(load_uA / 1000); + vreg->load = load_uA; + vreg->load_updated = 1; + ret = rpm_reg_write_active(vreg); + if (ret) + vreg->load = old_load; - return rpm_reg_write_active(vreg, &req, sizeof(req)); + return ret; } static const struct regulator_ops rpm_smps_ldo_ops = { diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index 213b68743cc8..23713e16c286 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -1,5 +1,5 @@ /* - * Regulator driver for Rockchip RK808/RK818 + * Regulator driver for Rockchip RK805/RK808/RK818 * * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd * @@ -363,28 +363,28 @@ static int rk808_set_suspend_disable(struct regulator_dev *rdev) rdev->desc->enable_mask); } -static struct regulator_ops rk805_reg_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, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, - .set_suspend_voltage = rk808_set_suspend_voltage, - .set_suspend_enable = rk805_set_suspend_enable, - .set_suspend_disable = rk805_set_suspend_disable, +static const struct regulator_ops rk805_reg_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, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_suspend_voltage = rk808_set_suspend_voltage, + .set_suspend_enable = rk805_set_suspend_enable, + .set_suspend_disable = rk805_set_suspend_disable, }; -static struct regulator_ops rk805_switch_ops = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, - .set_suspend_enable = rk805_set_suspend_enable, - .set_suspend_disable = rk805_set_suspend_disable, +static const struct regulator_ops rk805_switch_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_suspend_enable = rk805_set_suspend_enable, + .set_suspend_disable = rk805_set_suspend_disable, }; -static struct regulator_ops rk808_buck1_2_ops = { +static const struct regulator_ops rk808_buck1_2_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = rk808_buck1_2_get_voltage_sel_regmap, @@ -399,7 +399,7 @@ static struct regulator_ops rk808_buck1_2_ops = { .set_suspend_disable = rk808_set_suspend_disable, }; -static struct regulator_ops rk808_reg_ops = { +static const struct regulator_ops rk808_reg_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -412,7 +412,7 @@ static struct regulator_ops rk808_reg_ops = { .set_suspend_disable = rk808_set_suspend_disable, }; -static struct regulator_ops rk808_reg_ops_ranges = { +static const struct regulator_ops rk808_reg_ops_ranges = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -425,7 +425,7 @@ static struct regulator_ops rk808_reg_ops_ranges = { .set_suspend_disable = rk808_set_suspend_disable, }; -static struct regulator_ops rk808_switch_ops = { +static const struct regulator_ops rk808_switch_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -433,6 +433,12 @@ static struct regulator_ops rk808_switch_ops = { .set_suspend_disable = rk808_set_suspend_disable, }; +static const struct regulator_linear_range rk805_buck_1_2_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(712500, 0, 59, 12500), + REGULATOR_LINEAR_RANGE(1800000, 60, 62, 200000), + REGULATOR_LINEAR_RANGE(2300000, 63, 63, 0), +}; + static const struct regulator_desc rk805_reg[] = { { .name = "DCDC_REG1", @@ -440,11 +446,11 @@ static const struct regulator_desc rk805_reg[] = { .of_match = of_match_ptr("DCDC_REG1"), .regulators_node = of_match_ptr("regulators"), .id = RK805_ID_DCDC1, - .ops = &rk805_reg_ops, + .ops = &rk808_reg_ops_ranges, .type = REGULATOR_VOLTAGE, - .min_uV = 712500, - .uV_step = 12500, .n_voltages = 64, + .linear_ranges = rk805_buck_1_2_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk805_buck_1_2_voltage_ranges), .vsel_reg = RK805_BUCK1_ON_VSEL_REG, .vsel_mask = RK818_BUCK_VSEL_MASK, .enable_reg = RK805_DCDC_EN_REG, @@ -456,11 +462,11 @@ static const struct regulator_desc rk805_reg[] = { .of_match = of_match_ptr("DCDC_REG2"), .regulators_node = of_match_ptr("regulators"), .id = RK805_ID_DCDC2, - .ops = &rk805_reg_ops, + .ops = &rk808_reg_ops_ranges, .type = REGULATOR_VOLTAGE, - .min_uV = 712500, - .uV_step = 12500, .n_voltages = 64, + .linear_ranges = rk805_buck_1_2_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(rk805_buck_1_2_voltage_ranges), .vsel_reg = RK805_BUCK2_ON_VSEL_REG, .vsel_mask = RK818_BUCK_VSEL_MASK, .enable_reg = RK805_DCDC_EN_REG, @@ -796,7 +802,7 @@ static struct platform_driver rk808_regulator_driver = { module_platform_driver(rk808_regulator_driver); -MODULE_DESCRIPTION("regulator driver for the RK808/RK818 series PMICs"); +MODULE_DESCRIPTION("regulator driver for the RK805/RK808/RK818 series PMICs"); MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>"); MODULE_AUTHOR("Wadim Egorov <w.egorov@phytec.de>"); diff --git a/drivers/regulator/rt5033-regulator.c b/drivers/regulator/rt5033-regulator.c index 96d2c18e051a..639cbadc044a 100644 --- a/drivers/regulator/rt5033-regulator.c +++ b/drivers/regulator/rt5033-regulator.c @@ -16,14 +16,14 @@ #include <linux/mfd/rt5033-private.h> #include <linux/regulator/of_regulator.h> -static struct regulator_ops rt5033_safe_ldo_ops = { +static const struct regulator_ops rt5033_safe_ldo_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .list_voltage = regulator_list_voltage_linear, }; -static struct regulator_ops rt5033_buck_ops = { +static const struct regulator_ops rt5033_buck_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c index 095d25f3d2ea..58a1fe583a6c 100644 --- a/drivers/regulator/s2mpa01.c +++ b/drivers/regulator/s2mpa01.c @@ -298,13 +298,13 @@ static const struct regulator_desc regulators[] = { regulator_desc_ldo(2, STEP_50_MV), regulator_desc_ldo(3, STEP_50_MV), regulator_desc_ldo(4, STEP_50_MV), - regulator_desc_ldo(5, STEP_50_MV), + regulator_desc_ldo(5, STEP_25_MV), regulator_desc_ldo(6, STEP_25_MV), regulator_desc_ldo(7, STEP_50_MV), regulator_desc_ldo(8, STEP_50_MV), regulator_desc_ldo(9, STEP_50_MV), regulator_desc_ldo(10, STEP_50_MV), - regulator_desc_ldo(11, STEP_25_MV), + regulator_desc_ldo(11, STEP_50_MV), regulator_desc_ldo(12, STEP_50_MV), regulator_desc_ldo(13, STEP_50_MV), regulator_desc_ldo(14, STEP_50_MV), @@ -315,11 +315,11 @@ static const struct regulator_desc regulators[] = { regulator_desc_ldo(19, STEP_50_MV), regulator_desc_ldo(20, STEP_50_MV), regulator_desc_ldo(21, STEP_50_MV), - regulator_desc_ldo(22, STEP_25_MV), - regulator_desc_ldo(23, STEP_25_MV), + regulator_desc_ldo(22, STEP_50_MV), + regulator_desc_ldo(23, STEP_50_MV), regulator_desc_ldo(24, STEP_50_MV), regulator_desc_ldo(25, STEP_50_MV), - regulator_desc_ldo(26, STEP_50_MV), + regulator_desc_ldo(26, STEP_25_MV), regulator_desc_buck1_4(1), regulator_desc_buck1_4(2), regulator_desc_buck1_4(3), diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 5bb6f4ca48db..134c62db36c5 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -5,7 +5,7 @@ #include <linux/bug.h> #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/of.h> @@ -14,7 +14,6 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> -#include <linux/of_gpio.h> #include <linux/mfd/samsung/core.h> #include <linux/mfd/samsung/s2mps11.h> #include <linux/mfd/samsung/s2mps13.h> @@ -44,7 +43,7 @@ struct s2mps11_info { * Array (size: number of regulators) with GPIO-s for external * sleep control. */ - int *ext_control_gpio; + struct gpio_desc **ext_control_gpiod; }; static int get_ramp_delay(int ramp_delay) @@ -363,7 +362,7 @@ static const struct regulator_desc s2mps11_regulators[] = { regulator_desc_s2mps11_ldo(32, STEP_50_MV), regulator_desc_s2mps11_ldo(33, STEP_50_MV), regulator_desc_s2mps11_ldo(34, STEP_50_MV), - regulator_desc_s2mps11_ldo(35, STEP_50_MV), + regulator_desc_s2mps11_ldo(35, STEP_25_MV), regulator_desc_s2mps11_ldo(36, STEP_50_MV), regulator_desc_s2mps11_ldo(37, STEP_50_MV), regulator_desc_s2mps11_ldo(38, STEP_50_MV), @@ -373,8 +372,8 @@ static const struct regulator_desc s2mps11_regulators[] = { regulator_desc_s2mps11_buck1_4(4), regulator_desc_s2mps11_buck5, regulator_desc_s2mps11_buck67810(6, MIN_600_MV, STEP_6_25_MV), - regulator_desc_s2mps11_buck67810(7, MIN_600_MV, STEP_6_25_MV), - regulator_desc_s2mps11_buck67810(8, MIN_600_MV, STEP_6_25_MV), + regulator_desc_s2mps11_buck67810(7, MIN_600_MV, STEP_12_5_MV), + regulator_desc_s2mps11_buck67810(8, MIN_600_MV, STEP_12_5_MV), regulator_desc_s2mps11_buck9, regulator_desc_s2mps11_buck67810(10, MIN_750_MV, STEP_12_5_MV), }; @@ -511,7 +510,7 @@ static int s2mps14_regulator_enable(struct regulator_dev *rdev) case S2MPS14X: if (test_bit(rdev_get_id(rdev), s2mps11->suspend_state)) val = S2MPS14_ENABLE_SUSPEND; - else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)])) + else if (s2mps11->ext_control_gpiod[rdev_get_id(rdev)]) val = S2MPS14_ENABLE_EXT_CONTROL; else val = rdev->desc->enable_mask; @@ -805,7 +804,7 @@ static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11, static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev, struct of_regulator_match *rdata, struct s2mps11_info *s2mps11) { - int *gpio = s2mps11->ext_control_gpio; + struct gpio_desc **gpio = s2mps11->ext_control_gpiod; unsigned int i; unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11, S2MPS14_LDO12 }; @@ -816,11 +815,20 @@ static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev, if (!rdata[reg].init_data || !rdata[reg].of_node) continue; - gpio[reg] = of_get_named_gpio(rdata[reg].of_node, - "samsung,ext-control-gpios", 0); - if (gpio_is_valid(gpio[reg])) - dev_dbg(&pdev->dev, "Using GPIO %d for ext-control over %d/%s\n", - gpio[reg], reg, rdata[reg].name); + gpio[reg] = devm_gpiod_get_from_of_node(&pdev->dev, + rdata[reg].of_node, + "samsung,ext-control-gpios", + 0, + GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, + "s2mps11-regulator"); + if (IS_ERR(gpio[reg])) { + dev_err(&pdev->dev, "Failed to get control GPIO for %d/%s\n", + reg, rdata[reg].name); + continue; + } + if (gpio[reg]) + dev_dbg(&pdev->dev, "Using GPIO for ext-control over %d/%s\n", + reg, rdata[reg].name); } } @@ -1126,17 +1134,10 @@ static int s2mps11_pmic_probe(struct platform_device *pdev) return -EINVAL; } - s2mps11->ext_control_gpio = devm_kmalloc_array(&pdev->dev, - rdev_num, sizeof(*s2mps11->ext_control_gpio), - GFP_KERNEL); - if (!s2mps11->ext_control_gpio) + s2mps11->ext_control_gpiod = devm_kcalloc(&pdev->dev, rdev_num, + sizeof(*s2mps11->ext_control_gpiod), GFP_KERNEL); + if (!s2mps11->ext_control_gpiod) return -ENOMEM; - /* - * 0 is a valid GPIO so initialize all GPIO-s to negative value - * to indicate that external control won't be used for this regulator. - */ - for (i = 0; i < rdev_num; i++) - s2mps11->ext_control_gpio[i] = -EINVAL; if (!iodev->dev->of_node) { if (iodev->pdata) { @@ -1166,8 +1167,6 @@ common_reg: config.dev = &pdev->dev; config.regmap = iodev->regmap_pmic; config.driver_data = s2mps11; - config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH; - config.ena_gpio_initialized = true; for (i = 0; i < rdev_num; i++) { struct regulator_dev *regulator; @@ -1178,8 +1177,13 @@ common_reg: config.init_data = rdata[i].init_data; config.of_node = rdata[i].of_node; } - config.ena_gpio = s2mps11->ext_control_gpio[i]; - + config.ena_gpiod = s2mps11->ext_control_gpiod[i]; + /* + * Hand the GPIO descriptor management over to the regulator + * core, remove it from devres management. + */ + if (config.ena_gpiod) + devm_gpiod_unhinge(&pdev->dev, config.ena_gpiod); regulator = devm_regulator_register(&pdev->dev, ®ulators[i], &config); if (IS_ERR(regulator)) { @@ -1189,7 +1193,7 @@ common_reg: goto out; } - if (gpio_is_valid(s2mps11->ext_control_gpio[i])) { + if (s2mps11->ext_control_gpiod[i]) { ret = s2mps14_pmic_enable_ext_control(s2mps11, regulator); if (ret < 0) { diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 219b9afda0cb..bb9d1a083299 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -115,7 +115,7 @@ static const struct sec_voltage_desc *reg_voltage_map[] = { [S5M8767_BUCK9] = &buck_voltage_val3, }; -static unsigned int s5m8767_opmode_reg[][4] = { +static const unsigned int s5m8767_opmode_reg[][4] = { /* {OFF, ON, LOWPOWER, SUSPEND} */ /* LDO1 ... LDO28 */ {0x0, 0x3, 0x2, 0x1}, /* LDO1 */ @@ -339,13 +339,9 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int new_sel) { struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); - const struct sec_voltage_desc *desc; - int reg_id = rdev_get_id(rdev); - - desc = reg_voltage_map[reg_id]; if ((old_sel < new_sel) && s5m8767->ramp_delay) - return DIV_ROUND_UP(desc->step * (new_sel - old_sel), + return DIV_ROUND_UP(rdev->desc->uV_step * (new_sel - old_sel), s5m8767->ramp_delay * 1000); return 0; } @@ -561,7 +557,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, pdata->opmode = rmode; for_each_child_of_node(regulators_np, reg_np) { for (i = 0; i < ARRAY_SIZE(regulators); i++) - if (!of_node_cmp(reg_np->name, regulators[i].name)) + if (of_node_name_eq(reg_np, regulators[i].name)) break; if (i == ARRAY_SIZE(regulators)) { @@ -956,10 +952,17 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) config.regmap = iodev->regmap_pmic; config.of_node = pdata->regulators[i].reg_node; config.ena_gpiod = NULL; - if (pdata->regulators[i].ext_control_gpiod) + if (pdata->regulators[i].ext_control_gpiod) { + /* Assigns config.ena_gpiod */ s5m8767_regulator_config_ext_control(s5m8767, &pdata->regulators[i], &config); + /* + * Hand the GPIO descriptor management over to the + * regulator core, remove it from devres management. + */ + devm_gpiod_unhinge(s5m8767->dev, config.ena_gpiod); + } rdev = devm_regulator_register(&pdev->dev, ®ulators[id], &config); if (IS_ERR(rdev)) { diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c index e0a9c445ed67..ba2f24949dc9 100644 --- a/drivers/regulator/stm32-vrefbuf.c +++ b/drivers/regulator/stm32-vrefbuf.c @@ -15,6 +15,7 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/of_regulator.h> +#include <linux/pm_runtime.h> /* STM32 VREFBUF registers */ #define STM32_VREFBUF_CSR 0x00 @@ -25,9 +26,12 @@ #define STM32_HIZ BIT(1) #define STM32_ENVR BIT(0) +#define STM32_VREFBUF_AUTO_SUSPEND_DELAY_MS 10 + struct stm32_vrefbuf { void __iomem *base; struct clk *clk; + struct device *dev; }; static const unsigned int stm32_vrefbuf_voltages[] = { @@ -38,9 +42,16 @@ static const unsigned int stm32_vrefbuf_voltages[] = { static int stm32_vrefbuf_enable(struct regulator_dev *rdev) { struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); - u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); + u32 val; int ret; + ret = pm_runtime_get_sync(priv->dev); + if (ret < 0) { + pm_runtime_put_noidle(priv->dev); + return ret; + } + + val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); val = (val & ~STM32_HIZ) | STM32_ENVR; writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); @@ -59,45 +70,95 @@ static int stm32_vrefbuf_enable(struct regulator_dev *rdev) writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); } + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); + return ret; } static int stm32_vrefbuf_disable(struct regulator_dev *rdev) { struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); - u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); + u32 val; + int ret; + ret = pm_runtime_get_sync(priv->dev); + if (ret < 0) { + pm_runtime_put_noidle(priv->dev); + return ret; + } + + val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); val = (val & ~STM32_ENVR) | STM32_HIZ; writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); + return 0; } static int stm32_vrefbuf_is_enabled(struct regulator_dev *rdev) { struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); + int ret; + + ret = pm_runtime_get_sync(priv->dev); + if (ret < 0) { + pm_runtime_put_noidle(priv->dev); + return ret; + } + + ret = readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR; - return readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR; + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); + + return ret; } static int stm32_vrefbuf_set_voltage_sel(struct regulator_dev *rdev, unsigned sel) { struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); - u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); + u32 val; + int ret; + ret = pm_runtime_get_sync(priv->dev); + if (ret < 0) { + pm_runtime_put_noidle(priv->dev); + return ret; + } + + val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); val = (val & ~STM32_VRS) | FIELD_PREP(STM32_VRS, sel); writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); + return 0; } static int stm32_vrefbuf_get_voltage_sel(struct regulator_dev *rdev) { struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); - u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); + u32 val; + int ret; - return FIELD_GET(STM32_VRS, val); + ret = pm_runtime_get_sync(priv->dev); + if (ret < 0) { + pm_runtime_put_noidle(priv->dev); + return ret; + } + + val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); + ret = FIELD_GET(STM32_VRS, val); + + pm_runtime_mark_last_busy(priv->dev); + pm_runtime_put_autosuspend(priv->dev); + + return ret; } static const struct regulator_ops stm32_vrefbuf_volt_ops = { @@ -130,6 +191,7 @@ static int stm32_vrefbuf_probe(struct platform_device *pdev) priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + priv->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->base = devm_ioremap_resource(&pdev->dev, res); @@ -140,10 +202,17 @@ static int stm32_vrefbuf_probe(struct platform_device *pdev) if (IS_ERR(priv->clk)) return PTR_ERR(priv->clk); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, + STM32_VREFBUF_AUTO_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + ret = clk_prepare_enable(priv->clk); if (ret) { dev_err(&pdev->dev, "clk prepare failed with error %d\n", ret); - return ret; + goto err_pm_stop; } config.dev = &pdev->dev; @@ -161,10 +230,17 @@ static int stm32_vrefbuf_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, rdev); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + return 0; err_clk_dis: clk_disable_unprepare(priv->clk); +err_pm_stop: + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); return ret; } @@ -174,12 +250,42 @@ static int stm32_vrefbuf_remove(struct platform_device *pdev) struct regulator_dev *rdev = platform_get_drvdata(pdev); struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); + pm_runtime_get_sync(&pdev->dev); regulator_unregister(rdev); clk_disable_unprepare(priv->clk); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); return 0; }; +static int __maybe_unused stm32_vrefbuf_runtime_suspend(struct device *dev) +{ + struct regulator_dev *rdev = dev_get_drvdata(dev); + struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); + + clk_disable_unprepare(priv->clk); + + return 0; +} + +static int __maybe_unused stm32_vrefbuf_runtime_resume(struct device *dev) +{ + struct regulator_dev *rdev = dev_get_drvdata(dev); + struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); + + return clk_prepare_enable(priv->clk); +} + +static const struct dev_pm_ops stm32_vrefbuf_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(stm32_vrefbuf_runtime_suspend, + stm32_vrefbuf_runtime_resume, + NULL) +}; + static const struct of_device_id stm32_vrefbuf_of_match[] = { { .compatible = "st,stm32-vrefbuf", }, {}, @@ -192,6 +298,7 @@ static struct platform_driver stm32_vrefbuf_driver = { .driver = { .name = "stm32-vrefbuf", .of_match_table = of_match_ptr(stm32_vrefbuf_of_match), + .pm = &stm32_vrefbuf_pm_ops, }, }; module_platform_driver(stm32_vrefbuf_driver); diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c index e15634edb8ce..f09061473613 100644 --- a/drivers/regulator/stpmic1_regulator.c +++ b/drivers/regulator/stpmic1_regulator.c @@ -12,8 +12,10 @@ #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> +#include <dt-bindings/mfd/st,stpmic1.h> + /** - * stpmic1 regulator description + * stpmic1 regulator description: this structure is used as driver data * @desc: regulator framework description * @mask_reset_reg: mask reset register address * @mask_reset_mask: mask rank and mask reset register mask @@ -28,28 +30,9 @@ struct stpmic1_regulator_cfg { u8 icc_mask; }; -/** - * stpmic1 regulator data: this structure is used as driver data - * @regul_id: regulator id - * @reg_node: DT node of regulator (unused on non-DT platforms) - * @cfg: stpmic specific regulator description - * @mask_reset: mask_reset bit value - * @irq_curlim: current limit interrupt number - * @regmap: point to parent regmap structure - */ -struct stpmic1_regulator { - unsigned int regul_id; - struct device_node *reg_node; - struct stpmic1_regulator_cfg *cfg; - u8 mask_reset; - int irq_curlim; - struct regmap *regmap; -}; - static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode); static unsigned int stpmic1_get_mode(struct regulator_dev *rdev); static int stpmic1_set_icc(struct regulator_dev *rdev); -static int stpmic1_regulator_parse_dt(void *driver_data); static unsigned int stpmic1_map_mode(unsigned int mode); enum { @@ -72,15 +55,13 @@ enum { /* Enable time worst case is 5000mV/(2250uV/uS) */ #define PMIC_ENABLE_TIME_US 2200 -#define STPMIC1_BUCK_MODE_NORMAL 0 -#define STPMIC1_BUCK_MODE_LP BUCK_HPLP_ENABLE_MASK - -struct regulator_linear_range buck1_ranges[] = { - REGULATOR_LINEAR_RANGE(600000, 0, 30, 25000), - REGULATOR_LINEAR_RANGE(1350000, 31, 63, 0), +static const struct regulator_linear_range buck1_ranges[] = { + REGULATOR_LINEAR_RANGE(725000, 0, 4, 0), + REGULATOR_LINEAR_RANGE(725000, 5, 36, 25000), + REGULATOR_LINEAR_RANGE(1500000, 37, 63, 0), }; -struct regulator_linear_range buck2_ranges[] = { +static const struct regulator_linear_range buck2_ranges[] = { REGULATOR_LINEAR_RANGE(1000000, 0, 17, 0), REGULATOR_LINEAR_RANGE(1050000, 18, 19, 0), REGULATOR_LINEAR_RANGE(1100000, 20, 21, 0), @@ -94,7 +75,7 @@ struct regulator_linear_range buck2_ranges[] = { REGULATOR_LINEAR_RANGE(1500000, 36, 63, 0), }; -struct regulator_linear_range buck3_ranges[] = { +static const struct regulator_linear_range buck3_ranges[] = { REGULATOR_LINEAR_RANGE(1000000, 0, 19, 0), REGULATOR_LINEAR_RANGE(1100000, 20, 23, 0), REGULATOR_LINEAR_RANGE(1200000, 24, 27, 0), @@ -102,10 +83,9 @@ struct regulator_linear_range buck3_ranges[] = { REGULATOR_LINEAR_RANGE(1400000, 32, 35, 0), REGULATOR_LINEAR_RANGE(1500000, 36, 55, 100000), REGULATOR_LINEAR_RANGE(3400000, 56, 63, 0), - }; -struct regulator_linear_range buck4_ranges[] = { +static const struct regulator_linear_range buck4_ranges[] = { REGULATOR_LINEAR_RANGE(600000, 0, 27, 25000), REGULATOR_LINEAR_RANGE(1300000, 28, 29, 0), REGULATOR_LINEAR_RANGE(1350000, 30, 31, 0), @@ -113,24 +93,21 @@ struct regulator_linear_range buck4_ranges[] = { REGULATOR_LINEAR_RANGE(1450000, 34, 35, 0), REGULATOR_LINEAR_RANGE(1500000, 36, 60, 100000), REGULATOR_LINEAR_RANGE(3900000, 61, 63, 0), - }; -struct regulator_linear_range ldo1_ranges[] = { +static const struct regulator_linear_range ldo1_ranges[] = { REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000), REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0), - }; -struct regulator_linear_range ldo2_ranges[] = { +static const struct regulator_linear_range ldo2_ranges[] = { REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000), REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0), - }; -struct regulator_linear_range ldo3_ranges[] = { +static const struct regulator_linear_range ldo3_ranges[] = { REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000), REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0), @@ -138,18 +115,18 @@ struct regulator_linear_range ldo3_ranges[] = { REGULATOR_LINEAR_RANGE(500000, 31, 31, 0), }; -struct regulator_linear_range ldo5_ranges[] = { +static const struct regulator_linear_range ldo5_ranges[] = { REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), REGULATOR_LINEAR_RANGE(1700000, 8, 30, 100000), REGULATOR_LINEAR_RANGE(3900000, 31, 31, 0), }; -struct regulator_linear_range ldo6_ranges[] = { +static const struct regulator_linear_range ldo6_ranges[] = { REGULATOR_LINEAR_RANGE(900000, 0, 24, 100000), REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0), }; -static struct regulator_ops stpmic1_ldo_ops = { +static const struct regulator_ops stpmic1_ldo_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .is_enabled = regulator_is_enabled_regmap, @@ -157,11 +134,10 @@ static struct regulator_ops stpmic1_ldo_ops = { .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, - .set_pull_down = regulator_set_pull_down_regmap, .set_over_current_protection = stpmic1_set_icc, }; -static struct regulator_ops stpmic1_ldo3_ops = { +static const struct regulator_ops stpmic1_ldo3_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_iterate, .is_enabled = regulator_is_enabled_regmap, @@ -169,21 +145,19 @@ static struct regulator_ops stpmic1_ldo3_ops = { .disable = regulator_disable_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, - .set_pull_down = regulator_set_pull_down_regmap, .get_bypass = regulator_get_bypass_regmap, .set_bypass = regulator_set_bypass_regmap, .set_over_current_protection = stpmic1_set_icc, }; -static struct regulator_ops stpmic1_ldo4_fixed_regul_ops = { +static const struct regulator_ops stpmic1_ldo4_fixed_regul_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .set_pull_down = regulator_set_pull_down_regmap, .set_over_current_protection = stpmic1_set_icc, }; -static struct regulator_ops stpmic1_buck_ops = { +static const struct regulator_ops stpmic1_buck_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .is_enabled = regulator_is_enabled_regmap, @@ -197,20 +171,27 @@ static struct regulator_ops stpmic1_buck_ops = { .set_over_current_protection = stpmic1_set_icc, }; -static struct regulator_ops stpmic1_vref_ddr_ops = { +static const struct regulator_ops stpmic1_vref_ddr_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .set_pull_down = regulator_set_pull_down_regmap, }; -static struct regulator_ops stpmic1_switch_regul_ops = { +static const struct regulator_ops stpmic1_boost_regul_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .set_over_current_protection = stpmic1_set_icc, }; +static const struct regulator_ops stpmic1_switch_regul_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .set_over_current_protection = stpmic1_set_icc, + .set_active_discharge = regulator_set_active_discharge_regmap, +}; + #define REG_LDO(ids, base) { \ .name = #ids, \ .id = STPMIC1_##ids, \ @@ -227,8 +208,6 @@ static struct regulator_ops stpmic1_switch_regul_ops = { .enable_val = 1, \ .disable_val = 0, \ .enable_time = PMIC_ENABLE_TIME_US, \ - .pull_down_reg = ids##_PULL_DOWN_REG, \ - .pull_down_mask = ids##_PULL_DOWN_MASK, \ .supply_name = #base, \ } @@ -252,8 +231,6 @@ static struct regulator_ops stpmic1_switch_regul_ops = { .bypass_mask = LDO_BYPASS_MASK, \ .bypass_val_on = LDO_BYPASS_MASK, \ .bypass_val_off = 0, \ - .pull_down_reg = ids##_PULL_DOWN_REG, \ - .pull_down_mask = ids##_PULL_DOWN_MASK, \ .supply_name = #base, \ } @@ -271,8 +248,6 @@ static struct regulator_ops stpmic1_switch_regul_ops = { .enable_val = 1, \ .disable_val = 0, \ .enable_time = PMIC_ENABLE_TIME_US, \ - .pull_down_reg = ids##_PULL_DOWN_REG, \ - .pull_down_mask = ids##_PULL_DOWN_MASK, \ .supply_name = #base, \ } @@ -312,12 +287,47 @@ static struct regulator_ops stpmic1_switch_regul_ops = { .enable_val = 1, \ .disable_val = 0, \ .enable_time = PMIC_ENABLE_TIME_US, \ - .pull_down_reg = ids##_PULL_DOWN_REG, \ - .pull_down_mask = ids##_PULL_DOWN_MASK, \ .supply_name = #base, \ } -#define REG_SWITCH(ids, base, reg, mask, val) { \ +#define REG_BOOST(ids, base) { \ + .name = #ids, \ + .id = STPMIC1_##ids, \ + .n_voltages = 1, \ + .ops = &stpmic1_boost_regul_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 0, \ + .fixed_uV = 5000000, \ + .enable_reg = BST_SW_CR, \ + .enable_mask = BOOST_ENABLED, \ + .enable_val = BOOST_ENABLED, \ + .disable_val = 0, \ + .enable_time = PMIC_ENABLE_TIME_US, \ + .supply_name = #base, \ +} + +#define REG_VBUS_OTG(ids, base) { \ + .name = #ids, \ + .id = STPMIC1_##ids, \ + .n_voltages = 1, \ + .ops = &stpmic1_switch_regul_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .min_uV = 0, \ + .fixed_uV = 5000000, \ + .enable_reg = BST_SW_CR, \ + .enable_mask = USBSW_OTG_SWITCH_ENABLED, \ + .enable_val = USBSW_OTG_SWITCH_ENABLED, \ + .disable_val = 0, \ + .enable_time = PMIC_ENABLE_TIME_US, \ + .supply_name = #base, \ + .active_discharge_reg = BST_SW_CR, \ + .active_discharge_mask = VBUS_OTG_DISCHARGE, \ + .active_discharge_on = VBUS_OTG_DISCHARGE, \ +} + +#define REG_SW_OUT(ids, base) { \ .name = #ids, \ .id = STPMIC1_##ids, \ .n_voltages = 1, \ @@ -326,15 +336,18 @@ static struct regulator_ops stpmic1_switch_regul_ops = { .owner = THIS_MODULE, \ .min_uV = 0, \ .fixed_uV = 5000000, \ - .enable_reg = (reg), \ - .enable_mask = (mask), \ - .enable_val = (val), \ + .enable_reg = BST_SW_CR, \ + .enable_mask = SWIN_SWOUT_ENABLED, \ + .enable_val = SWIN_SWOUT_ENABLED, \ .disable_val = 0, \ .enable_time = PMIC_ENABLE_TIME_US, \ .supply_name = #base, \ + .active_discharge_reg = BST_SW_CR, \ + .active_discharge_mask = SW_OUT_DISCHARGE, \ + .active_discharge_on = SW_OUT_DISCHARGE, \ } -struct stpmic1_regulator_cfg stpmic1_regulator_cfgs[] = { +static const struct stpmic1_regulator_cfg stpmic1_regulator_cfgs[] = { [STPMIC1_BUCK1] = { .desc = REG_BUCK(BUCK1, buck1), .icc_reg = BUCKS_ICCTO_CR, @@ -411,23 +424,17 @@ struct stpmic1_regulator_cfg stpmic1_regulator_cfgs[] = { .mask_reset_mask = BIT(6), }, [STPMIC1_BOOST] = { - .desc = REG_SWITCH(BOOST, boost, BST_SW_CR, - BOOST_ENABLED, - BOOST_ENABLED), + .desc = REG_BOOST(BOOST, boost), .icc_reg = BUCKS_ICCTO_CR, .icc_mask = BIT(6), }, [STPMIC1_VBUS_OTG] = { - .desc = REG_SWITCH(VBUS_OTG, pwr_sw1, BST_SW_CR, - USBSW_OTG_SWITCH_ENABLED, - USBSW_OTG_SWITCH_ENABLED), + .desc = REG_VBUS_OTG(VBUS_OTG, pwr_sw1), .icc_reg = BUCKS_ICCTO_CR, .icc_mask = BIT(4), }, [STPMIC1_SW_OUT] = { - .desc = REG_SWITCH(SW_OUT, pwr_sw2, BST_SW_CR, - SWIN_SWOUT_ENABLED, - SWIN_SWOUT_ENABLED), + .desc = REG_SW_OUT(SW_OUT, pwr_sw2), .icc_reg = BUCKS_ICCTO_CR, .icc_mask = BIT(5), }, @@ -448,8 +455,9 @@ static unsigned int stpmic1_map_mode(unsigned int mode) static unsigned int stpmic1_get_mode(struct regulator_dev *rdev) { int value; + struct regmap *regmap = rdev_get_regmap(rdev); - regmap_read(rdev->regmap, rdev->desc->enable_reg, &value); + regmap_read(regmap, rdev->desc->enable_reg, &value); if (value & STPMIC1_BUCK_MODE_LP) return REGULATOR_MODE_STANDBY; @@ -460,6 +468,7 @@ static unsigned int stpmic1_get_mode(struct regulator_dev *rdev) static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode) { int value; + struct regmap *regmap = rdev_get_regmap(rdev); switch (mode) { case REGULATOR_MODE_NORMAL: @@ -472,75 +481,43 @@ static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode) return -EINVAL; } - return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + return regmap_update_bits(regmap, rdev->desc->enable_reg, STPMIC1_BUCK_MODE_LP, value); } static int stpmic1_set_icc(struct regulator_dev *rdev) { - struct stpmic1_regulator *regul = rdev_get_drvdata(rdev); + struct stpmic1_regulator_cfg *cfg = rdev_get_drvdata(rdev); + struct regmap *regmap = rdev_get_regmap(rdev); /* enable switch off in case of over current */ - return regmap_update_bits(regul->regmap, regul->cfg->icc_reg, - regul->cfg->icc_mask, regul->cfg->icc_mask); + return regmap_update_bits(regmap, cfg->icc_reg, cfg->icc_mask, + cfg->icc_mask); } static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data) { struct regulator_dev *rdev = (struct regulator_dev *)data; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); /* Send an overcurrent notification */ regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, NULL); - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return IRQ_HANDLED; } -static int stpmic1_regulator_init(struct platform_device *pdev, - struct regulator_dev *rdev) -{ - struct stpmic1_regulator *regul = rdev_get_drvdata(rdev); - int ret = 0; - - /* set mask reset */ - if (regul->mask_reset && regul->cfg->mask_reset_reg != 0) { - ret = regmap_update_bits(regul->regmap, - regul->cfg->mask_reset_reg, - regul->cfg->mask_reset_mask, - regul->cfg->mask_reset_mask); - if (ret) { - dev_err(&pdev->dev, "set mask reset failed\n"); - return ret; - } - } - - /* setup an irq handler for over-current detection */ - if (regul->irq_curlim > 0) { - ret = devm_request_threaded_irq(&pdev->dev, - regul->irq_curlim, NULL, - stpmic1_curlim_irq_handler, - IRQF_ONESHOT | IRQF_SHARED, - pdev->name, rdev); - if (ret) { - dev_err(&pdev->dev, "Request IRQ failed\n"); - return ret; - } - } - return 0; -} - #define MATCH(_name, _id) \ [STPMIC1_##_id] = { \ .name = #_name, \ .desc = &stpmic1_regulator_cfgs[STPMIC1_##_id].desc, \ } -static struct of_regulator_match stpmic1_regulators_matches[] = { +static struct of_regulator_match stpmic1_matches[] = { MATCH(buck1, BUCK1), MATCH(buck2, BUCK2), MATCH(buck3, BUCK3), @@ -557,94 +534,75 @@ static struct of_regulator_match stpmic1_regulators_matches[] = { MATCH(pwr_sw2, SW_OUT), }; -static int stpmic1_regulator_parse_dt(void *driver_data) -{ - struct stpmic1_regulator *regul = - (struct stpmic1_regulator *)driver_data; - - if (!regul) - return -EINVAL; - - if (of_get_property(regul->reg_node, "st,mask-reset", NULL)) - regul->mask_reset = 1; - - regul->irq_curlim = of_irq_get(regul->reg_node, 0); - - return 0; -} - -static struct -regulator_dev *stpmic1_regulator_register(struct platform_device *pdev, int id, - struct regulator_init_data *init_data, - struct stpmic1_regulator *regul) +static int stpmic1_regulator_register(struct platform_device *pdev, int id, + struct of_regulator_match *match, + const struct stpmic1_regulator_cfg *cfg) { struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); struct regulator_dev *rdev; struct regulator_config config = {}; + int ret = 0; + int irq; config.dev = &pdev->dev; - config.init_data = init_data; - config.of_node = stpmic1_regulators_matches[id].of_node; + config.init_data = match->init_data; + config.of_node = match->of_node; config.regmap = pmic_dev->regmap; - config.driver_data = regul; - - regul->regul_id = id; - regul->reg_node = config.of_node; - regul->cfg = &stpmic1_regulator_cfgs[id]; - regul->regmap = pmic_dev->regmap; + config.driver_data = (void *)cfg; - rdev = devm_regulator_register(&pdev->dev, ®ul->cfg->desc, &config); + rdev = devm_regulator_register(&pdev->dev, &cfg->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s regulator\n", - regul->cfg->desc.name); + cfg->desc.name); + return PTR_ERR(rdev); + } + + /* set mask reset */ + if (of_get_property(config.of_node, "st,mask-reset", NULL) && + cfg->mask_reset_reg != 0) { + ret = regmap_update_bits(pmic_dev->regmap, + cfg->mask_reset_reg, + cfg->mask_reset_mask, + cfg->mask_reset_mask); + if (ret) { + dev_err(&pdev->dev, "set mask reset failed\n"); + return ret; + } } - return rdev; + /* setup an irq handler for over-current detection */ + irq = of_irq_get(config.of_node, 0); + if (irq > 0) { + ret = devm_request_threaded_irq(&pdev->dev, + irq, NULL, + stpmic1_curlim_irq_handler, + IRQF_ONESHOT | IRQF_SHARED, + pdev->name, rdev); + if (ret) { + dev_err(&pdev->dev, "Request IRQ failed\n"); + return ret; + } + } + return 0; } static int stpmic1_regulator_probe(struct platform_device *pdev) { - struct regulator_dev *rdev; - struct stpmic1_regulator *regul; - struct regulator_init_data *init_data; - struct device_node *np; int i, ret; - np = pdev->dev.of_node; - - ret = of_regulator_match(&pdev->dev, np, - stpmic1_regulators_matches, - ARRAY_SIZE(stpmic1_regulators_matches)); + ret = of_regulator_match(&pdev->dev, pdev->dev.of_node, stpmic1_matches, + ARRAY_SIZE(stpmic1_matches)); if (ret < 0) { dev_err(&pdev->dev, "Error in PMIC regulator device tree node"); return ret; } - regul = devm_kzalloc(&pdev->dev, ARRAY_SIZE(stpmic1_regulator_cfgs) * - sizeof(struct stpmic1_regulator), - GFP_KERNEL); - if (!regul) - return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(stpmic1_regulator_cfgs); i++) { - /* Parse DT & find regulators to register */ - init_data = stpmic1_regulators_matches[i].init_data; - if (init_data) - init_data->regulator_init = &stpmic1_regulator_parse_dt; - - rdev = stpmic1_regulator_register(pdev, i, init_data, regul); - if (IS_ERR(rdev)) - return PTR_ERR(rdev); - - ret = stpmic1_regulator_init(pdev, rdev); - if (ret) { - dev_err(&pdev->dev, - "failed to initialize regulator %d\n", ret); + ret = stpmic1_regulator_register(pdev, i, &stpmic1_matches[i], + &stpmic1_regulator_cfgs[i]); + if (ret < 0) return ret; - } - - regul++; } dev_dbg(&pdev->dev, "stpmic1_regulator driver probed\n"); diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index db714d5edafc..0614551796a1 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c @@ -480,6 +480,12 @@ static int tps65090_regulator_probe(struct platform_device *pdev) else config.of_node = NULL; + /* + * Hand the GPIO descriptor management over to the regulator + * core, remove it from devres management. + */ + if (config.ena_gpiod) + devm_gpiod_unhinge(&pdev->dev, config.ena_gpiod); rdev = devm_regulator_register(&pdev->dev, ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index 6209beee1018..95708d34876b 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -188,7 +188,8 @@ static struct regulator_ops tps65218_ldo1_dcdc34_ops = { .set_suspend_disable = tps65218_pmic_set_suspend_disable, }; -static const int ls3_currents[] = { 100, 200, 500, 1000 }; +static const int ls3_currents[] = { 100000, 200000, 500000, 1000000 }; + static int tps65218_pmic_set_input_current_lim(struct regulator_dev *dev, int lim_uA) @@ -204,7 +205,8 @@ static int tps65218_pmic_set_input_current_lim(struct regulator_dev *dev, return -EINVAL; return tps65218_set_bits(tps, dev->desc->csel_reg, dev->desc->csel_mask, - index << 2, TPS65218_PROTECT_L1); + index << __builtin_ctz(dev->desc->csel_mask), + TPS65218_PROTECT_L1); } static int tps65218_pmic_set_current_limit(struct regulator_dev *dev, @@ -214,7 +216,7 @@ static int tps65218_pmic_set_current_limit(struct regulator_dev *dev, unsigned int num_currents = ARRAY_SIZE(ls3_currents); struct tps65218 *tps = rdev_get_drvdata(dev); - while (index < num_currents && ls3_currents[index] < max_uA) + while (index < num_currents && ls3_currents[index] <= max_uA) index++; index--; @@ -223,7 +225,8 @@ static int tps65218_pmic_set_current_limit(struct regulator_dev *dev, return -EINVAL; return tps65218_set_bits(tps, dev->desc->csel_reg, dev->desc->csel_mask, - index << 2, TPS65218_PROTECT_L1); + index << __builtin_ctz(dev->desc->csel_mask), + TPS65218_PROTECT_L1); } static int tps65218_pmic_get_current_limit(struct regulator_dev *dev) @@ -236,12 +239,13 @@ static int tps65218_pmic_get_current_limit(struct regulator_dev *dev) if (retval < 0) return retval; - index = (index & dev->desc->csel_mask) >> 2; + index = (index & dev->desc->csel_mask) >> + __builtin_ctz(dev->desc->csel_mask); return ls3_currents[index]; } -static struct regulator_ops tps65218_ls3_ops = { +static struct regulator_ops tps65218_ls23_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = tps65218_pmic_enable, .disable = tps65218_pmic_disable, @@ -303,8 +307,13 @@ static const struct regulator_desc regulators[] = { TPS65218_ENABLE2_LDO1_EN, 0, 0, ldo1_dcdc3_ranges, 2, 0, 0, TPS65218_REG_SEQ6, TPS65218_SEQ6_LDO1_SEQ_MASK), + TPS65218_REGULATOR("LS2", "regulator-ls2", TPS65218_LS_2, + REGULATOR_CURRENT, tps65218_ls23_ops, 0, 0, 0, + TPS65218_REG_ENABLE2, TPS65218_ENABLE2_LS2_EN, + TPS65218_REG_CONFIG2, TPS65218_CONFIG2_LS2ILIM_MASK, + NULL, 0, 0, 0, 0, 0), TPS65218_REGULATOR("LS3", "regulator-ls3", TPS65218_LS_3, - REGULATOR_CURRENT, tps65218_ls3_ops, 0, 0, 0, + REGULATOR_CURRENT, tps65218_ls23_ops, 0, 0, 0, TPS65218_REG_ENABLE2, TPS65218_ENABLE2_LS3_EN, TPS65218_REG_CONFIG2, TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0, 0, 0), diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 02ccdaa226a7..5ebb6ee73f07 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -1102,8 +1102,10 @@ static int tps65910_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pmic); /* Give control of all register to control port */ - tps65910_reg_set_bits(pmic->mfd, TPS65910_DEVCTRL, + err = tps65910_reg_set_bits(pmic->mfd, TPS65910_DEVCTRL, DEVCTRL_SR_CTL_I2C_SEL_MASK); + if (err < 0) + return err; switch (tps65910_chip_id(tps65910)) { case TPS65910: diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 884c7505ed91..402ea43c77d1 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -576,14 +576,9 @@ static int twlreg_probe(struct platform_device *pdev) struct regulator_init_data *initdata; struct regulation_constraints *c; struct regulator_dev *rdev; - const struct of_device_id *match; struct regulator_config config = { }; - match = of_match_device(twl_of_match, &pdev->dev); - if (!match) - return -ENODEV; - - template = match->data; + template = of_device_get_match_data(&pdev->dev); if (!template) return -ENODEV; diff --git a/drivers/regulator/twl6030-regulator.c b/drivers/regulator/twl6030-regulator.c index 219cbd910dbf..15f19df6bc5d 100644 --- a/drivers/regulator/twl6030-regulator.c +++ b/drivers/regulator/twl6030-regulator.c @@ -31,9 +31,6 @@ struct twlreg_info { /* twl resource ID, for resource control state machine */ u8 id; - /* chip constraints on regulator behavior */ - u16 min_mV; - u8 flags; /* used by regulator core */ @@ -247,32 +244,11 @@ static int twl6030coresmps_get_voltage(struct regulator_dev *rdev) return -ENODEV; } -static struct regulator_ops twl6030coresmps_ops = { +static const struct regulator_ops twl6030coresmps_ops = { .set_voltage = twl6030coresmps_set_voltage, .get_voltage = twl6030coresmps_get_voltage, }; -static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned sel) -{ - struct twlreg_info *info = rdev_get_drvdata(rdev); - - switch (sel) { - case 0: - return 0; - case 1 ... 24: - /* Linear mapping from 00000001 to 00011000: - * Absolute voltage value = 1.0 V + 0.1 V × (sel – 00000001) - */ - return (info->min_mV + 100 * (sel - 1)) * 1000; - case 25 ... 30: - return -EINVAL; - case 31: - return 2750000; - default: - return -EINVAL; - } -} - static int twl6030ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { @@ -290,8 +266,8 @@ static int twl6030ldo_get_voltage_sel(struct regulator_dev *rdev) return vsel; } -static struct regulator_ops twl6030ldo_ops = { - .list_voltage = twl6030ldo_list_voltage, +static const struct regulator_ops twl6030ldo_ops = { + .list_voltage = regulator_list_voltage_linear_range, .set_voltage_sel = twl6030ldo_set_voltage_sel, .get_voltage_sel = twl6030ldo_get_voltage_sel, @@ -305,7 +281,7 @@ static struct regulator_ops twl6030ldo_ops = { .get_status = twl6030reg_get_status, }; -static struct regulator_ops twl6030fixed_ops = { +static const struct regulator_ops twl6030fixed_ops = { .list_voltage = regulator_list_voltage_linear, .enable = twl6030reg_enable, @@ -496,7 +472,7 @@ static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev) return twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS); } -static struct regulator_ops twlsmps_ops = { +static const struct regulator_ops twlsmps_ops = { .list_voltage = twl6030smps_list_voltage, .map_voltage = twl6030smps_map_voltage, @@ -513,6 +489,11 @@ static struct regulator_ops twlsmps_ops = { }; /*----------------------------------------------------------------------*/ +static const struct regulator_linear_range twl6030ldo_linear_range[] = { + REGULATOR_LINEAR_RANGE(0, 0, 0, 0), + REGULATOR_LINEAR_RANGE(1000000, 1, 24, 100000), + REGULATOR_LINEAR_RANGE(2750000, 31, 31, 0), +}; #define TWL6030_ADJUSTABLE_SMPS(label) \ static const struct twlreg_info TWL6030_INFO_##label = { \ @@ -525,28 +506,30 @@ static const struct twlreg_info TWL6030_INFO_##label = { \ }, \ } -#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts) \ +#define TWL6030_ADJUSTABLE_LDO(label, offset) \ static const struct twlreg_info TWL6030_INFO_##label = { \ .base = offset, \ - .min_mV = min_mVolts, \ .desc = { \ .name = #label, \ .id = TWL6030_REG_##label, \ .n_voltages = 32, \ + .linear_ranges = twl6030ldo_linear_range, \ + .n_linear_ranges = ARRAY_SIZE(twl6030ldo_linear_range), \ .ops = &twl6030ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ }, \ } -#define TWL6032_ADJUSTABLE_LDO(label, offset, min_mVolts) \ +#define TWL6032_ADJUSTABLE_LDO(label, offset) \ static const struct twlreg_info TWL6032_INFO_##label = { \ .base = offset, \ - .min_mV = min_mVolts, \ .desc = { \ .name = #label, \ .id = TWL6032_REG_##label, \ .n_voltages = 32, \ + .linear_ranges = twl6030ldo_linear_range, \ + .n_linear_ranges = ARRAY_SIZE(twl6030ldo_linear_range), \ .ops = &twl6030ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -557,7 +540,6 @@ static const struct twlreg_info TWL6032_INFO_##label = { \ static const struct twlreg_info TWLFIXED_INFO_##label = { \ .base = offset, \ .id = 0, \ - .min_mV = mVolts, \ .desc = { \ .name = #label, \ .id = TWL6030##_REG_##label, \ @@ -574,7 +556,6 @@ static const struct twlreg_info TWLFIXED_INFO_##label = { \ #define TWL6032_ADJUSTABLE_SMPS(label, offset) \ static const struct twlreg_info TWLSMPS_INFO_##label = { \ .base = offset, \ - .min_mV = 600, \ .desc = { \ .name = #label, \ .id = TWL6032_REG_##label, \ @@ -592,22 +573,22 @@ static const struct twlreg_info TWLSMPS_INFO_##label = { \ TWL6030_ADJUSTABLE_SMPS(VDD1); TWL6030_ADJUSTABLE_SMPS(VDD2); TWL6030_ADJUSTABLE_SMPS(VDD3); -TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000); -TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000); -TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000); -TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000); -TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000); -TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000); +TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54); +TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58); +TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c); +TWL6030_ADJUSTABLE_LDO(VMMC, 0x68); +TWL6030_ADJUSTABLE_LDO(VPP, 0x6c); +TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74); /* 6025 are renamed compared to 6030 versions */ -TWL6032_ADJUSTABLE_LDO(LDO2, 0x54, 1000); -TWL6032_ADJUSTABLE_LDO(LDO4, 0x58, 1000); -TWL6032_ADJUSTABLE_LDO(LDO3, 0x5c, 1000); -TWL6032_ADJUSTABLE_LDO(LDO5, 0x68, 1000); -TWL6032_ADJUSTABLE_LDO(LDO1, 0x6c, 1000); -TWL6032_ADJUSTABLE_LDO(LDO7, 0x74, 1000); -TWL6032_ADJUSTABLE_LDO(LDO6, 0x60, 1000); -TWL6032_ADJUSTABLE_LDO(LDOLN, 0x64, 1000); -TWL6032_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000); +TWL6032_ADJUSTABLE_LDO(LDO2, 0x54); +TWL6032_ADJUSTABLE_LDO(LDO4, 0x58); +TWL6032_ADJUSTABLE_LDO(LDO3, 0x5c); +TWL6032_ADJUSTABLE_LDO(LDO5, 0x68); +TWL6032_ADJUSTABLE_LDO(LDO1, 0x6c); +TWL6032_ADJUSTABLE_LDO(LDO7, 0x74); +TWL6032_ADJUSTABLE_LDO(LDO6, 0x60); +TWL6032_ADJUSTABLE_LDO(LDOLN, 0x64); +TWL6032_ADJUSTABLE_LDO(LDOUSB, 0x70); TWL6030_FIXED_LDO(VANA, 0x50, 2100, 0); TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 0); TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0); @@ -687,14 +668,9 @@ static int twlreg_probe(struct platform_device *pdev) struct regulator_init_data *initdata; struct regulation_constraints *c; struct regulator_dev *rdev; - const struct of_device_id *match; struct regulator_config config = { }; - match = of_match_device(twl_of_match, &pdev->dev); - if (!match) - return -ENODEV; - - template = match->data; + template = of_device_get_match_data(&pdev->dev); if (!template) return -ENODEV; diff --git a/drivers/regulator/uniphier-regulator.c b/drivers/regulator/uniphier-regulator.c index abf22acbd13e..9026d5a3e964 100644 --- a/drivers/regulator/uniphier-regulator.c +++ b/drivers/regulator/uniphier-regulator.c @@ -32,7 +32,7 @@ struct uniphier_regulator_priv { const struct uniphier_regulator_soc_data *data; }; -static struct regulator_ops uniphier_regulator_ops = { +static const struct regulator_ops uniphier_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -87,8 +87,10 @@ static int uniphier_regulator_probe(struct platform_device *pdev) } regmap = devm_regmap_init_mmio(dev, base, priv->data->regconf); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + goto out_rst_assert; + } config.dev = dev; config.driver_data = priv; diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 5a5bc4bb08d2..12b422373580 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -205,33 +205,10 @@ static irqreturn_t wm831x_dcdc_oc_irq(int irq, void *data) * BUCKV specifics */ -static int wm831x_buckv_list_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - if (selector <= 0x8) - return 600000; - if (selector <= WM831X_BUCKV_MAX_SELECTOR) - return 600000 + ((selector - 0x8) * 12500); - return -EINVAL; -} - -static int wm831x_buckv_map_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - u16 vsel; - - if (min_uV < 600000) - vsel = 0; - else if (min_uV <= 1800000) - vsel = DIV_ROUND_UP(min_uV - 600000, 12500) + 8; - else - return -EINVAL; - - if (wm831x_buckv_list_voltage(rdev, vsel) > max_uV) - return -EINVAL; - - return vsel; -} +static const struct regulator_linear_range wm831x_buckv_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0, 0x7, 0), + REGULATOR_LINEAR_RANGE(600000, 0x8, 0x68, 12500), +}; static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state) { @@ -309,7 +286,7 @@ static int wm831x_buckv_set_suspend_voltage(struct regulator_dev *rdev, u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL; int vsel; - vsel = wm831x_buckv_map_voltage(rdev, uV, uV); + vsel = regulator_map_voltage_linear_range(rdev, uV, uV); if (vsel < 0) return vsel; @@ -327,52 +304,18 @@ static int wm831x_buckv_get_voltage_sel(struct regulator_dev *rdev) } /* Current limit options */ -static u16 wm831x_dcdc_ilim[] = { - 125, 250, 375, 500, 625, 750, 875, 1000 +static const unsigned int wm831x_dcdc_ilim[] = { + 125000, 250000, 375000, 500000, 625000, 750000, 875000, 1000000 }; -static int wm831x_buckv_set_current_limit(struct regulator_dev *rdev, - int min_uA, int max_uA) -{ - struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); - struct wm831x *wm831x = dcdc->wm831x; - u16 reg = dcdc->base + WM831X_DCDC_CONTROL_2; - int i; - - for (i = ARRAY_SIZE(wm831x_dcdc_ilim) - 1; i >= 0; i--) { - if ((min_uA <= wm831x_dcdc_ilim[i]) && - (wm831x_dcdc_ilim[i] <= max_uA)) - return wm831x_set_bits(wm831x, reg, - WM831X_DC1_HC_THR_MASK, - i << WM831X_DC1_HC_THR_SHIFT); - } - - return -EINVAL; -} - -static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev) -{ - struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); - struct wm831x *wm831x = dcdc->wm831x; - u16 reg = dcdc->base + WM831X_DCDC_CONTROL_2; - int val; - - val = wm831x_reg_read(wm831x, reg); - if (val < 0) - return val; - - val = (val & WM831X_DC1_HC_THR_MASK) >> WM831X_DC1_HC_THR_SHIFT; - return wm831x_dcdc_ilim[val]; -} - static const struct regulator_ops wm831x_buckv_ops = { .set_voltage_sel = wm831x_buckv_set_voltage_sel, .get_voltage_sel = wm831x_buckv_get_voltage_sel, - .list_voltage = wm831x_buckv_list_voltage, - .map_voltage = wm831x_buckv_map_voltage, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, .set_suspend_voltage = wm831x_buckv_set_suspend_voltage, - .set_current_limit = wm831x_buckv_set_current_limit, - .get_current_limit = wm831x_buckv_get_current_limit, + .set_current_limit = regulator_set_current_limit_regmap, + .get_current_limit = regulator_get_current_limit_regmap, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, @@ -492,10 +435,16 @@ static int wm831x_buckv_probe(struct platform_device *pdev) dcdc->desc.id = id; dcdc->desc.type = REGULATOR_VOLTAGE; dcdc->desc.n_voltages = WM831X_BUCKV_MAX_SELECTOR + 1; + dcdc->desc.linear_ranges = wm831x_buckv_ranges; + dcdc->desc.n_linear_ranges = ARRAY_SIZE(wm831x_buckv_ranges); dcdc->desc.ops = &wm831x_buckv_ops; dcdc->desc.owner = THIS_MODULE; dcdc->desc.enable_reg = WM831X_DCDC_ENABLE; dcdc->desc.enable_mask = 1 << id; + dcdc->desc.csel_reg = dcdc->base + WM831X_DCDC_CONTROL_2; + dcdc->desc.csel_mask = WM831X_DC1_HC_THR_MASK; + dcdc->desc.n_current_limits = ARRAY_SIZE(wm831x_dcdc_ilim); + dcdc->desc.curr_table = wm831x_dcdc_ilim; ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG); if (ret < 0) { diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 8ad11b074b49..a1c7dfee5c37 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1153,7 +1153,7 @@ static irqreturn_t pmic_uv_handler(int irq, void *data) { struct regulator_dev *rdev = (struct regulator_dev *)data; - mutex_lock(&rdev->mutex); + regulator_lock(rdev); if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2) regulator_notifier_call_chain(rdev, REGULATOR_EVENT_REGULATION_OUT, @@ -1162,7 +1162,7 @@ static irqreturn_t pmic_uv_handler(int irq, void *data) regulator_notifier_call_chain(rdev, REGULATOR_EVENT_UNDER_VOLTAGE, NULL); - mutex_unlock(&rdev->mutex); + regulator_unlock(rdev); return IRQ_HANDLED; } diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 7a4ce6df4f22..38928cdcb6e6 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -19,7 +19,7 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/mfd/wm8994/core.h> @@ -129,6 +129,7 @@ static int wm8994_ldo_probe(struct platform_device *pdev) int id = pdev->id % ARRAY_SIZE(pdata->ldo); struct regulator_config config = { }; struct wm8994_ldo *ldo; + struct gpio_desc *gpiod; int ret; dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); @@ -145,12 +146,18 @@ static int wm8994_ldo_probe(struct platform_device *pdev) config.driver_data = ldo; config.regmap = wm8994->regmap; config.init_data = &ldo->init_data; - if (pdata) { - config.ena_gpio = pdata->ldo[id].enable; - } else if (wm8994->dev->of_node) { - config.ena_gpio = wm8994->pdata.ldo[id].enable; - config.ena_gpio_initialized = true; - } + + /* + * Look up LDO enable GPIO from the parent device node, we don't + * use devm because the regulator core will free the GPIO + */ + gpiod = gpiod_get_optional(pdev->dev.parent, + id ? "wlf,ldo2ena" : "wlf,ldo1ena", + GPIOD_OUT_LOW | + GPIOD_FLAGS_BIT_NONEXCLUSIVE); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + config.ena_gpiod = gpiod; /* Use default constraints if none set up */ if (!pdata || !pdata->ldo[id].init_data || wm8994->dev->of_node) { @@ -159,12 +166,17 @@ static int wm8994_ldo_probe(struct platform_device *pdev) ldo->init_data = wm8994_ldo_default[id]; ldo->init_data.consumer_supplies = &ldo->supply; - if (!config.ena_gpio) + if (!gpiod) ldo->init_data.constraints.valid_ops_mask = 0; } else { ldo->init_data = *pdata->ldo[id].init_data; } + /* + * At this point the GPIO descriptor is handled over to the + * regulator core and we need not worry about it on the + * error path. + */ ldo->regulator = devm_regulator_register(&pdev->dev, &wm8994_ldo_desc[id], &config); @@ -172,15 +184,12 @@ static int wm8994_ldo_probe(struct platform_device *pdev) ret = PTR_ERR(ldo->regulator); dev_err(wm8994->dev, "Failed to register LDO%d: %d\n", id + 1, ret); - goto err; + return ret; } platform_set_drvdata(pdev, ldo); return 0; - -err: - return ret; } static struct platform_driver wm8994_ldo_driver = { |