From 297101ab85841319aac2c7843ca755d650c1964f Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Fri, 15 Jun 2018 13:44:53 +0200 Subject: regulator: pfuze100: add pfuze3001 support This extends the pfuze100 driver with pfuze3001 support. Latest datasheet: https://www.nxp.com/docs/en/data-sheet/PF3001.pdf Signed-off-by: Robin Gong Signed-off-by: Stefan Wahren Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 4 +- drivers/regulator/pfuze100-regulator.c | 78 +++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 9 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 5dbccf5f3037..2964eaea94c0 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -633,12 +633,12 @@ config REGULATOR_PCF50633 on PCF50633 config REGULATOR_PFUZE100 - tristate "Freescale PFUZE100/200/3000 regulator driver" + tristate "Freescale PFUZE100/200/3000/3001 regulator driver" depends on I2C select REGMAP_I2C help Say y here to support the regulators found on the Freescale - PFUZE100/200/3000 PMIC. + PFUZE100/200/3000/3001 PMIC. config REGULATOR_PV88060 tristate "Powerventure Semiconductor PV88060 regulator" diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 8d9dbcc775ea..32f9af7f87c4 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -44,7 +44,7 @@ #define PFUZE100_VGEN5VOL 0x70 #define PFUZE100_VGEN6VOL 0x71 -enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3 }; +enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3, PFUZE3001 = 0x31, }; struct pfuze_regulator { struct regulator_desc desc; @@ -92,6 +92,7 @@ static const struct i2c_device_id pfuze_device_id[] = { {.name = "pfuze100", .driver_data = PFUZE100}, {.name = "pfuze200", .driver_data = PFUZE200}, {.name = "pfuze3000", .driver_data = PFUZE3000}, + {.name = "pfuze3001", .driver_data = PFUZE3001}, { } }; MODULE_DEVICE_TABLE(i2c, pfuze_device_id); @@ -100,6 +101,7 @@ static const struct of_device_id pfuze_dt_ids[] = { { .compatible = "fsl,pfuze100", .data = (void *)PFUZE100}, { .compatible = "fsl,pfuze200", .data = (void *)PFUZE200}, { .compatible = "fsl,pfuze3000", .data = (void *)PFUZE3000}, + { .compatible = "fsl,pfuze3001", .data = (void *)PFUZE3001}, { } }; MODULE_DEVICE_TABLE(of, pfuze_dt_ids); @@ -108,10 +110,28 @@ static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) { struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev); int id = rdev_get_id(rdev); + bool reg_has_ramp_delay; unsigned int ramp_bits; int ret; - if (id < PFUZE100_SWBST) { + switch (pfuze100->chip_id) { + case PFUZE3001: + /* no dynamic voltage scaling for PF3001 */ + reg_has_ramp_delay = false; + break; + case PFUZE3000: + reg_has_ramp_delay = (id < PFUZE3000_SWBST); + break; + case PFUZE200: + reg_has_ramp_delay = (id < PFUZE200_SWBST); + break; + case PFUZE100: + default: + reg_has_ramp_delay = (id < PFUZE100_SWBST); + break; + } + + if (reg_has_ramp_delay) { ramp_delay = 12500 / ramp_delay; ramp_bits = (ramp_delay >> 1) - (ramp_delay >> 3); ret = regmap_update_bits(pfuze100->regmap, @@ -119,8 +139,9 @@ static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) 0xc0, ramp_bits << 6); if (ret < 0) dev_err(pfuze100->dev, "ramp failed, err %d\n", ret); - } else + } else { ret = -EACCES; + } return ret; } @@ -361,6 +382,19 @@ static struct pfuze_regulator pfuze3000_regulators[] = { PFUZE100_VGEN_REG(PFUZE3000, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), }; +static struct pfuze_regulator pfuze3001_regulators[] = { + PFUZE100_SWB_REG(PFUZE3001, SW1, PFUZE100_SW1ABVOL, 0x1f, pfuze3000_sw1a), + PFUZE100_SWB_REG(PFUZE3001, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo), + PFUZE3000_SW3_REG(PFUZE3001, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000), + PFUZE100_SWB_REG(PFUZE3001, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), + PFUZE100_VGEN_REG(PFUZE3001, VLDO1, PFUZE100_VGEN1VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE3001, VLDO2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000), + PFUZE3000_VCC_REG(PFUZE3001, VCCSD, PFUZE100_VGEN3VOL, 2850000, 3300000, 150000), + PFUZE3000_VCC_REG(PFUZE3001, V33, PFUZE100_VGEN4VOL, 2850000, 3300000, 150000), + PFUZE100_VGEN_REG(PFUZE3001, VLDO3, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000), + PFUZE100_VGEN_REG(PFUZE3001, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000), +}; + #ifdef CONFIG_OF /* PFUZE100 */ static struct of_regulator_match pfuze100_matches[] = { @@ -418,6 +452,21 @@ static struct of_regulator_match pfuze3000_matches[] = { { .name = "vldo4", }, }; +/* PFUZE3001 */ +static struct of_regulator_match pfuze3001_matches[] = { + + { .name = "sw1", }, + { .name = "sw2", }, + { .name = "sw3", }, + { .name = "vsnvs", }, + { .name = "vldo1", }, + { .name = "vldo2", }, + { .name = "vccsd", }, + { .name = "v33", }, + { .name = "vldo3", }, + { .name = "vldo4", }, +}; + static struct of_regulator_match *pfuze_matches; static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) @@ -437,6 +486,11 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) } switch (chip->chip_id) { + case PFUZE3001: + pfuze_matches = pfuze3001_matches; + ret = of_regulator_match(dev, parent, pfuze3001_matches, + ARRAY_SIZE(pfuze3001_matches)); + break; case PFUZE3000: pfuze_matches = pfuze3000_matches; ret = of_regulator_match(dev, parent, pfuze3000_matches, @@ -508,7 +562,8 @@ static int pfuze_identify(struct pfuze_chip *pfuze_chip) */ dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8"); } else if ((value & 0x0f) != pfuze_chip->chip_id && - (value & 0xf0) >> 4 != pfuze_chip->chip_id) { + (value & 0xf0) >> 4 != pfuze_chip->chip_id && + (value != pfuze_chip->chip_id)) { /* device id NOT match with your setting */ dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value); return -ENODEV; @@ -588,6 +643,13 @@ static int pfuze100_regulator_probe(struct i2c_client *client, /* use the right regulators after identify the right device */ switch (pfuze_chip->chip_id) { + case PFUZE3001: + pfuze_chip->pfuze_regulators = pfuze3001_regulators; + regulator_num = ARRAY_SIZE(pfuze3001_regulators); + sw_check_start = PFUZE3001_SW2; + sw_check_end = PFUZE3001_SW2; + sw_hi = 1 << 3; + break; case PFUZE3000: pfuze_chip->pfuze_regulators = pfuze3000_regulators; regulator_num = ARRAY_SIZE(pfuze3000_regulators); @@ -611,7 +673,8 @@ static int pfuze100_regulator_probe(struct i2c_client *client, } dev_info(&client->dev, "pfuze%s found.\n", (pfuze_chip->chip_id == PFUZE100) ? "100" : - ((pfuze_chip->chip_id == PFUZE200) ? "200" : "3000")); + (((pfuze_chip->chip_id == PFUZE200) ? "200" : + ((pfuze_chip->chip_id == PFUZE3000) ? "3000" : "3001")))); memcpy(pfuze_chip->regulator_descs, pfuze_chip->pfuze_regulators, sizeof(pfuze_chip->regulator_descs)); @@ -636,7 +699,8 @@ static int pfuze100_regulator_probe(struct i2c_client *client, if (i >= sw_check_start && i <= sw_check_end) { regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val); if (val & sw_hi) { - if (pfuze_chip->chip_id == PFUZE3000) { + if (pfuze_chip->chip_id == PFUZE3000 || + pfuze_chip->chip_id == PFUZE3001) { desc->volt_table = pfuze3000_sw2hi; desc->n_voltages = ARRAY_SIZE(pfuze3000_sw2hi); } else { @@ -675,5 +739,5 @@ static struct i2c_driver pfuze_driver = { module_i2c_driver(pfuze_driver); MODULE_AUTHOR("Robin Gong "); -MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/200/3000 PMIC"); +MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/200/3000/3001 PMIC"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From adb78a8e24bbfe19df0d4dd19ee78cec351a5f04 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 27 Jun 2018 20:40:13 +0800 Subject: regulator: bd71837: Staticize ldo_2_volts Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/bd71837-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/bd71837-regulator.c b/drivers/regulator/bd71837-regulator.c index 6eae4d0432a2..403b45de1262 100644 --- a/drivers/regulator/bd71837-regulator.c +++ b/drivers/regulator/bd71837-regulator.c @@ -195,7 +195,7 @@ static const struct regulator_linear_range bd71837_ldo1_voltage_ranges[] = { * LDO2 * 0.8 or 0.9V */ -const unsigned int ldo_2_volts[] = { +static const unsigned int ldo_2_volts[] = { 900000, 800000 }; -- cgit v1.2.3 From ffdc4984100050d0c8e2f11f76a15ca36f5d9e37 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 27 Jun 2018 20:40:14 +0800 Subject: regulator: bd71837: Simplify bd71837_set_voltage_sel_restricted implementation Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/bd71837-regulator.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/bd71837-regulator.c b/drivers/regulator/bd71837-regulator.c index 403b45de1262..f57f42ed7160 100644 --- a/drivers/regulator/bd71837-regulator.c +++ b/drivers/regulator/bd71837-regulator.c @@ -73,14 +73,10 @@ static int bd71837_buck1234_set_ramp_delay(struct regulator_dev *rdev, static int bd71837_set_voltage_sel_restricted(struct regulator_dev *rdev, unsigned int sel) { - int ret; - - ret = regulator_is_enabled_regmap(rdev); - if (!ret) - ret = regulator_set_voltage_sel_regmap(rdev, sel); - else if (ret == 1) - ret = -EBUSY; - return ret; + if (regulator_is_enabled_regmap(rdev)) + return -EBUSY; + + return regulator_set_voltage_sel_regmap(rdev, sel); } static struct regulator_ops bd71837_ldo_regulator_ops = { -- cgit v1.2.3 From c9dc4cfa10a1266376dde151485f7b493447258b Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Thu, 28 Jun 2018 14:22:23 +0300 Subject: regulator: bd71837: Editorial cleanups. Address issues spotted by Andy Shevchenko during review of original patch No functional changes intended Signed-off-by: Matti Vaittinen Signed-off-by: Mark Brown --- drivers/regulator/bd71837-regulator.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/bd71837-regulator.c b/drivers/regulator/bd71837-regulator.c index f57f42ed7160..3a487255482c 100644 --- a/drivers/regulator/bd71837-regulator.c +++ b/drivers/regulator/bd71837-regulator.c @@ -2,19 +2,18 @@ // Copyright (C) 2018 ROHM Semiconductors // bd71837-regulator.c ROHM BD71837MWV regulator driver -#include -#include -#include +#include #include +#include #include +#include +#include +#include #include #include #include -#include -#include -#include -#include #include +#include struct bd71837_pmic { struct regulator_desc descs[BD71837_REGULATOR_CNT]; @@ -39,7 +38,7 @@ static int bd71837_buck1234_set_ramp_delay(struct regulator_dev *rdev, int id = rdev->desc->id; unsigned int ramp_value = BUCK_RAMPRATE_10P00MV; - dev_dbg(&(pmic->pdev->dev), "Buck[%d] Set Ramp = %d\n", id + 1, + dev_dbg(&pmic->pdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1, ramp_delay); switch (ramp_delay) { case 1 ... 1250: @@ -544,8 +543,7 @@ static int bd71837_probe(struct platform_device *pdev) int i, err; - pmic = devm_kzalloc(&pdev->dev, sizeof(struct bd71837_pmic), - GFP_KERNEL); + pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); if (!pmic) return -ENOMEM; @@ -569,8 +567,8 @@ static int bd71837_probe(struct platform_device *pdev) dev_err(&pmic->pdev->dev, "Failed to unlock PMIC (%d)\n", err); goto err; } else { - dev_dbg(&pmic->pdev->dev, "%s: Unlocked lock register 0x%x\n", - __func__, BD71837_REG_REGLOCK); + dev_dbg(&pmic->pdev->dev, "Unlocked lock register 0x%x\n", + BD71837_REG_REGLOCK); } for (i = 0; i < ARRAY_SIZE(pmic_regulator_inits); i++) { @@ -615,8 +613,6 @@ static int bd71837_probe(struct platform_device *pdev) pmic->rdev[i] = rdev; } - return 0; - err: return err; } @@ -624,7 +620,6 @@ err: static struct platform_driver bd71837_regulator = { .driver = { .name = "bd71837-pmic", - .owner = THIS_MODULE, }, .probe = bd71837_probe, }; -- cgit v1.2.3 From 464a5686e6c9df364fbfa9a6d0f61276a777d550 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 1 Jul 2018 22:18:27 -0300 Subject: regulator: Revert "regulator: pfuze100: add enable/disable for switch" This reverts commit 5fe156f1cab4f340ddb6283c993912be77594016. Commit 5fe156f1cab4 ("regulator: pfuze100: add enable/disable for switch") causes boot regression on some platforms such as imx6sl-evk and imx6sll-evk. After this commit the SW4 regulator will be turned off and since it supplies the DDR voltage on these boards, a kernel hang is observed. Revert it to avoid breaking old dtb's. Fixes: 5fe156f1cab4 ("regulator: pfuze100: add enable/disable for switch") Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 32f9af7f87c4..cde6eda1d283 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -163,9 +163,6 @@ static const struct regulator_ops pfuze100_fixed_regulator_ops = { }; static const struct regulator_ops pfuze100_sw_regulator_ops = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_linear, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -212,11 +209,6 @@ static const struct regulator_ops pfuze100_swb_regulator_ops = { .uV_step = (step), \ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ .vsel_mask = 0x3f, \ - .enable_reg = (base) + PFUZE100_MODE_OFFSET, \ - .enable_val = 0xc, \ - .disable_val = 0x0, \ - .enable_mask = 0xf, \ - .enable_time = 500, \ }, \ .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ .stby_mask = 0x3f, \ -- cgit v1.2.3 From 0380cf7dbaca75c524e34b30979f0806124fa8e6 Mon Sep 17 00:00:00 2001 From: pascal paillet Date: Thu, 5 Jul 2018 14:25:57 +0000 Subject: regulator: core: Change suspend_late to suspend Change suspend_late ops to suspend normal ops. The goal is to avoid requesting all the regulator drivers to be operational in suspend late phase. Signed-off-by: pascal paillet Signed-off-by: Mark Brown --- drivers/regulator/core.c | 26 +++++++++++++------------- include/linux/regulator/driver.h | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 6ed568b96c0e..da9b0fed8330 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -4441,7 +4441,7 @@ void regulator_unregister(struct regulator_dev *rdev) EXPORT_SYMBOL_GPL(regulator_unregister); #ifdef CONFIG_SUSPEND -static int _regulator_suspend_late(struct device *dev, void *data) +static int _regulator_suspend(struct device *dev, void *data) { struct regulator_dev *rdev = dev_to_rdev(dev); suspend_state_t *state = data; @@ -4455,20 +4455,20 @@ static int _regulator_suspend_late(struct device *dev, void *data) } /** - * regulator_suspend_late - prepare regulators for system wide suspend + * regulator_suspend - prepare regulators for system wide suspend * @state: system suspend state * * Configure each regulator with it's suspend operating parameters for state. */ -static int regulator_suspend_late(struct device *dev) +static int regulator_suspend(struct device *dev) { suspend_state_t state = pm_suspend_target_state; return class_for_each_device(®ulator_class, NULL, &state, - _regulator_suspend_late); + _regulator_suspend); } -static int _regulator_resume_early(struct device *dev, void *data) +static int _regulator_resume(struct device *dev, void *data) { int ret = 0; struct regulator_dev *rdev = dev_to_rdev(dev); @@ -4481,35 +4481,35 @@ static int _regulator_resume_early(struct device *dev, void *data) regulator_lock(rdev); - if (rdev->desc->ops->resume_early && + if (rdev->desc->ops->resume && (rstate->enabled == ENABLE_IN_SUSPEND || rstate->enabled == DISABLE_IN_SUSPEND)) - ret = rdev->desc->ops->resume_early(rdev); + ret = rdev->desc->ops->resume(rdev); regulator_unlock(rdev); return ret; } -static int regulator_resume_early(struct device *dev) +static int regulator_resume(struct device *dev) { suspend_state_t state = pm_suspend_target_state; return class_for_each_device(®ulator_class, NULL, &state, - _regulator_resume_early); + _regulator_resume); } #else /* !CONFIG_SUSPEND */ -#define regulator_suspend_late NULL -#define regulator_resume_early NULL +#define regulator_suspend NULL +#define regulator_resume NULL #endif /* !CONFIG_SUSPEND */ #ifdef CONFIG_PM static const struct dev_pm_ops __maybe_unused regulator_pm_ops = { - .suspend_late = regulator_suspend_late, - .resume_early = regulator_resume_early, + .suspend = regulator_suspend, + .resume = regulator_resume, }; #endif diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index dea96ee39fdc..0fd8fbb74763 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -220,7 +220,7 @@ struct regulator_ops { /* set regulator suspend operating mode (defined in consumer.h) */ int (*set_suspend_mode) (struct regulator_dev *, unsigned int mode); - int (*resume_early)(struct regulator_dev *rdev); + int (*resume)(struct regulator_dev *rdev); int (*set_pull_down) (struct regulator_dev *); }; -- cgit v1.2.3 From ed1ae2dd9f242c7a36e8e39100f6a7f6bcdfdd89 Mon Sep 17 00:00:00 2001 From: pascal paillet Date: Thu, 5 Jul 2018 14:25:56 +0000 Subject: regulator: core: Link consumer with regulator driver Add a device link between the consumer and the driver so that the consumer is not suspended before the driver. The goal is to avoid implementing suspend_late ops in regulator drivers. Signed-off-by: pascal paillet Signed-off-by: Mark Brown --- drivers/regulator/core.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index da9b0fed8330..bb1324f93143 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1740,6 +1740,8 @@ struct regulator *_regulator_get(struct device *dev, const char *id, rdev->use_count = 0; } + device_link_add(dev, &rdev->dev, DL_FLAG_STATELESS); + return regulator; } @@ -1829,9 +1831,21 @@ static void _regulator_put(struct regulator *regulator) debugfs_remove_recursive(regulator->debugfs); - /* remove any sysfs entries */ - if (regulator->dev) + 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); + + /* remove any sysfs entries */ sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); + } + regulator_lock(rdev); list_del(®ulator->list); -- cgit v1.2.3 From 1aa1b918946537c089716bffd1399e30a2981cb7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 6 Jul 2018 11:37:18 +0300 Subject: regulator: max8997: clean up a condition in max8997_list_voltage() The current code generates a static cehcker warnings because "rid < 0" is always false: drivers/regulator/max8997-regulator.c:169 max8997_list_voltage() warn: condition is always false The problem is that because of type promotion, if "rid" is negative the comparison against ARRAY_SIZE() is type promoted to size_t and it's treated as a very high positive value. I've changed the order of the checks so now everyone is happy. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- drivers/regulator/max8997-regulator.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/max8997-regulator.c b/drivers/regulator/max8997-regulator.c index a8ea30ee18a6..029a6ee426ab 100644 --- a/drivers/regulator/max8997-regulator.c +++ b/drivers/regulator/max8997-regulator.c @@ -165,8 +165,7 @@ static int max8997_list_voltage(struct regulator_dev *rdev, int rid = rdev_get_id(rdev); int val; - if (rid >= ARRAY_SIZE(reg_voltage_map) || - rid < 0) + if (rid < 0 || rid >= ARRAY_SIZE(reg_voltage_map)) return -EINVAL; desc = reg_voltage_map[rid]; -- cgit v1.2.3 From 9df4f90954c860b9715f8fbca521781d8d5cf280 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Wed, 11 Jul 2018 13:30:52 +0900 Subject: regulator: uniphier: add regulator driver for UniPhier SoC Initial commit to add support for regulators implemented in UniPhier SoCs. This supports USB VBUS only. Signed-off-by: Kunihiko Hayashi Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 8 ++ drivers/regulator/Makefile | 1 + drivers/regulator/uniphier-regulator.c | 213 +++++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+) create mode 100644 drivers/regulator/uniphier-regulator.c (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 2964eaea94c0..8233dc7f0a68 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -950,6 +950,14 @@ config REGULATOR_TWL4030 This driver supports the voltage regulators provided by this family of companion chips. +config REGULATOR_UNIPHIER + tristate "UniPhier regulator driver" + depends on ARCH_UNIPHIER || COMPILE_TEST + depends on OF && MFD_SYSCON + default ARCH_UNIPHIER + help + Support for regulators implemented on Socionext UniPhier SoCs. + config REGULATOR_VCTRL tristate "Voltage controlled regulators" depends on OF diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index bd818ceb7c72..b7839f41591e 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -118,6 +118,7 @@ obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o obj-$(CONFIG_REGULATOR_TPS65132) += tps65132-regulator.o obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o twl6030-regulator.o +obj-$(CONFIG_REGULATOR_UNIPHIER) += uniphier-regulator.o obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o diff --git a/drivers/regulator/uniphier-regulator.c b/drivers/regulator/uniphier-regulator.c new file mode 100644 index 000000000000..abf22acbd13e --- /dev/null +++ b/drivers/regulator/uniphier-regulator.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Regulator controller driver for UniPhier SoC +// Copyright 2018 Socionext Inc. +// Author: Kunihiko Hayashi + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_CLKS 2 +#define MAX_RSTS 2 + +struct uniphier_regulator_soc_data { + int nclks; + const char * const *clock_names; + int nrsts; + const char * const *reset_names; + const struct regulator_desc *desc; + const struct regmap_config *regconf; +}; + +struct uniphier_regulator_priv { + struct clk_bulk_data clk[MAX_CLKS]; + struct reset_control *rst[MAX_RSTS]; + const struct uniphier_regulator_soc_data *data; +}; + +static struct regulator_ops uniphier_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static int uniphier_regulator_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct uniphier_regulator_priv *priv; + struct regulator_config config = { }; + struct regulator_dev *rdev; + struct regmap *regmap; + struct resource *res; + void __iomem *base; + const char *name; + int i, ret, nr; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->data = of_device_get_match_data(dev); + if (WARN_ON(!priv->data)) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + for (i = 0; i < priv->data->nclks; i++) + priv->clk[i].id = priv->data->clock_names[i]; + ret = devm_clk_bulk_get(dev, priv->data->nclks, priv->clk); + if (ret) + return ret; + + for (i = 0; i < priv->data->nrsts; i++) { + name = priv->data->reset_names[i]; + priv->rst[i] = devm_reset_control_get_shared(dev, name); + if (IS_ERR(priv->rst[i])) + return PTR_ERR(priv->rst[i]); + } + + ret = clk_bulk_prepare_enable(priv->data->nclks, priv->clk); + if (ret) + return ret; + + for (nr = 0; nr < priv->data->nrsts; nr++) { + ret = reset_control_deassert(priv->rst[nr]); + if (ret) + goto out_rst_assert; + } + + regmap = devm_regmap_init_mmio(dev, base, priv->data->regconf); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + config.dev = dev; + config.driver_data = priv; + config.of_node = dev->of_node; + config.regmap = regmap; + config.init_data = of_get_regulator_init_data(dev, dev->of_node, + priv->data->desc); + rdev = devm_regulator_register(dev, priv->data->desc, &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + goto out_rst_assert; + } + + platform_set_drvdata(pdev, priv); + + return 0; + +out_rst_assert: + while (nr--) + reset_control_assert(priv->rst[nr]); + + clk_bulk_disable_unprepare(priv->data->nclks, priv->clk); + + return ret; +} + +static int uniphier_regulator_remove(struct platform_device *pdev) +{ + struct uniphier_regulator_priv *priv = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < priv->data->nrsts; i++) + reset_control_assert(priv->rst[i]); + + clk_bulk_disable_unprepare(priv->data->nclks, priv->clk); + + return 0; +} + +/* USB3 controller data */ +#define USB3VBUS_OFFSET 0x0 +#define USB3VBUS_REG BIT(4) +#define USB3VBUS_REG_EN BIT(3) +static const struct regulator_desc uniphier_usb3_regulator_desc = { + .name = "vbus", + .of_match = of_match_ptr("vbus"), + .ops = &uniphier_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = USB3VBUS_OFFSET, + .enable_mask = USB3VBUS_REG_EN | USB3VBUS_REG, + .enable_val = USB3VBUS_REG_EN | USB3VBUS_REG, + .disable_val = USB3VBUS_REG_EN, +}; + +static const struct regmap_config uniphier_usb3_regulator_regconf = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 1, +}; + +static const char * const uniphier_pro4_clock_reset_names[] = { + "gio", "link", +}; + +static const struct uniphier_regulator_soc_data uniphier_pro4_usb3_data = { + .nclks = ARRAY_SIZE(uniphier_pro4_clock_reset_names), + .clock_names = uniphier_pro4_clock_reset_names, + .nrsts = ARRAY_SIZE(uniphier_pro4_clock_reset_names), + .reset_names = uniphier_pro4_clock_reset_names, + .desc = &uniphier_usb3_regulator_desc, + .regconf = &uniphier_usb3_regulator_regconf, +}; + +static const char * const uniphier_pxs2_clock_reset_names[] = { + "link", +}; + +static const struct uniphier_regulator_soc_data uniphier_pxs2_usb3_data = { + .nclks = ARRAY_SIZE(uniphier_pxs2_clock_reset_names), + .clock_names = uniphier_pxs2_clock_reset_names, + .nrsts = ARRAY_SIZE(uniphier_pxs2_clock_reset_names), + .reset_names = uniphier_pxs2_clock_reset_names, + .desc = &uniphier_usb3_regulator_desc, + .regconf = &uniphier_usb3_regulator_regconf, +}; + +static const struct of_device_id uniphier_regulator_match[] = { + /* USB VBUS */ + { + .compatible = "socionext,uniphier-pro4-usb3-regulator", + .data = &uniphier_pro4_usb3_data, + }, + { + .compatible = "socionext,uniphier-pxs2-usb3-regulator", + .data = &uniphier_pxs2_usb3_data, + }, + { + .compatible = "socionext,uniphier-ld20-usb3-regulator", + .data = &uniphier_pxs2_usb3_data, + }, + { + .compatible = "socionext,uniphier-pxs3-usb3-regulator", + .data = &uniphier_pxs2_usb3_data, + }, + { /* Sentinel */ }, +}; + +static struct platform_driver uniphier_regulator_driver = { + .probe = uniphier_regulator_probe, + .remove = uniphier_regulator_remove, + .driver = { + .name = "uniphier-regulator", + .of_match_table = uniphier_regulator_match, + }, +}; +module_platform_driver(uniphier_regulator_driver); + +MODULE_AUTHOR("Kunihiko Hayashi "); +MODULE_DESCRIPTION("UniPhier Regulator Controller Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 02b3a073c12edc8cbc18e07e8880a32e78c1aee0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 16 Jul 2018 17:30:50 +0200 Subject: regulator: bd9571mwv: Use "backup_mode" sysfs file instead of "wake_up" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the BD9571MWV PMIC driver uses the standard "wake_up" sysfs file to control enablement of DDR Backup Mode. However, configuring DDR Backup Mode is not really equivalent to configuring the PMIC as a wake-up source. To avoid confusion, use a custom "backup_mode" attribute file in sysfs instead. Signed-off-by: Geert Uytterhoeven Reviewed-by: Niklas Söderlund Signed-off-by: Mark Brown --- drivers/regulator/bd9571mwv-regulator.c | 52 +++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/bd9571mwv-regulator.c b/drivers/regulator/bd9571mwv-regulator.c index be574eb444eb..1da36a6590c8 100644 --- a/drivers/regulator/bd9571mwv-regulator.c +++ b/drivers/regulator/bd9571mwv-regulator.c @@ -30,6 +30,7 @@ struct bd9571mwv_reg { /* DDR Backup Power */ u8 bkup_mode_cnt_keepon; /* from "rohm,ddr-backup-power" */ u8 bkup_mode_cnt_saved; + bool bkup_mode_enabled; /* Power switch type */ bool rstbmode_level; @@ -171,13 +172,40 @@ static int bd9571mwv_bkup_mode_write(struct bd9571mwv *bd, unsigned int mode) return 0; } +static ssize_t backup_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", bdreg->bkup_mode_enabled ? "on" : "off"); +} + +static ssize_t backup_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev); + int ret; + + if (!count) + return 0; + + ret = kstrtobool(buf, &bdreg->bkup_mode_enabled); + if (ret) + return ret; + + return count; +} + +DEVICE_ATTR_RW(backup_mode); + static int bd9571mwv_suspend(struct device *dev) { struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev); unsigned int mode; int ret; - if (!device_may_wakeup(dev)) + if (!bdreg->bkup_mode_enabled) return 0; /* Save DDR Backup Mode */ @@ -204,7 +232,7 @@ static int bd9571mwv_resume(struct device *dev) { struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev); - if (!device_may_wakeup(dev)) + if (!bdreg->bkup_mode_enabled) return 0; /* Restore DDR Backup Mode */ @@ -215,9 +243,15 @@ static const struct dev_pm_ops bd9571mwv_pm = { SET_SYSTEM_SLEEP_PM_OPS(bd9571mwv_suspend, bd9571mwv_resume) }; +static int bd9571mwv_regulator_remove(struct platform_device *pdev) +{ + device_remove_file(&pdev->dev, &dev_attr_backup_mode); + return 0; +} #define DEV_PM_OPS &bd9571mwv_pm #else #define DEV_PM_OPS NULL +#define bd9571mwv_regulator_remove NULL #endif /* CONFIG_PM_SLEEP */ static int bd9571mwv_regulator_probe(struct platform_device *pdev) @@ -270,14 +304,21 @@ static int bd9571mwv_regulator_probe(struct platform_device *pdev) return -EINVAL; } +#ifdef CONFIG_PM_SLEEP if (bdreg->bkup_mode_cnt_keepon) { - device_set_wakeup_capable(&pdev->dev, true); + int ret; + /* - * Wakeup is enabled by default in pulse mode, but needs + * Backup mode is enabled by default in pulse mode, but needs * explicit user setup in level mode. */ - device_set_wakeup_enable(&pdev->dev, bdreg->rstbmode_pulse); + bdreg->bkup_mode_enabled = bdreg->rstbmode_pulse; + + ret = device_create_file(&pdev->dev, &dev_attr_backup_mode); + if (ret) + return ret; } +#endif /* CONFIG_PM_SLEEP */ return 0; } @@ -294,6 +335,7 @@ static struct platform_driver bd9571mwv_regulator_driver = { .pm = DEV_PM_OPS, }, .probe = bd9571mwv_regulator_probe, + .remove = bd9571mwv_regulator_remove, .id_table = bd9571mwv_regulator_id_table, }; module_platform_driver(bd9571mwv_regulator_driver); -- cgit v1.2.3 From e436875f6f97708613976da75a92974f18998af9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 16 Jul 2018 17:30:51 +0200 Subject: regulator: bd9571mwv: Add support for toggle power switches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the existing support for backup mode to toggle power switches. With a toggle power switch (or level signal), the following steps must be followed exactly: 1. Configure PMIC for backup mode, to change the role of the accessory power switch from a power switch to a wake-up switch, 2. Switch accessory power switch off, to prepare for system suspend, which is a manual step not controlled by software, 3. Suspend system, 4. Switch accessory power switch on, to resume the system. Hence the PMIC is configured for backup mode when "on" or "1" is written to the PMIC's "backup_mode" virtual file in sysfs. Conversely, writing "off" or "0" reverts the role of the accessory switch to a power switch. Unlike with momentary switches, backup mode is not enabled by default, as enabling it prevents the board from being powered off using the power switch, which may confuse the user. Signed-off-by: Geert Uytterhoeven Reviewed-by: Niklas Söderlund Signed-off-by: Mark Brown --- drivers/regulator/bd9571mwv-regulator.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/bd9571mwv-regulator.c b/drivers/regulator/bd9571mwv-regulator.c index 1da36a6590c8..c44613b9423b 100644 --- a/drivers/regulator/bd9571mwv-regulator.c +++ b/drivers/regulator/bd9571mwv-regulator.c @@ -185,6 +185,7 @@ static ssize_t backup_mode_store(struct device *dev, const char *buf, size_t count) { struct bd9571mwv_reg *bdreg = dev_get_drvdata(dev); + unsigned int mode; int ret; if (!count) @@ -194,6 +195,25 @@ static ssize_t backup_mode_store(struct device *dev, if (ret) return ret; + if (!bdreg->rstbmode_level) + return count; + + /* + * Configure DDR Backup Mode, to change the role of the accessory power + * switch from a power switch to a wake-up switch, or vice versa + */ + ret = bd9571mwv_bkup_mode_read(bdreg->bd, &mode); + if (ret) + return ret; + + mode &= ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK; + if (bdreg->bkup_mode_enabled) + mode |= bdreg->bkup_mode_cnt_keepon; + + ret = bd9571mwv_bkup_mode_write(bdreg->bd, mode); + if (ret) + return ret; + return count; } -- cgit v1.2.3 From fffe7f52eb5db41eedadba9a8038e982dcfaee0c Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 16 Jul 2018 15:32:51 +0200 Subject: regulator: qcom_spmi: Fix warning Bad of_node_put() For of_find_node_by_name(), you typically pass what the previous call returned. Therefore, of_find_node_by_name() increases the refcount of the returned node, and decreases the refcount of the node passed as the first argument. of_find_node_by_name() is incorrectly used, and produces a warning. Fix the warning by using the more suitable function of_get_child_by_name(). Also add a missing of_node_put() for the returned value, since this was previously being leaked. OF: ERROR: Bad of_node_put() on /soc/qcom,spmi@400f000/pmic@3/regulators CPU: 1 PID: 1 Comm: swapper/0 Tainted: G W 4.18.0-rc4-00223-gefd7b360b70e #12 Hardware name: Qualcomm Technologies, Inc. DB820c (DT) Call trace: dump_backtrace+0x0/0x1a8 show_stack+0x14/0x20 dump_stack+0x90/0xb4 of_node_release+0x74/0x78 kobject_put+0x90/0x1f0 of_node_put+0x14/0x20 of_find_node_by_name+0x80/0xd8 qcom_spmi_regulator_probe+0x30c/0x508 Fixes: 0caecaa87202 ("regulator: qcom_spmi: Add support for SAW") Signed-off-by: Niklas Cassel Signed-off-by: Mark Brown --- drivers/regulator/qcom_spmi-regulator.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 9817f1a75342..4cc14c65d86b 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -1752,7 +1752,8 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) const char *name; struct device *dev = &pdev->dev; struct device_node *node = pdev->dev.of_node; - struct device_node *syscon; + struct device_node *syscon, *reg_node; + struct property *reg_prop; int ret, lenp; struct list_head *vreg_list; @@ -1780,10 +1781,13 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) for (reg = match->data; reg->name; reg++) { - if (saw_regmap && \ - of_find_property(of_find_node_by_name(node, reg->name), \ - "qcom,saw-slave", &lenp)) { - continue; + if (saw_regmap) { + reg_node = of_get_child_by_name(node, reg->name); + reg_prop = of_find_property(reg_node, "qcom,saw-slave", + &lenp); + of_node_put(reg_node); + if (reg_prop) + continue; } vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL); @@ -1816,13 +1820,17 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) if (ret) continue; - if (saw_regmap && \ - of_find_property(of_find_node_by_name(node, reg->name), \ - "qcom,saw-leader", &lenp)) { - spmi_saw_ops = *(vreg->desc.ops); - spmi_saw_ops.set_voltage_sel = \ - spmi_regulator_saw_set_voltage; - vreg->desc.ops = &spmi_saw_ops; + if (saw_regmap) { + reg_node = of_get_child_by_name(node, reg->name); + reg_prop = of_find_property(reg_node, "qcom,saw-leader", + &lenp); + of_node_put(reg_node); + if (reg_prop) { + spmi_saw_ops = *(vreg->desc.ops); + spmi_saw_ops.set_voltage_sel = + spmi_regulator_saw_set_voltage; + vreg->desc.ops = &spmi_saw_ops; + } } config.dev = dev; -- cgit v1.2.3 From 85046a15529606466bc778e1205f4cab8e3724d1 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 16 Jul 2018 15:32:52 +0200 Subject: regulator: qcom_spmi: Use correct regmap when checking for error Since we have just assigned saw_regmap, and since the error message refers to saw_regmap, it feels safe to assume that it is saw_regmap, and not regmap, that should be checked for errors. Fixes: 0caecaa87202 ("regulator: qcom_spmi: Add support for SAW") Signed-off-by: Niklas Cassel Signed-off-by: Mark Brown --- drivers/regulator/qcom_spmi-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 4cc14c65d86b..ba3d5e63ada6 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -1775,7 +1775,7 @@ static int qcom_spmi_regulator_probe(struct platform_device *pdev) syscon = of_parse_phandle(node, "qcom,saw-reg", 0); saw_regmap = syscon_node_to_regmap(syscon); of_node_put(syscon); - if (IS_ERR(regmap)) + if (IS_ERR(saw_regmap)) dev_err(dev, "ERROR reading SAW regmap\n"); } -- cgit v1.2.3 From 9689ca0af345b82d06a02e45cc214c1b8bad9e8d Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 16 Jul 2018 15:32:53 +0200 Subject: regulator: qcom_spmi: Do not initialise static to NULL Fix the following checkpatch error: ERROR: do not initialise statics to NULL +static struct regmap *saw_regmap = NULL; Fixes: 0caecaa87202 ("regulator: qcom_spmi: Add support for SAW") Signed-off-by: Niklas Cassel Signed-off-by: Mark Brown --- drivers/regulator/qcom_spmi-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index ba3d5e63ada6..5246f5b870c2 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -1060,7 +1060,7 @@ static irqreturn_t spmi_regulator_vs_ocp_isr(int irq, void *data) #define SAW3_AVS_CTL_TGGL_MASK 0x8000000 #define SAW3_AVS_CTL_CLEAR_MASK 0x7efc00 -static struct regmap *saw_regmap = NULL; +static struct regmap *saw_regmap; static void spmi_saw_set_vdd(void *data) { -- cgit v1.2.3 From 37164571fb25adef80ae2aaf55840b0105c15b22 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 16 Jul 2018 15:32:54 +0200 Subject: regulator: qcom_spmi: Indent with tabs instead of spaces Fix the following checkpatch error: ERROR: code indent should use tabs where possible + { }$ Fixes: ca5cd8c9400c ("regulator: qcom_spmi: Add support for pmi8994") Signed-off-by: Niklas Cassel Signed-off-by: Mark Brown --- drivers/regulator/qcom_spmi-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 5246f5b870c2..53a61fb65642 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -1728,7 +1728,7 @@ static const struct spmi_regulator_data pmi8994_regulators[] = { { "s2", 0x1700, "vdd_s2", }, { "s3", 0x1a00, "vdd_s3", }, { "l1", 0x4000, "vdd_l1", }, - { } + { } }; static const struct of_device_id qcom_spmi_regulator_match[] = { -- cgit v1.2.3 From 9d2fd4f0ddfbc4aa1135000df34caebc02793a26 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Mon, 23 Jul 2018 09:47:47 +0200 Subject: regulator: pfuze100: add support to en-/disable switch regulators Add enable/disable support for switch regulators on pfuze100. Based on commit 5fe156f1cab4 ("regulator: pfuze100: add enable/disable for switch") which is reverted due to boot regressions by commit 464a5686e6c9 ("regulator: Revert "regulator: pfuze100: add enable/disable for switch""). Disabling the switch regulators will only be done if the user specifies "fsl,pfuze-support-disable-sw" in its device tree to keep backward compatibility with current dtb's [1]. [1] https://patchwork.kernel.org/patch/10490381/ Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index cde6eda1d283..31c3a236120a 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -17,6 +17,8 @@ #include #include +#define PFUZE_FLAG_DISABLE_SW BIT(1) + #define PFUZE_NUMREGS 128 #define PFUZE100_VOL_OFFSET 0 #define PFUZE100_STANDBY_OFFSET 1 @@ -50,10 +52,12 @@ struct pfuze_regulator { struct regulator_desc desc; unsigned char stby_reg; unsigned char stby_mask; + bool sw_reg; }; struct pfuze_chip { int chip_id; + int flags; struct regmap *regmap; struct device *dev; struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR]; @@ -170,6 +174,17 @@ static const struct regulator_ops pfuze100_sw_regulator_ops = { .set_ramp_delay = pfuze100_set_ramp_delay, }; +static const struct regulator_ops pfuze100_sw_disable_regulator_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_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, + .set_ramp_delay = pfuze100_set_ramp_delay, +}; + static const struct regulator_ops pfuze100_swb_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -209,9 +224,12 @@ static const struct regulator_ops pfuze100_swb_regulator_ops = { .uV_step = (step), \ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ .vsel_mask = 0x3f, \ + .enable_reg = (base) + PFUZE100_MODE_OFFSET, \ + .enable_mask = 0xf, \ }, \ .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \ .stby_mask = 0x3f, \ + .sw_reg = true, \ } #define PFUZE100_SWB_REG(_chip, _name, base, mask, voltages) \ @@ -471,6 +489,9 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip) if (!np) return -EINVAL; + if (of_property_read_bool(np, "fsl,pfuze-support-disable-sw")) + chip->flags |= PFUZE_FLAG_DISABLE_SW; + parent = of_get_child_by_name(np, "regulators"); if (!parent) { dev_err(dev, "regulators node not found\n"); @@ -703,6 +724,21 @@ static int pfuze100_regulator_probe(struct i2c_client *client, } } + /* + * Allow SW regulators to turn off. Checking it trough a flag is + * a workaround to keep the backward compatibility with existing + * old dtb's which may relay on the fact that we didn't disable + * the switched regulator till yet. + */ + if (pfuze_chip->flags & PFUZE_FLAG_DISABLE_SW) { + if (pfuze_chip->regulator_descs[i].sw_reg) { + desc->ops = &pfuze100_sw_disable_regulator_ops; + desc->enable_val = 0x8; + desc->disable_val = 0x0; + desc->enable_time = 500; + } + } + config.dev = &client->dev; config.init_data = init_data; config.driver_data = pfuze_chip; -- cgit v1.2.3 From a70a4694ed38fb68407c142db0f53722553bedea Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 24 Jul 2018 06:32:59 +0000 Subject: regulator: bd9571mwv: Make symbol 'dev_attr_backup_mode' static Fixes the following sparse warning: drivers/regulator/bd9571mwv-regulator.c:220:1: warning: symbol 'dev_attr_backup_mode' was not declared. Should it be static? Signed-off-by: Wei Yongjun Reviewed-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/regulator/bd9571mwv-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/bd9571mwv-regulator.c b/drivers/regulator/bd9571mwv-regulator.c index c44613b9423b..274c5ed7cd73 100644 --- a/drivers/regulator/bd9571mwv-regulator.c +++ b/drivers/regulator/bd9571mwv-regulator.c @@ -217,7 +217,7 @@ static ssize_t backup_mode_store(struct device *dev, return count; } -DEVICE_ATTR_RW(backup_mode); +static DEVICE_ATTR_RW(backup_mode); static int bd9571mwv_suspend(struct device *dev) { -- cgit v1.2.3 From ad66225dff3f30fece4f5133ea14058c95f4e29a Mon Sep 17 00:00:00 2001 From: Peter Geis Date: Tue, 24 Jul 2018 09:25:40 -0400 Subject: regulator: Add sw2_sw4 voltage table to cpcap regulator. SW2 and SW4 use a shared table to provide voltage to the cpu core and devices on Tegra hardware. Added this table to the cpcap regulator driver as the first step to supporting this device on Tegra. Signed-off-by: Peter Geis Signed-off-by: Mark Brown --- drivers/regulator/cpcap-regulator.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/cpcap-regulator.c b/drivers/regulator/cpcap-regulator.c index bd910fe123d9..c0b1e04bd90f 100644 --- a/drivers/regulator/cpcap-regulator.c +++ b/drivers/regulator/cpcap-regulator.c @@ -271,6 +271,29 @@ static struct regulator_ops cpcap_regulator_ops = { }; static const unsigned int unknown_val_tbl[] = { 0, }; +static const unsigned int sw2_sw4_val_tbl[] = { 612500, 625000, 637500, + 650000, 662500, 675000, + 687500, 700000, 712500, + 725000, 737500, 750000, + 762500, 775000, 787500, + 800000, 812500, 825000, + 837500, 850000, 862500, + 875000, 887500, 900000, + 912500, 925000, 937500, + 950000, 962500, 975000, + 987500, 1000000, 1012500, + 1025000, 1037500, 1050000, + 1062500, 1075000, 1087500, + 1100000, 1112500, 1125000, + 1137500, 1150000, 1162500, + 1175000, 1187500, 1200000, + 1212500, 1225000, 1237500, + 1250000, 1262500, 1275000, + 1287500, 1300000, 1312500, + 1325000, 1337500, 1350000, + 1362500, 1375000, 1387500, + 1400000, 1412500, 1425000, + 1437500, 1450000, 1462500, }; static const unsigned int sw5_val_tbl[] = { 0, 5050000, }; static const unsigned int vcam_val_tbl[] = { 2600000, 2700000, 2800000, 2900000, }; -- cgit v1.2.3 From 6c0b319c0306accd92dc1601f8bf42adc147d4bf Mon Sep 17 00:00:00 2001 From: Peter Geis Date: Tue, 24 Jul 2018 09:25:41 -0400 Subject: regulator: Add support for CPCAP regulators on Motorola Xoom devices. Added support for the CPCAP power management regulator functions on Tegra based Motorola Xoom devices. Added sw2_sw4 value tables, which provide power to the Tegra core and aux devices. Added the Xoom init tables and device tree compatibility match. Signed-off-by: Peter Geis Signed-off-by: Mark Brown --- .../bindings/regulator/cpcap-regulator.txt | 1 + drivers/regulator/cpcap-regulator.c | 80 ++++++++++++++++++++++ 2 files changed, 81 insertions(+) (limited to 'drivers/regulator') diff --git a/Documentation/devicetree/bindings/regulator/cpcap-regulator.txt b/Documentation/devicetree/bindings/regulator/cpcap-regulator.txt index 675f4437ce92..36f5e2f5cc0f 100644 --- a/Documentation/devicetree/bindings/regulator/cpcap-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/cpcap-regulator.txt @@ -5,6 +5,7 @@ Requires node properties: - "compatible" value one of: "motorola,cpcap-regulator" "motorola,mapphone-cpcap-regulator" + "motorola,xoom-cpcap-regulator" Required regulator properties: - "regulator-name" diff --git a/drivers/regulator/cpcap-regulator.c b/drivers/regulator/cpcap-regulator.c index c0b1e04bd90f..2131457937b7 100644 --- a/drivers/regulator/cpcap-regulator.c +++ b/drivers/regulator/cpcap-regulator.c @@ -412,6 +412,82 @@ static struct cpcap_regulator omap4_regulators[] = { { /* sentinel */ }, }; +static 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), + CPCAP_REG(SW2, CPCAP_REG_S2C1, CPCAP_REG_ASSIGN2, + CPCAP_BIT_SW2_SEL, sw2_sw4_val_tbl, + 0xf00, 0x7f, 0, 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), + CPCAP_REG(SW4, CPCAP_REG_S4C1, CPCAP_REG_ASSIGN2, + CPCAP_BIT_SW4_SEL, sw2_sw4_val_tbl, + 0xf00, 0x7f, 0, 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), + CPCAP_REG(SW6, CPCAP_REG_S6C, CPCAP_REG_ASSIGN2, + CPCAP_BIT_SW6_SEL, unknown_val_tbl, + 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), + CPCAP_REG(VCSI, CPCAP_REG_VCSIC, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VCSI_SEL, vcsi_val_tbl, + 0x47, 0x10, 4, 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), + CPCAP_REG(VDIG, CPCAP_REG_VDIGC, CPCAP_REG_ASSIGN2, + CPCAP_BIT_VDIG_SEL, vdig_val_tbl, + 0x87, 0x30, 4, 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), + CPCAP_REG(VHVIO, CPCAP_REG_VHVIOC, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VHVIO_SEL, vhvio_val_tbl, + 0x17, 0, 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), + CPCAP_REG(VPLL, CPCAP_REG_VPLLC, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VPLL_SEL, vpll_val_tbl, + 0x43, 0x18, 3, 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), + CPCAP_REG(VRF2, CPCAP_REG_VRF2C, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VRF2_SEL, vrf2_val_tbl, + 0x23, 0x8, 3, 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), + CPCAP_REG(VWLAN1, CPCAP_REG_VWLAN1C, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VWLAN1_SEL, vwlan1_val_tbl, + 0x47, 0x10, 4, 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), + CPCAP_REG(VSIM, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3, + 0xffff, vsim_val_tbl, + 0x23, 0x8, 3, 0x3, 0, 420), + CPCAP_REG(VSIMCARD, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3, + 0xffff, vsimcard_val_tbl, + 0x1e80, 0x8, 3, 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), + CPCAP_REG(VUSB, CPCAP_REG_VUSBC, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VUSB_SEL, vusb_val_tbl, + 0x11c, 0x40, 6, 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), + { /* sentinel */ }, +}; + static const struct of_device_id cpcap_regulator_id_table[] = { { .compatible = "motorola,cpcap-regulator", @@ -420,6 +496,10 @@ static const struct of_device_id cpcap_regulator_id_table[] = { .compatible = "motorola,mapphone-cpcap-regulator", .data = omap4_regulators, }, + { + .compatible = "motorola,xoom-cpcap-regulator", + .data = xoom_regulators, + }, {}, }; MODULE_DEVICE_TABLE(of, cpcap_regulator_id_table); -- cgit v1.2.3 From 4f919ca2bf6da826ba1a4316e1b8e9c94e5dbeb2 Mon Sep 17 00:00:00 2001 From: Anton Vasilyev Date: Fri, 27 Jul 2018 16:59:29 +0300 Subject: regulator: tps65217: Fix NULL pointer dereference on probe There is no check that tps->strobes is allocated successfully in tps65217_regulator_probe(). The patch adds corresponding check. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Anton Vasilyev Signed-off-by: Mark Brown --- drivers/regulator/tps65217-regulator.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index fc12badf3805..d84fab616abf 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -232,6 +232,8 @@ static int tps65217_regulator_probe(struct platform_device *pdev) tps->strobes = devm_kcalloc(&pdev->dev, TPS65217_NUM_REGULATOR, sizeof(u8), GFP_KERNEL); + if (!tps->strobes) + return -ENOMEM; platform_set_drvdata(pdev, tps); -- cgit v1.2.3 From 410e8b4f5ca34e026ffc460a86e2354febe06fac Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 30 Jul 2018 14:50:08 +0300 Subject: regulator: bd71837: adobt MFD changes to regulator driver MFD part for bd71837 was changed during the review. Clean regulator part to match changed MFD: - renamed header file => fix include - remove unused platdata as also type definition was removed - Kconfig option for MFD part was changed => fix depends on clause - Rename Kconfig option for regulators As Kconfig option for regulators gets now used (when dependency to MFD is satisfied) change it so that it won't require new change when support for bd71847 is added. Signed-off-by: Matti Vaittinen Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 4 ++-- drivers/regulator/Makefile | 2 +- drivers/regulator/bd71837-regulator.c | 7 +------ 3 files changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 8233dc7f0a68..347351e79b1e 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -180,9 +180,9 @@ config REGULATOR_BCM590XX BCM590xx PMUs. This will enable support for the software controllable LDO/Switching regulators. -config REGULATOR_BD71837 +config REGULATOR_BD718XX tristate "ROHM BD71837 Power Regulator" - depends on MFD_BD71837 + depends on MFD_ROHM_BD718XX help This driver supports voltage regulators on ROHM BD71837 PMIC. This will enable support for the software controllable buck diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index b7839f41591e..18bfed61e7fe 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -27,7 +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_BD71837) += bd71837-regulator.o +obj-$(CONFIG_REGULATOR_BD718XX) += bd71837-regulator.o obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o diff --git a/drivers/regulator/bd71837-regulator.c b/drivers/regulator/bd71837-regulator.c index 3a487255482c..0f8ac8dec3e1 100644 --- a/drivers/regulator/bd71837-regulator.c +++ b/drivers/regulator/bd71837-regulator.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -490,7 +490,6 @@ struct reg_init { static int bd71837_probe(struct platform_device *pdev) { struct bd71837_pmic *pmic; - struct bd71837_board *pdata; struct regulator_config config = { 0 }; struct reg_init pmic_regulator_inits[] = { { @@ -558,7 +557,6 @@ static int bd71837_probe(struct platform_device *pdev) goto err; } platform_set_drvdata(pdev, pmic); - pdata = dev_get_platdata(pmic->mfd->dev); /* Register LOCK release */ err = regmap_update_bits(pmic->mfd->regmap, BD71837_REG_REGLOCK, @@ -578,9 +576,6 @@ static int bd71837_probe(struct platform_device *pdev) desc = &pmic->descs[i]; - if (pdata) - config.init_data = pdata->init_data[i]; - config.dev = pdev->dev.parent; config.driver_data = pmic; config.regmap = pmic->mfd->regmap; -- cgit v1.2.3 From 5e9384c705fcfa6bf6d3937967df3ab1f5e414cb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Aug 2018 18:18:25 +0200 Subject: regulator: maxim: Add SPDX license identifiers Replace GPL v2.0 and v2.0+ license statements with SPDX license identifiers. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/max14577-regulator.c | 22 +++++------------ drivers/regulator/max77686-regulator.c | 32 +++++++----------------- drivers/regulator/max77693-regulator.c | 32 +++++++----------------- drivers/regulator/max77802-regulator.c | 34 +++++++++----------------- drivers/regulator/max8997-regulator.c | 30 ++++++----------------- drivers/regulator/max8998.c | 28 ++++++--------------- include/dt-bindings/regulator/maxim,max77802.h | 5 +--- 7 files changed, 52 insertions(+), 131 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/max14577-regulator.c b/drivers/regulator/max14577-regulator.c index 0db288ce319c..bc7f4751bf9c 100644 --- a/drivers/regulator/max14577-regulator.c +++ b/drivers/regulator/max14577-regulator.c @@ -1,19 +1,9 @@ -/* - * max14577.c - Regulator driver for the Maxim 14577/77836 - * - * Copyright (C) 2013,2014 Samsung Electronics - * Krzysztof Kozlowski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// max14577.c - Regulator driver for the Maxim 14577/77836 +// +// Copyright (C) 2013,2014 Samsung Electronics +// Krzysztof Kozlowski #include #include diff --git a/drivers/regulator/max77686-regulator.c b/drivers/regulator/max77686-regulator.c index c301f3733475..bee060937f56 100644 --- a/drivers/regulator/max77686-regulator.c +++ b/drivers/regulator/max77686-regulator.c @@ -1,26 +1,12 @@ -/* - * max77686.c - Regulator driver for the Maxim 77686 - * - * Copyright (C) 2012 Samsung Electronics - * Chiwoong Byun - * Jonghwa Lee - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This driver is based on max8997.c - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// max77686.c - Regulator driver for the Maxim 77686 +// +// Copyright (C) 2012 Samsung Electronics +// Chiwoong Byun +// Jonghwa Lee +// +// This driver is based on max8997.c #include #include diff --git a/drivers/regulator/max77693-regulator.c b/drivers/regulator/max77693-regulator.c index e7000e777292..077ecbbfdf76 100644 --- a/drivers/regulator/max77693-regulator.c +++ b/drivers/regulator/max77693-regulator.c @@ -1,26 +1,12 @@ -/* - * max77693.c - Regulator driver for the Maxim 77693 and 77843 - * - * Copyright (C) 2013-2015 Samsung Electronics - * Jonghwa Lee - * Krzysztof Kozlowski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This driver is based on max77686.c - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// max77693.c - Regulator driver for the Maxim 77693 and 77843 +// +// Copyright (C) 2013-2015 Samsung Electronics +// Jonghwa Lee +// Krzysztof Kozlowski +// +// This driver is based on max77686.c #include #include diff --git a/drivers/regulator/max77802-regulator.c b/drivers/regulator/max77802-regulator.c index b6261903818c..c30cf5c9f2de 100644 --- a/drivers/regulator/max77802-regulator.c +++ b/drivers/regulator/max77802-regulator.c @@ -1,25 +1,15 @@ -/* - * max77802.c - Regulator driver for the Maxim 77802 - * - * Copyright (C) 2013-2014 Google, Inc - * Simon Glass - * - * Copyright (C) 2012 Samsung Electronics - * Chiwoong Byun - * Jonghwa Lee - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This driver is based on max8997.c - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// max77802.c - Regulator driver for the Maxim 77802 +// +// Copyright (C) 2013-2014 Google, Inc +// Simon Glass +// +// Copyright (C) 2012 Samsung Electronics +// Chiwoong Byun +// Jonghwa Lee +// +// This driver is based on max8997.c #include #include diff --git a/drivers/regulator/max8997-regulator.c b/drivers/regulator/max8997-regulator.c index 029a6ee426ab..ad0c806b0737 100644 --- a/drivers/regulator/max8997-regulator.c +++ b/drivers/regulator/max8997-regulator.c @@ -1,25 +1,11 @@ -/* - * max8997.c - Regulator driver for the Maxim 8997/8966 - * - * Copyright (C) 2011 Samsung Electronics - * MyungJoo Ham - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This driver is based on max8998.c - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// max8997.c - Regulator driver for the Maxim 8997/8966 +// +// Copyright (C) 2011 Samsung Electronics +// MyungJoo Ham +// +// This driver is based on max8998.c #include #include diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 6b9f262ebbb0..271bb736f3f5 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -1,24 +1,10 @@ -/* - * max8998.c - Voltage regulator driver for the Maxim 8998 - * - * Copyright (C) 2009-2010 Samsung Electronics - * Kyungmin Park - * Marek Szyprowski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// max8998.c - Voltage regulator driver for the Maxim 8998 +// +// Copyright (C) 2009-2010 Samsung Electronics +// Kyungmin Park +// Marek Szyprowski #include #include diff --git a/include/dt-bindings/regulator/maxim,max77802.h b/include/dt-bindings/regulator/maxim,max77802.h index cf28631d7109..d0baba1973d4 100644 --- a/include/dt-bindings/regulator/maxim,max77802.h +++ b/include/dt-bindings/regulator/maxim,max77802.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2014 Google, Inc * - * 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. - * * Device Tree binding constants for the Maxim 77802 PMIC regulators */ -- cgit v1.2.3 From 4f3fb287358337d739bd2186769a8c74aae19ac6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Aug 2018 18:18:26 +0200 Subject: regulator: samsung: Add SPDX license identifiers Replace GPL v2.0+ license statements with SPDX license identifiers. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/s2mpa01.c | 14 ++++---------- drivers/regulator/s2mps11.c | 21 ++++----------------- drivers/regulator/s5m8767.c | 16 ++++------------ 3 files changed, 12 insertions(+), 39 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c index 48f0ca90743c..095d25f3d2ea 100644 --- a/drivers/regulator/s2mpa01.c +++ b/drivers/regulator/s2mpa01.c @@ -1,13 +1,7 @@ -/* - * Copyright (c) 2013 Samsung Electronics Co., Ltd - * http://www.samsung.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2013 Samsung Electronics Co., Ltd +// http://www.samsung.com #include #include diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index d1207ec683db..5bb6f4ca48db 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -1,20 +1,7 @@ -/* - * s2mps11.c - * - * Copyright (c) 2012-2014 Samsung Electronics Co., Ltd - * http://www.samsung.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2012-2014 Samsung Electronics Co., Ltd +// http://www.samsung.com #include #include diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 0cbc980753c2..667d16dc83ce 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -1,15 +1,7 @@ -/* - * s5m8767.c - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd - * http://www.samsung.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2011 Samsung Electronics Co., Ltd +// http://www.samsung.com #include #include -- cgit v1.2.3 From 46fc033eba42f5a4fb583b2ab53f0a9918468452 Mon Sep 17 00:00:00 2001 From: David Collins Date: Fri, 13 Jul 2018 18:50:59 -0700 Subject: regulator: add QCOM RPMh regulator driver Add the QCOM RPMh regulator driver to manage PMIC regulators which are controlled via RPMh on some Qualcomm Technologies, Inc. SoCs. RPMh is a hardware block which contains several accelerators which are used to manage various hardware resources that are shared between the processors of the SoC. The final hardware state of a regulator is determined within RPMh by performing max aggregation of the requests made by all of the processors. Add support for PMIC regulator control via the voltage regulator manager (VRM) and oscillator buffer (XOB) RPMh accelerators. VRM supports manipulation of enable state, voltage, and mode. XOB supports manipulation of enable state. Signed-off-by: David Collins Reviewed-by: Douglas Anderson Reviewed-by: Matthias Kaehlcke Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 9 + drivers/regulator/Makefile | 1 + drivers/regulator/qcom-rpmh-regulator.c | 769 ++++++++++++++++++++++++++++++++ 3 files changed, 779 insertions(+) create mode 100644 drivers/regulator/qcom-rpmh-regulator.c (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 347351e79b1e..329cdd33ed62 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -682,6 +682,15 @@ config REGULATOR_QCOM_RPM Qualcomm RPM as a module. The module will be named "qcom_rpm-regulator". +config REGULATOR_QCOM_RPMH + tristate "Qualcomm Technologies, Inc. RPMh regulator driver" + depends on QCOM_RPMH || COMPILE_TEST + help + This driver supports control of PMIC regulators via the RPMh hardware + block found on Qualcomm Technologies Inc. SoCs. RPMh regulator + control allows for voting on regulator state between multiple + processors within the SoC. + config REGULATOR_QCOM_SMD_RPM tristate "Qualcomm SMD based RPM regulator driver" depends on QCOM_SMD_RPM diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 18bfed61e7fe..801d9a34a203 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o +obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c new file mode 100644 index 000000000000..9f27daebd8c8 --- /dev/null +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -0,0 +1,769 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018, The Linux Foundation. All rights reserved. + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +/** + * enum rpmh_regulator_type - supported RPMh accelerator types + * %VRM: RPMh VRM accelerator which supports voting on enable, voltage, + * and mode of LDO, SMPS, and BOB type PMIC regulators. + * %XOB: RPMh XOB accelerator which supports voting on the enable state + * of PMIC regulators. + */ +enum rpmh_regulator_type { + VRM, + XOB, +}; + +#define RPMH_REGULATOR_REG_VRM_VOLTAGE 0x0 +#define RPMH_REGULATOR_REG_ENABLE 0x4 +#define RPMH_REGULATOR_REG_VRM_MODE 0x8 + +#define PMIC4_LDO_MODE_RETENTION 4 +#define PMIC4_LDO_MODE_LPM 5 +#define PMIC4_LDO_MODE_HPM 7 + +#define PMIC4_SMPS_MODE_RETENTION 4 +#define PMIC4_SMPS_MODE_PFM 5 +#define PMIC4_SMPS_MODE_AUTO 6 +#define PMIC4_SMPS_MODE_PWM 7 + +#define PMIC4_BOB_MODE_PASS 0 +#define PMIC4_BOB_MODE_PFM 1 +#define PMIC4_BOB_MODE_AUTO 2 +#define PMIC4_BOB_MODE_PWM 3 + +/** + * struct rpmh_vreg_hw_data - RPMh regulator hardware configurations + * @regulator_type: RPMh accelerator type used to manage this + * regulator + * @ops: Pointer to regulator ops callback structure + * @voltage_range: The single range of voltages supported by this + * PMIC regulator type + * @n_voltages: The number of unique voltage set points defined + * by voltage_range + * @hpm_min_load_uA: Minimum load current in microamps that requires + * high power mode (HPM) operation. This is used + * for LDO hardware type regulators only. + * @pmic_mode_map: Array indexed by regulator framework mode + * containing PMIC hardware modes. Must be large + * enough to index all framework modes supported + * by this regulator hardware type. + * @of_map_mode: Maps an RPMH_REGULATOR_MODE_* mode value defined + * in device tree to a regulator framework mode + */ +struct rpmh_vreg_hw_data { + enum rpmh_regulator_type regulator_type; + const struct regulator_ops *ops; + const struct regulator_linear_range voltage_range; + int n_voltages; + int hpm_min_load_uA; + const int *pmic_mode_map; + unsigned int (*of_map_mode)(unsigned int mode); +}; + +/** + * struct rpmh_vreg - individual RPMh regulator data structure encapsulating a + * single regulator device + * @dev: Device pointer for the top-level PMIC RPMh + * regulator parent device. This is used as a + * handle in RPMh write requests. + * @addr: Base address of the regulator resource within + * an RPMh accelerator + * @rdesc: Regulator descriptor + * @hw_data: PMIC regulator configuration data for this RPMh + * regulator + * @always_wait_for_ack: Boolean flag indicating if a request must always + * wait for an ACK from RPMh before continuing even + * if it corresponds to a strictly lower power + * state (e.g. enabled --> disabled). + * @enabled: Flag indicating if the regulator is enabled or + * not + * @bypassed: Boolean indicating if the regulator is in + * bypass (pass-through) mode or not. This is + * only used by BOB rpmh-regulator resources. + * @voltage_selector: Selector used for get_voltage_sel() and + * set_voltage_sel() callbacks + * @mode: RPMh VRM regulator current framework mode + */ +struct rpmh_vreg { + struct device *dev; + u32 addr; + struct regulator_desc rdesc; + const struct rpmh_vreg_hw_data *hw_data; + bool always_wait_for_ack; + + int enabled; + bool bypassed; + int voltage_selector; + unsigned int mode; +}; + +/** + * struct rpmh_vreg_init_data - initialization data for an RPMh regulator + * @name: Name for the regulator which also corresponds + * to the device tree subnode name of the regulator + * @resource_name: RPMh regulator resource name format string. + * This must include exactly one field: '%s' which + * is filled at run-time with the PMIC ID provided + * by device tree property qcom,pmic-id. Example: + * "ldo%s1" for RPMh resource "ldoa1". + * @supply_name: Parent supply regulator name + * @hw_data: Configuration data for this PMIC regulator type + */ +struct rpmh_vreg_init_data { + const char *name; + const char *resource_name; + const char *supply_name; + const struct rpmh_vreg_hw_data *hw_data; +}; + +/** + * rpmh_regulator_send_request() - send the request to RPMh + * @vreg: Pointer to the RPMh regulator + * @cmd: Pointer to the RPMh command to send + * @wait_for_ack: Boolean indicating if execution must wait until the + * request has been acknowledged as complete + * + * Return: 0 on success, errno on failure + */ +static int rpmh_regulator_send_request(struct rpmh_vreg *vreg, + struct tcs_cmd *cmd, bool wait_for_ack) +{ + int ret; + + if (wait_for_ack || vreg->always_wait_for_ack) + ret = rpmh_write(vreg->dev, RPMH_ACTIVE_ONLY_STATE, cmd, 1); + else + ret = rpmh_write_async(vreg->dev, RPMH_ACTIVE_ONLY_STATE, cmd, + 1); + + return ret; +} + +static int _rpmh_regulator_vrm_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector, bool wait_for_ack) +{ + struct rpmh_vreg *vreg = rdev_get_drvdata(rdev); + struct tcs_cmd cmd = { + .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_VOLTAGE, + }; + int ret; + + /* VRM voltage control register is set with voltage in millivolts. */ + cmd.data = DIV_ROUND_UP(regulator_list_voltage_linear_range(rdev, + selector), 1000); + + ret = rpmh_regulator_send_request(vreg, &cmd, wait_for_ack); + if (!ret) + vreg->voltage_selector = selector; + + return ret; +} + +static int rpmh_regulator_vrm_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + struct rpmh_vreg *vreg = rdev_get_drvdata(rdev); + + if (vreg->enabled == -EINVAL) { + /* + * Cache the voltage and send it later when the regulator is + * enabled or disabled. + */ + vreg->voltage_selector = selector; + return 0; + } + + return _rpmh_regulator_vrm_set_voltage_sel(rdev, selector, + selector > vreg->voltage_selector); +} + +static int rpmh_regulator_vrm_get_voltage_sel(struct regulator_dev *rdev) +{ + struct rpmh_vreg *vreg = rdev_get_drvdata(rdev); + + return vreg->voltage_selector; +} + +static int rpmh_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct rpmh_vreg *vreg = rdev_get_drvdata(rdev); + + return vreg->enabled; +} + +static int rpmh_regulator_set_enable_state(struct regulator_dev *rdev, + bool enable) +{ + struct rpmh_vreg *vreg = rdev_get_drvdata(rdev); + struct tcs_cmd cmd = { + .addr = vreg->addr + RPMH_REGULATOR_REG_ENABLE, + .data = enable, + }; + int ret; + + if (vreg->enabled == -EINVAL && + vreg->voltage_selector != -ENOTRECOVERABLE) { + ret = _rpmh_regulator_vrm_set_voltage_sel(rdev, + vreg->voltage_selector, true); + if (ret < 0) + return ret; + } + + ret = rpmh_regulator_send_request(vreg, &cmd, enable); + if (!ret) + vreg->enabled = enable; + + return ret; +} + +static int rpmh_regulator_enable(struct regulator_dev *rdev) +{ + return rpmh_regulator_set_enable_state(rdev, true); +} + +static int rpmh_regulator_disable(struct regulator_dev *rdev) +{ + return rpmh_regulator_set_enable_state(rdev, false); +} + +static int rpmh_regulator_vrm_set_mode_bypass(struct rpmh_vreg *vreg, + unsigned int mode, bool bypassed) +{ + struct tcs_cmd cmd = { + .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_MODE, + }; + int pmic_mode; + + if (mode > REGULATOR_MODE_STANDBY) + return -EINVAL; + + pmic_mode = vreg->hw_data->pmic_mode_map[mode]; + if (pmic_mode < 0) + return pmic_mode; + + if (bypassed) + cmd.data = PMIC4_BOB_MODE_PASS; + else + cmd.data = pmic_mode; + + return rpmh_regulator_send_request(vreg, &cmd, true); +} + +static int rpmh_regulator_vrm_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct rpmh_vreg *vreg = rdev_get_drvdata(rdev); + int ret; + + if (mode == vreg->mode) + return 0; + + ret = rpmh_regulator_vrm_set_mode_bypass(vreg, mode, vreg->bypassed); + if (!ret) + vreg->mode = mode; + + return ret; +} + +static unsigned int rpmh_regulator_vrm_get_mode(struct regulator_dev *rdev) +{ + struct rpmh_vreg *vreg = rdev_get_drvdata(rdev); + + return vreg->mode; +} + +/** + * rpmh_regulator_vrm_set_load() - set the regulator mode based upon the load + * current requested + * @rdev: Regulator device pointer for the rpmh-regulator + * @load_uA: Aggregated load current in microamps + * + * This function is used in the regulator_ops for VRM type RPMh regulator + * devices. + * + * Return: 0 on success, errno on failure + */ +static int rpmh_regulator_vrm_set_load(struct regulator_dev *rdev, int load_uA) +{ + struct rpmh_vreg *vreg = rdev_get_drvdata(rdev); + unsigned int mode; + + if (load_uA >= vreg->hw_data->hpm_min_load_uA) + mode = REGULATOR_MODE_NORMAL; + else + mode = REGULATOR_MODE_IDLE; + + return rpmh_regulator_vrm_set_mode(rdev, mode); +} + +static int rpmh_regulator_vrm_set_bypass(struct regulator_dev *rdev, + bool enable) +{ + struct rpmh_vreg *vreg = rdev_get_drvdata(rdev); + int ret; + + if (vreg->bypassed == enable) + return 0; + + ret = rpmh_regulator_vrm_set_mode_bypass(vreg, vreg->mode, enable); + if (!ret) + vreg->bypassed = enable; + + return ret; +} + +static int rpmh_regulator_vrm_get_bypass(struct regulator_dev *rdev, + bool *enable) +{ + struct rpmh_vreg *vreg = rdev_get_drvdata(rdev); + + *enable = vreg->bypassed; + + return 0; +} + +static const struct regulator_ops rpmh_regulator_vrm_ops = { + .enable = rpmh_regulator_enable, + .disable = rpmh_regulator_disable, + .is_enabled = rpmh_regulator_is_enabled, + .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel, + .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel, + .list_voltage = regulator_list_voltage_linear_range, + .set_mode = rpmh_regulator_vrm_set_mode, + .get_mode = rpmh_regulator_vrm_get_mode, +}; + +static const struct regulator_ops rpmh_regulator_vrm_drms_ops = { + .enable = rpmh_regulator_enable, + .disable = rpmh_regulator_disable, + .is_enabled = rpmh_regulator_is_enabled, + .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel, + .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel, + .list_voltage = regulator_list_voltage_linear_range, + .set_mode = rpmh_regulator_vrm_set_mode, + .get_mode = rpmh_regulator_vrm_get_mode, + .set_load = rpmh_regulator_vrm_set_load, +}; + +static const struct regulator_ops rpmh_regulator_vrm_bypass_ops = { + .enable = rpmh_regulator_enable, + .disable = rpmh_regulator_disable, + .is_enabled = rpmh_regulator_is_enabled, + .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel, + .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel, + .list_voltage = regulator_list_voltage_linear_range, + .set_mode = rpmh_regulator_vrm_set_mode, + .get_mode = rpmh_regulator_vrm_get_mode, + .set_bypass = rpmh_regulator_vrm_set_bypass, + .get_bypass = rpmh_regulator_vrm_get_bypass, +}; + +static const struct regulator_ops rpmh_regulator_xob_ops = { + .enable = rpmh_regulator_enable, + .disable = rpmh_regulator_disable, + .is_enabled = rpmh_regulator_is_enabled, +}; + +/** + * rpmh_regulator_init_vreg() - initialize all attributes of an rpmh-regulator + * vreg: Pointer to the individual rpmh-regulator resource + * dev: Pointer to the top level rpmh-regulator PMIC device + * node: Pointer to the individual rpmh-regulator resource + * device node + * pmic_id: String used to identify the top level rpmh-regulator + * PMIC device on the board + * pmic_rpmh_data: Pointer to a null-terminated array of rpmh-regulator + * resources defined for the top level PMIC device + * + * Return: 0 on success, errno on failure + */ +static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev, + struct device_node *node, const char *pmic_id, + const struct rpmh_vreg_init_data *pmic_rpmh_data) +{ + struct regulator_config reg_config = {}; + char rpmh_resource_name[20] = ""; + const struct rpmh_vreg_init_data *rpmh_data; + struct regulator_init_data *init_data; + struct regulator_dev *rdev; + int ret; + + vreg->dev = dev; + + for (rpmh_data = pmic_rpmh_data; rpmh_data->name; rpmh_data++) + if (!strcmp(rpmh_data->name, node->name)) + break; + + if (!rpmh_data->name) { + dev_err(dev, "Unknown regulator %s\n", node->name); + return -EINVAL; + } + + scnprintf(rpmh_resource_name, sizeof(rpmh_resource_name), + rpmh_data->resource_name, pmic_id); + + vreg->addr = cmd_db_read_addr(rpmh_resource_name); + if (!vreg->addr) { + dev_err(dev, "%s: could not find RPMh address for resource %s\n", + node->name, rpmh_resource_name); + return -ENODEV; + } + + vreg->rdesc.name = rpmh_data->name; + vreg->rdesc.supply_name = rpmh_data->supply_name; + vreg->hw_data = rpmh_data->hw_data; + + vreg->enabled = -EINVAL; + vreg->voltage_selector = -ENOTRECOVERABLE; + vreg->mode = REGULATOR_MODE_INVALID; + + if (rpmh_data->hw_data->n_voltages) { + vreg->rdesc.linear_ranges = &rpmh_data->hw_data->voltage_range; + vreg->rdesc.n_linear_ranges = 1; + vreg->rdesc.n_voltages = rpmh_data->hw_data->n_voltages; + } + + vreg->always_wait_for_ack = of_property_read_bool(node, + "qcom,always-wait-for-ack"); + + vreg->rdesc.owner = THIS_MODULE; + vreg->rdesc.type = REGULATOR_VOLTAGE; + vreg->rdesc.ops = vreg->hw_data->ops; + vreg->rdesc.of_map_mode = vreg->hw_data->of_map_mode; + + init_data = of_get_regulator_init_data(dev, node, &vreg->rdesc); + if (!init_data) + return -ENOMEM; + + if (rpmh_data->hw_data->regulator_type == XOB && + init_data->constraints.min_uV && + init_data->constraints.min_uV == init_data->constraints.max_uV) { + vreg->rdesc.fixed_uV = init_data->constraints.min_uV; + vreg->rdesc.n_voltages = 1; + } + + reg_config.dev = dev; + reg_config.init_data = init_data; + reg_config.of_node = node; + reg_config.driver_data = vreg; + + rdev = devm_regulator_register(dev, &vreg->rdesc, ®_config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(dev, "%s: devm_regulator_register() failed, ret=%d\n", + node->name, ret); + return ret; + } + + dev_dbg(dev, "%s regulator registered for RPMh resource %s @ 0x%05X\n", + node->name, rpmh_resource_name, vreg->addr); + + return 0; +} + +static const int pmic_mode_map_pmic4_ldo[REGULATOR_MODE_STANDBY + 1] = { + [REGULATOR_MODE_INVALID] = -EINVAL, + [REGULATOR_MODE_STANDBY] = PMIC4_LDO_MODE_RETENTION, + [REGULATOR_MODE_IDLE] = PMIC4_LDO_MODE_LPM, + [REGULATOR_MODE_NORMAL] = PMIC4_LDO_MODE_HPM, + [REGULATOR_MODE_FAST] = -EINVAL, +}; + +static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode) +{ + unsigned int mode; + + switch (rpmh_mode) { + case RPMH_REGULATOR_MODE_HPM: + mode = REGULATOR_MODE_NORMAL; + break; + case RPMH_REGULATOR_MODE_LPM: + mode = REGULATOR_MODE_IDLE; + break; + case RPMH_REGULATOR_MODE_RET: + mode = REGULATOR_MODE_STANDBY; + break; + default: + mode = REGULATOR_MODE_INVALID; + } + + return mode; +} + +static const int pmic_mode_map_pmic4_smps[REGULATOR_MODE_STANDBY + 1] = { + [REGULATOR_MODE_INVALID] = -EINVAL, + [REGULATOR_MODE_STANDBY] = PMIC4_SMPS_MODE_RETENTION, + [REGULATOR_MODE_IDLE] = PMIC4_SMPS_MODE_PFM, + [REGULATOR_MODE_NORMAL] = PMIC4_SMPS_MODE_AUTO, + [REGULATOR_MODE_FAST] = PMIC4_SMPS_MODE_PWM, +}; + +static unsigned int +rpmh_regulator_pmic4_smps_of_map_mode(unsigned int rpmh_mode) +{ + unsigned int mode; + + switch (rpmh_mode) { + case RPMH_REGULATOR_MODE_HPM: + mode = REGULATOR_MODE_FAST; + break; + case RPMH_REGULATOR_MODE_AUTO: + mode = REGULATOR_MODE_NORMAL; + break; + case RPMH_REGULATOR_MODE_LPM: + mode = REGULATOR_MODE_IDLE; + break; + case RPMH_REGULATOR_MODE_RET: + mode = REGULATOR_MODE_STANDBY; + break; + default: + mode = REGULATOR_MODE_INVALID; + } + + return mode; +} + +static const int pmic_mode_map_pmic4_bob[REGULATOR_MODE_STANDBY + 1] = { + [REGULATOR_MODE_INVALID] = -EINVAL, + [REGULATOR_MODE_STANDBY] = -EINVAL, + [REGULATOR_MODE_IDLE] = PMIC4_BOB_MODE_PFM, + [REGULATOR_MODE_NORMAL] = PMIC4_BOB_MODE_AUTO, + [REGULATOR_MODE_FAST] = PMIC4_BOB_MODE_PWM, +}; + +static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int rpmh_mode) +{ + unsigned int mode; + + switch (rpmh_mode) { + case RPMH_REGULATOR_MODE_HPM: + mode = REGULATOR_MODE_FAST; + break; + case RPMH_REGULATOR_MODE_AUTO: + mode = REGULATOR_MODE_NORMAL; + break; + case RPMH_REGULATOR_MODE_LPM: + mode = REGULATOR_MODE_IDLE; + break; + default: + mode = REGULATOR_MODE_INVALID; + } + + return mode; +} + +static const struct rpmh_vreg_hw_data pmic4_pldo = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(1664000, 0, 255, 8000), + .n_voltages = 256, + .hpm_min_load_uA = 10000, + .pmic_mode_map = pmic_mode_map_pmic4_ldo, + .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic4_pldo_lv = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(1256000, 0, 127, 8000), + .n_voltages = 128, + .hpm_min_load_uA = 10000, + .pmic_mode_map = pmic_mode_map_pmic4_ldo, + .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic4_nldo = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000), + .n_voltages = 128, + .hpm_min_load_uA = 30000, + .pmic_mode_map = pmic_mode_map_pmic4_ldo, + .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic4_hfsmps3 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000), + .n_voltages = 216, + .pmic_mode_map = pmic_mode_map_pmic4_smps, + .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic4_ftsmps426 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 258, 4000), + .n_voltages = 259, + .pmic_mode_map = pmic_mode_map_pmic4_smps, + .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic4_bob = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_bypass_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(1824000, 0, 83, 32000), + .n_voltages = 84, + .pmic_mode_map = pmic_mode_map_pmic4_bob, + .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic4_lvs = { + .regulator_type = XOB, + .ops = &rpmh_regulator_xob_ops, + /* LVS hardware does not support voltage or mode configuration. */ +}; + +#define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \ +{ \ + .name = _name, \ + .resource_name = _resource_name, \ + .hw_data = _hw_data, \ + .supply_name = _supply_name, \ +} + +static const struct rpmh_vreg_init_data pm8998_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic4_hfsmps3, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic4_hfsmps3, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic4_hfsmps3, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic4_ftsmps426, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic4_ftsmps426, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic4_ftsmps426, "vdd-s8"), + RPMH_VREG("smps9", "smp%s9", &pmic4_ftsmps426, "vdd-s9"), + RPMH_VREG("smps10", "smp%s10", &pmic4_ftsmps426, "vdd-s10"), + RPMH_VREG("smps11", "smp%s11", &pmic4_ftsmps426, "vdd-s11"), + RPMH_VREG("smps12", "smp%s12", &pmic4_ftsmps426, "vdd-s12"), + RPMH_VREG("smps13", "smp%s13", &pmic4_ftsmps426, "vdd-s13"), + RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l27"), + RPMH_VREG("ldo2", "ldo%s2", &pmic4_nldo, "vdd-l2-l8-l17"), + RPMH_VREG("ldo3", "ldo%s3", &pmic4_nldo, "vdd-l3-l11"), + RPMH_VREG("ldo4", "ldo%s4", &pmic4_nldo, "vdd-l4-l5"), + RPMH_VREG("ldo5", "ldo%s5", &pmic4_nldo, "vdd-l4-l5"), + RPMH_VREG("ldo6", "ldo%s6", &pmic4_pldo, "vdd-l6"), + RPMH_VREG("ldo7", "ldo%s7", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo8", "ldo%s8", &pmic4_nldo, "vdd-l2-l8-l17"), + RPMH_VREG("ldo9", "ldo%s9", &pmic4_pldo, "vdd-l9"), + RPMH_VREG("ldo10", "ldo%s10", &pmic4_pldo, "vdd-l10-l23-l25"), + RPMH_VREG("ldo11", "ldo%s11", &pmic4_nldo, "vdd-l3-l11"), + RPMH_VREG("ldo12", "ldo%s12", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo13", "ldo%s13", &pmic4_pldo, "vdd-l13-l19-l21"), + RPMH_VREG("ldo14", "ldo%s14", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo15", "ldo%s15", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo16", "ldo%s16", &pmic4_pldo, "vdd-l16-l28"), + RPMH_VREG("ldo17", "ldo%s17", &pmic4_nldo, "vdd-l2-l8-l17"), + RPMH_VREG("ldo18", "ldo%s18", &pmic4_pldo, "vdd-l18-l22"), + RPMH_VREG("ldo19", "ldo%s19", &pmic4_pldo, "vdd-l13-l19-l21"), + RPMH_VREG("ldo20", "ldo%s20", &pmic4_pldo, "vdd-l20-l24"), + RPMH_VREG("ldo21", "ldo%s21", &pmic4_pldo, "vdd-l13-l19-l21"), + RPMH_VREG("ldo22", "ldo%s22", &pmic4_pldo, "vdd-l18-l22"), + RPMH_VREG("ldo23", "ldo%s23", &pmic4_pldo, "vdd-l10-l23-l25"), + RPMH_VREG("ldo24", "ldo%s24", &pmic4_pldo, "vdd-l20-l24"), + RPMH_VREG("ldo25", "ldo%s25", &pmic4_pldo, "vdd-l10-l23-l25"), + RPMH_VREG("ldo26", "ldo%s26", &pmic4_nldo, "vdd-l26"), + RPMH_VREG("ldo27", "ldo%s27", &pmic4_nldo, "vdd-l1-l27"), + RPMH_VREG("ldo28", "ldo%s28", &pmic4_pldo, "vdd-l16-l28"), + RPMH_VREG("lvs1", "vs%s1", &pmic4_lvs, "vin-lvs-1-2"), + RPMH_VREG("lvs2", "vs%s2", &pmic4_lvs, "vin-lvs-1-2"), + {}, +}; + +static const struct rpmh_vreg_init_data pmi8998_vreg_data[] = { + RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"), + {}, +}; + +static const struct rpmh_vreg_init_data pm8005_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic4_ftsmps426, "vdd-s4"), + {}, +}; + +static int rpmh_regulator_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct rpmh_vreg_init_data *vreg_data; + struct device_node *node; + struct rpmh_vreg *vreg; + const char *pmic_id; + int ret; + + vreg_data = of_device_get_match_data(dev); + if (!vreg_data) + return -ENODEV; + + ret = of_property_read_string(dev->of_node, "qcom,pmic-id", &pmic_id); + if (ret < 0) { + dev_err(dev, "qcom,pmic-id missing in DT node\n"); + return ret; + } + + for_each_available_child_of_node(dev->of_node, node) { + vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL); + if (!vreg) { + of_node_put(node); + return -ENOMEM; + } + + ret = rpmh_regulator_init_vreg(vreg, dev, node, pmic_id, + vreg_data); + if (ret < 0) { + of_node_put(node); + return ret; + } + } + + return 0; +} + +static const struct of_device_id rpmh_regulator_match_table[] = { + { + .compatible = "qcom,pm8998-rpmh-regulators", + .data = pm8998_vreg_data, + }, + { + .compatible = "qcom,pmi8998-rpmh-regulators", + .data = pmi8998_vreg_data, + }, + { + .compatible = "qcom,pm8005-rpmh-regulators", + .data = pm8005_vreg_data, + }, + {} +}; +MODULE_DEVICE_TABLE(of, rpmh_regulator_match_table); + +static struct platform_driver rpmh_regulator_driver = { + .driver = { + .name = "qcom-rpmh-regulator", + .of_match_table = of_match_ptr(rpmh_regulator_match_table), + }, + .probe = rpmh_regulator_probe, +}; +module_platform_driver(rpmh_regulator_driver); + +MODULE_DESCRIPTION("Qualcomm RPMh regulator driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3