From ec454d7016f2c9c897235b362089ddf9f1f8e4b8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 20 Feb 2015 16:08:43 +0000 Subject: [PATCH 01/34] regulator: arizona-ldo1: Drop OF node reference on error path We were not calling of_node_put if the regulator failed to register this patch fixes this. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- drivers/regulator/arizona-ldo1.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index 8169165904c0..a1d07d347c20 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -282,6 +282,9 @@ static int arizona_ldo1_probe(struct platform_device *pdev) arizona->external_dcvdd = true; ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config); + + of_node_put(config.of_node); + if (IS_ERR(ldo1->regulator)) { ret = PTR_ERR(ldo1->regulator); dev_err(arizona->dev, "Failed to register LDO1 supply: %d\n", @@ -289,8 +292,6 @@ static int arizona_ldo1_probe(struct platform_device *pdev) return ret; } - of_node_put(config.of_node); - platform_set_drvdata(pdev, ldo1); return 0; From a7b976ae4bff9ff4f9c9943d3232dec7e87c68b9 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 20 Feb 2015 16:08:44 +0000 Subject: [PATCH 02/34] regulator: arizona-micsupp: Drop OF node reference on error path We were not calling of_node_put if the regulator failed to register this patch fixes this. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- drivers/regulator/arizona-micsupp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index 20079006459a..4116e74effa4 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -284,6 +284,9 @@ static int arizona_micsupp_probe(struct platform_device *pdev) micsupp->regulator = devm_regulator_register(&pdev->dev, desc, &config); + + of_node_put(config.of_node); + if (IS_ERR(micsupp->regulator)) { ret = PTR_ERR(micsupp->regulator); dev_err(arizona->dev, "Failed to register mic supply: %d\n", @@ -291,8 +294,6 @@ static int arizona_micsupp_probe(struct platform_device *pdev) return ret; } - of_node_put(config.of_node); - platform_set_drvdata(pdev, micsupp); return 0; From 8f4490e09694efaf7fe60ac6a1135530aa8c05ad Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 11 Feb 2015 19:39:12 -0800 Subject: [PATCH 03/34] regulator: core: Introduce set_load op Expose the requested load directly to the regulator implementation for hardware that does not support the normal enum based set_mode(). Signed-off-by: Bjorn Andersson Signed-off-by: Mark Brown --- drivers/regulator/core.c | 39 ++++++++++++++++++++------------ include/linux/regulator/driver.h | 3 +++ 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b899947d839d..f2452148c8da 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -648,10 +648,12 @@ static int drms_uA_update(struct regulator_dev *rdev) if (err < 0) return 0; - if (!rdev->desc->ops->get_optimum_mode) + if (!rdev->desc->ops->get_optimum_mode && + !rdev->desc->ops->set_load) return 0; - if (!rdev->desc->ops->set_mode) + if (!rdev->desc->ops->set_mode && + !rdev->desc->ops->set_load) return -EINVAL; /* get output voltage */ @@ -676,22 +678,29 @@ static int drms_uA_update(struct regulator_dev *rdev) list_for_each_entry(sibling, &rdev->consumer_list, list) current_uA += sibling->uA_load; - /* now get the optimum mode for our new total regulator load */ - mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV, - output_uV, current_uA); + if (rdev->desc->ops->set_load) { + /* set the optimum mode for our new total regulator load */ + err = rdev->desc->ops->set_load(rdev, current_uA); + if (err < 0) + rdev_err(rdev, "failed to set load %d\n", current_uA); + } else { + /* now get the optimum mode for our new total regulator load */ + mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV, + output_uV, current_uA); - /* check the new mode is allowed */ - err = regulator_mode_constrain(rdev, &mode); - if (err < 0) { - rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n", - current_uA, input_uV, output_uV); - return err; + /* check the new mode is allowed */ + err = regulator_mode_constrain(rdev, &mode); + if (err < 0) { + rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n", + current_uA, input_uV, output_uV); + return err; + } + + err = rdev->desc->ops->set_mode(rdev, mode); + if (err < 0) + rdev_err(rdev, "failed to set optimum mode %x\n", mode); } - err = rdev->desc->ops->set_mode(rdev, mode); - if (err < 0) - rdev_err(rdev, "failed to set optimum mode %x\n", mode); - return err; } diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index d4ad5b5a02bb..8a0165f22f0a 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -98,6 +98,7 @@ struct regulator_linear_range { * REGULATOR_STATUS value (or negative errno) * @get_optimum_mode: Get the most efficient operating mode for the regulator * when running with the specified parameters. + * @set_load: Set the load for the regulator. * * @set_bypass: Set the regulator in bypass mode. * @get_bypass: Get the regulator bypass mode state. @@ -167,6 +168,8 @@ struct regulator_ops { /* get most efficient regulator operating mode for load */ unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV, int output_uV, int load_uA); + /* set the load on the regulator */ + int (*set_load)(struct regulator_dev *, int load_uA); /* control and report on bypass mode */ int (*set_bypass)(struct regulator_dev *dev, bool enable); From 2b85c28a5a7cb0f6bf5899125437812e67e02f70 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 11 Feb 2015 19:39:13 -0800 Subject: [PATCH 04/34] regulator: qcom-rpm: Implement set_load and enable drms Pass the requested load directly to the rpm. Signed-off-by: Bjorn Andersson Signed-off-by: Mark Brown --- drivers/regulator/qcom_rpm-regulator.c | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c index 00c5cc3d9546..15e07c233c1e 100644 --- a/drivers/regulator/qcom_rpm-regulator.c +++ b/drivers/regulator/qcom_rpm-regulator.c @@ -393,6 +393,28 @@ static int rpm_reg_is_enabled(struct regulator_dev *rdev) return vreg->is_enabled; } +static int rpm_reg_set_load(struct regulator_dev *rdev, int load_uA) +{ + struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev); + const struct rpm_reg_parts *parts = vreg->parts; + const struct request_member *req = &parts->ia; + int load_mA = load_uA / 1000; + int max_mA = req->mask >> req->shift; + int ret; + + if (req->mask == 0) + return -EINVAL; + + if (load_mA > max_mA) + load_mA = max_mA; + + mutex_lock(&vreg->lock); + ret = rpm_reg_write(vreg, req, load_mA); + mutex_unlock(&vreg->lock); + + return ret; +} + static struct regulator_ops uV_ops = { .list_voltage = regulator_list_voltage_linear_range, @@ -402,6 +424,8 @@ static struct regulator_ops uV_ops = { .enable = rpm_reg_uV_enable, .disable = rpm_reg_uV_disable, .is_enabled = rpm_reg_is_enabled, + + .set_load = rpm_reg_set_load, }; static struct regulator_ops mV_ops = { @@ -413,6 +437,8 @@ static struct regulator_ops mV_ops = { .enable = rpm_reg_mV_enable, .disable = rpm_reg_mV_disable, .is_enabled = rpm_reg_is_enabled, + + .set_load = rpm_reg_set_load, }; static struct regulator_ops switch_ops = { @@ -706,6 +732,10 @@ static int rpm_reg_probe(struct platform_device *pdev) return -EINVAL; } + /* Regulators with ia property suppports drms */ + if (vreg->parts->ia.mask) + initdata->constraints.valid_ops_mask |= REGULATOR_CHANGE_DRMS; + key = "bias-pull-down"; if (of_property_read_bool(pdev->dev.of_node, key)) { ret = rpm_reg_set(vreg, &vreg->parts->pd, 1); From 8f45acb5f9f34eabac8670e87349e0a91bfc354d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 23 Feb 2015 17:13:31 +0100 Subject: [PATCH 05/34] regulator: wm8350: Pass NULL data with REGULATION_OUT and UNDER_VOLTAGE events According to the documentation, no data is passed with the REGULATION_OUT and UNDER_VOLTAGE regulator notifier events. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/regulator/wm8350-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 7ec7c390eeda..78efead3b39f 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1157,11 +1157,11 @@ static irqreturn_t pmic_uv_handler(int irq, void *data) if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2) regulator_notifier_call_chain(rdev, REGULATOR_EVENT_REGULATION_OUT, - wm8350); + NULL); else regulator_notifier_call_chain(rdev, REGULATOR_EVENT_UNDER_VOLTAGE, - wm8350); + NULL); mutex_unlock(&rdev->mutex); return IRQ_HANDLED; From af78114ec757cea281aafa3433a3a2e211e2eb67 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 21 Feb 2015 18:53:54 -0800 Subject: [PATCH 06/34] regulator: dbx500: Remove use of seq_puts/seq_printf return value The seq_puts/seq_printf return value, because it's frequently misused, will eventually be converted to void. See: commit 1f33c41c03da ("seq_file: Rename seq_overflow() to seq_has_overflowed() and make public") Miscellanea: o Remove unnecessary dev_err("seq_ overflow\n") messages Signed-off-by: Joe Perches Signed-off-by: Mark Brown --- drivers/regulator/dbx500-prcmu.c | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c index 2d16b9f16de7..3963dfad766c 100644 --- a/drivers/regulator/dbx500-prcmu.c +++ b/drivers/regulator/dbx500-prcmu.c @@ -95,14 +95,9 @@ void ux500_regulator_resume_debug(void) static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p) { - struct device *dev = s->private; - int err; - /* print power state count */ - err = seq_printf(s, "ux500-regulator power state count: %i\n", - power_state_active_get()); - if (err < 0) - dev_err(dev, "seq_printf overflow\n"); + seq_printf(s, "ux500-regulator power state count: %i\n", + power_state_active_get()); return 0; } @@ -124,19 +119,11 @@ static const struct file_operations ux500_regulator_power_state_cnt_fops = { static int ux500_regulator_status_print(struct seq_file *s, void *p) { - struct device *dev = s->private; - int err; int i; /* print dump header */ - err = seq_puts(s, "ux500-regulator status:\n"); - if (err < 0) - dev_err(dev, "seq_puts overflow\n"); - - err = seq_printf(s, "%31s : %8s : %8s\n", "current", - "before", "after"); - if (err < 0) - dev_err(dev, "seq_printf overflow\n"); + seq_puts(s, "ux500-regulator status:\n"); + seq_printf(s, "%31s : %8s : %8s\n", "current", "before", "after"); for (i = 0; i < rdebug.num_regulators; i++) { struct dbx500_regulator_info *info; @@ -144,12 +131,11 @@ static int ux500_regulator_status_print(struct seq_file *s, void *p) info = &rdebug.regulator_array[i]; /* print status */ - err = seq_printf(s, "%20s : %8s : %8s : %8s\n", info->desc.name, - info->is_enabled ? "enabled" : "disabled", - rdebug.state_before_suspend[i] ? "enabled" : "disabled", - rdebug.state_after_suspend[i] ? "enabled" : "disabled"); - if (err < 0) - dev_err(dev, "seq_printf overflow\n"); + seq_printf(s, "%20s : %8s : %8s : %8s\n", + info->desc.name, + info->is_enabled ? "enabled" : "disabled", + rdebug.state_before_suspend[i] ? "enabled" : "disabled", + rdebug.state_after_suspend[i] ? "enabled" : "disabled"); } return 0; From 767e8aabb53cc6075d388dbce31142d4766521de Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 23 Feb 2015 17:11:07 +0100 Subject: [PATCH 07/34] regulator: da9211: Fix wrong register name in error message We tried to read the CONFIG_E register, not the CONTROL_E register. Signed-off-by: Geert Uytterhoeven Acked-by: James Ban Signed-off-by: Mark Brown --- drivers/regulator/da9211-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index 01343419555e..3eda2dd57713 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -344,7 +344,7 @@ static int da9211_regulator_init(struct da9211 *chip) ret = regmap_read(chip->regmap, DA9211_REG_CONFIG_E, &data); if (ret < 0) { - dev_err(chip->dev, "Failed to read CONTROL_E reg: %d\n", ret); + dev_err(chip->dev, "Failed to read CONFIG_E reg: %d\n", ret); return ret; } From a46a0730f5adf9292ce33172c6dc137fd694831d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 23 Feb 2015 17:12:16 +0100 Subject: [PATCH 08/34] regulator: da9211: Pass NULL data with OVER_CURRENT event According to the documentation, no data is passed with the OVER_CURRENT regulator notifier event. Signed-off-by: Geert Uytterhoeven Acked-by: James Ban Signed-off-by: Mark Brown --- drivers/regulator/da9211-regulator.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index 3eda2dd57713..df79e4b1946e 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -305,8 +305,7 @@ static irqreturn_t da9211_irq_handler(int irq, void *data) if (reg_val & DA9211_E_OV_CURR_A) { regulator_notifier_call_chain(chip->rdev[0], - REGULATOR_EVENT_OVER_CURRENT, - rdev_get_drvdata(chip->rdev[0])); + REGULATOR_EVENT_OVER_CURRENT, NULL); err = regmap_write(chip->regmap, DA9211_REG_EVENT_B, DA9211_E_OV_CURR_A); @@ -318,8 +317,7 @@ static irqreturn_t da9211_irq_handler(int irq, void *data) if (reg_val & DA9211_E_OV_CURR_B) { regulator_notifier_call_chain(chip->rdev[1], - REGULATOR_EVENT_OVER_CURRENT, - rdev_get_drvdata(chip->rdev[1])); + REGULATOR_EVENT_OVER_CURRENT, NULL); err = regmap_write(chip->regmap, DA9211_REG_EVENT_B, DA9211_E_OV_CURR_B); From 5c9e719691eab8c5de8b1b68fc3da9f7c4470c38 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 23 Feb 2015 17:10:03 +0100 Subject: [PATCH 09/34] regulator: core: Fix space before TAB Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- include/linux/regulator/consumer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index d17e1ff7ad01..aeacd624a794 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -114,7 +114,7 @@ struct regmap; #define REGULATOR_EVENT_OVER_TEMP 0x10 #define REGULATOR_EVENT_FORCE_DISABLE 0x20 #define REGULATOR_EVENT_VOLTAGE_CHANGE 0x40 -#define REGULATOR_EVENT_DISABLE 0x80 +#define REGULATOR_EVENT_DISABLE 0x80 #define REGULATOR_EVENT_PRE_VOLTAGE_CHANGE 0x100 #define REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE 0x200 #define REGULATOR_EVENT_PRE_DISABLE 0x400 From 046db763aaaeb987ea01ea8c7e6d618e0ad1e6b8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 5 Mar 2015 15:39:20 +0000 Subject: [PATCH 10/34] regulator: core: Add devres versions of notifier registration Add devm_regulator_register_notifier, this adds the resource against the device for the consumer supply we are registering the notifier for. There seem to be few use-cases where this wouldn't be the users intention and this ensures the notifiers will always be removed at the correct time. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- drivers/regulator/devres.c | 85 ++++++++++++++++++++++++++++++ include/linux/regulator/consumer.h | 16 ++++++ 2 files changed, 101 insertions(+) diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c index 8f785bc9e510..6ec1d400adae 100644 --- a/drivers/regulator/devres.c +++ b/drivers/regulator/devres.c @@ -413,3 +413,88 @@ void devm_regulator_bulk_unregister_supply_alias(struct device *dev, devm_regulator_unregister_supply_alias(dev, id[i]); } EXPORT_SYMBOL_GPL(devm_regulator_bulk_unregister_supply_alias); + +struct regulator_notifier_match { + struct regulator *regulator; + struct notifier_block *nb; +}; + +static int devm_regulator_match_notifier(struct device *dev, void *res, + void *data) +{ + struct regulator_notifier_match *match = res; + struct regulator_notifier_match *target = data; + + return match->regulator == target->regulator && match->nb == target->nb; +} + +static void devm_regulator_destroy_notifier(struct device *dev, void *res) +{ + struct regulator_notifier_match *match = res; + + regulator_unregister_notifier(match->regulator, match->nb); +} + +/** + * devm_regulator_register_notifier - Resource managed + * regulator_register_notifier + * + * @regulator: regulator source + * @nb: notifier block + * + * The notifier will be registers under the consumer device and be + * automatically be unregistered when the source device is unbound. + */ +int devm_regulator_register_notifier(struct regulator *regulator, + struct notifier_block *nb) +{ + struct regulator_notifier_match *match; + int ret; + + match = devres_alloc(devm_regulator_destroy_notifier, + sizeof(struct regulator_notifier_match), + GFP_KERNEL); + if (!match) + return -ENOMEM; + + match->regulator = regulator; + match->nb = nb; + + ret = regulator_register_notifier(regulator, nb); + if (ret < 0) { + devres_free(match); + return ret; + } + + devres_add(regulator->dev, match); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_regulator_register_notifier); + +/** + * devm_regulator_unregister_notifier - Resource managed + * regulator_unregister_notifier() + * + * @regulator: regulator source + * @nb: notifier block + * + * Unregister a notifier registered with devm_regulator_register_notifier(). + * Normally this function will not need to be called and the resource + * management code will ensure that the resource is freed. + */ +void devm_regulator_unregister_notifier(struct regulator *regulator, + struct notifier_block *nb) +{ + struct regulator_notifier_match match; + int rc; + + match.regulator = regulator; + match.nb = nb; + + rc = devres_release(regulator->dev, devm_regulator_destroy_notifier, + devm_regulator_match_notifier, &match); + if (rc != 0) + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_regulator_unregister_notifier); diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index d17e1ff7ad01..bd631ee5f1da 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -252,8 +252,12 @@ int regulator_list_hardware_vsel(struct regulator *regulator, /* regulator notifier block */ int regulator_register_notifier(struct regulator *regulator, struct notifier_block *nb); +int devm_regulator_register_notifier(struct regulator *regulator, + struct notifier_block *nb); int regulator_unregister_notifier(struct regulator *regulator, struct notifier_block *nb); +void devm_regulator_unregister_notifier(struct regulator *regulator, + struct notifier_block *nb); /* driver data - core doesn't touch */ void *regulator_get_drvdata(struct regulator *regulator); @@ -515,12 +519,24 @@ static inline int regulator_register_notifier(struct regulator *regulator, return 0; } +static inline int devm_regulator_register_notifier(struct regulator *regulator, + struct notifier_block *nb) +{ + return 0; +} + static inline int regulator_unregister_notifier(struct regulator *regulator, struct notifier_block *nb) { return 0; } +static inline int devm_regulator_unregister_notifier(struct regulator *regulator, + struct notifier_block *nb) +{ + return 0; +} + static inline void *regulator_get_drvdata(struct regulator *regulator) { return NULL; From 1b42085af787eb2e465863ba82633bbd905a7897 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 26 Feb 2015 01:54:51 -0300 Subject: [PATCH 11/34] regulator: wm8350: Remove unused variable Commit 8f45acb5f9f34eab ("regulator: wm8350: Pass NULL data with REGULATION_OUT and UNDER_VOLTAGE events") introduced the following build warning: drivers/regulator/wm8350-regulator.c: In function 'pmic_uv_handler': drivers/regulator/wm8350-regulator.c:1154:17: warning: unused variable 'wm8350' [-Wunused-variable] Remove 'wm8350' as it is unused now. Signed-off-by: Fabio Estevam Acked-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/regulator/wm8350-regulator.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 78efead3b39f..95f6b040186e 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1151,7 +1151,6 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { static irqreturn_t pmic_uv_handler(int irq, void *data) { struct regulator_dev *rdev = (struct regulator_dev *)data; - struct wm8350 *wm8350 = rdev_get_drvdata(rdev); mutex_lock(&rdev->mutex); if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2) From df3a950e4e7386027fc174566aa5c24781297be8 Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Kakakhel Date: Fri, 27 Feb 2015 17:04:04 +0000 Subject: [PATCH 12/34] regulator: act8865: Add act8600 support This patch adds act8600 support to the act8865 driver. VBUS and USB charger supported by this chip can be added later Tested on MIPS Creator CI20 Signed-off-by: Zubair Lutfullah Kakakhel Signed-off-by: Mark Brown --- .../bindings/regulator/act8865-regulator.txt | 5 +- drivers/regulator/act8865-regulator.c | 120 +++++++++++++++++- include/linux/regulator/act8865.h | 14 ++ 3 files changed, 137 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt index dad6358074ac..e170df2357df 100644 --- a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt @@ -2,7 +2,7 @@ ACT88xx regulators ------------------- Required properties: -- compatible: "active-semi,act8846" or "active-semi,act8865" +- compatible: "active-semi,act8846" or "active-semi,act8865" or "active-semi,act8600" - reg: I2C slave address Optional properties: @@ -16,6 +16,9 @@ The valid names for regulators are: REG1, REG2, REG3, REG4, REG5, REG6, REG7, REG8, REG9, REG10, REG11, REG12 - for act8865: DCDC_REG1, DCDC_REG2, DCDC_REG3, LDO_REG1, LDO_REG2, LDO_REG3, LDO_REG4. + - for act8600: + DCDC_REG1, DCDC_REG2, DCDC_REG3, SUDCDC_REG4, LDO_REG5, LDO_REG6, LDO_REG7, + LDO_REG8, LDO_REG9, LDO_REG10, Example: -------- diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 9eec453b745d..3781f6e289d8 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -28,6 +28,35 @@ #include #include +/* + * ACT8600 Global Register Map. + */ +#define ACT8600_SYS_MODE 0x00 +#define ACT8600_SYS_CTRL 0x01 +#define ACT8600_DCDC1_VSET 0x10 +#define ACT8600_DCDC1_CTRL 0x12 +#define ACT8600_DCDC2_VSET 0x20 +#define ACT8600_DCDC2_CTRL 0x22 +#define ACT8600_DCDC3_VSET 0x30 +#define ACT8600_DCDC3_CTRL 0x32 +#define ACT8600_SUDCDC4_VSET 0x40 +#define ACT8600_SUDCDC4_CTRL 0x41 +#define ACT8600_LDO5_VSET 0x50 +#define ACT8600_LDO5_CTRL 0x51 +#define ACT8600_LDO6_VSET 0x60 +#define ACT8600_LDO6_CTRL 0x61 +#define ACT8600_LDO7_VSET 0x70 +#define ACT8600_LDO7_CTRL 0x71 +#define ACT8600_LDO8_VSET 0x80 +#define ACT8600_LDO8_CTRL 0x81 +#define ACT8600_LDO910_CTRL 0x91 +#define ACT8600_APCH0 0xA1 +#define ACT8600_APCH1 0xA8 +#define ACT8600_APCH2 0xA9 +#define ACT8600_APCH_STAT 0xAA +#define ACT8600_OTG0 0xB0 +#define ACT8600_OTG1 0xB2 + /* * ACT8846 Global Register Map. */ @@ -94,10 +123,15 @@ #define ACT8865_ENA 0x80 /* ON - [7] */ #define ACT8865_VSEL_MASK 0x3F /* VSET - [5:0] */ + +#define ACT8600_LDO10_ENA 0x40 /* ON - [6] */ +#define ACT8600_SUDCDC_VSEL_MASK 0xFF /* SUDCDC VSET - [7:0] */ + /* * ACT8865 voltage number */ #define ACT8865_VOLTAGE_NUM 64 +#define ACT8600_SUDCDC_VOLTAGE_NUM 255 struct act8865 { struct regmap *regmap; @@ -116,6 +150,13 @@ static const struct regulator_linear_range act8865_voltage_ranges[] = { REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000), }; +static const struct regulator_linear_range act8600_sudcdc_voltage_ranges[] = { + REGULATOR_LINEAR_RANGE(3000000, 0, 63, 0), + REGULATOR_LINEAR_RANGE(3000000, 64, 159, 100000), + REGULATOR_LINEAR_RANGE(12600000, 160, 191, 200000), + REGULATOR_LINEAR_RANGE(19000000, 191, 255, 400000), +}; + static struct regulator_ops act8865_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, @@ -126,6 +167,12 @@ static struct regulator_ops act8865_ops = { .is_enabled = regulator_is_enabled_regmap, }; +static struct regulator_ops act8865_ldo_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + #define ACT88xx_REG(_name, _family, _id, _vsel_reg) \ [_family##_ID_##_id] = { \ .name = _name, \ @@ -142,6 +189,52 @@ static struct regulator_ops act8865_ops = { .owner = THIS_MODULE, \ } +static const struct regulator_desc act8600_regulators[] = { + ACT88xx_REG("DCDC1", ACT8600, DCDC1, VSET), + ACT88xx_REG("DCDC2", ACT8600, DCDC2, VSET), + ACT88xx_REG("DCDC3", ACT8600, DCDC3, VSET), + { + .name = "SUDCDC_REG4", + .id = ACT8600_ID_SUDCDC4, + .ops = &act8865_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = ACT8600_SUDCDC_VOLTAGE_NUM, + .linear_ranges = act8600_sudcdc_voltage_ranges, + .n_linear_ranges = ARRAY_SIZE(act8600_sudcdc_voltage_ranges), + .vsel_reg = ACT8600_SUDCDC4_VSET, + .vsel_mask = ACT8600_SUDCDC_VSEL_MASK, + .enable_reg = ACT8600_SUDCDC4_CTRL, + .enable_mask = ACT8865_ENA, + .owner = THIS_MODULE, + }, + ACT88xx_REG("LDO5", ACT8600, LDO5, VSET), + ACT88xx_REG("LDO6", ACT8600, LDO6, VSET), + ACT88xx_REG("LDO7", ACT8600, LDO7, VSET), + ACT88xx_REG("LDO8", ACT8600, LDO8, VSET), + { + .name = "LDO_REG9", + .id = ACT8600_ID_LDO9, + .ops = &act8865_ldo_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 1, + .fixed_uV = 1800000, + .enable_reg = ACT8600_LDO910_CTRL, + .enable_mask = ACT8865_ENA, + .owner = THIS_MODULE, + }, + { + .name = "LDO_REG10", + .id = ACT8600_ID_LDO10, + .ops = &act8865_ldo_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = 1, + .fixed_uV = 1200000, + .enable_reg = ACT8600_LDO910_CTRL, + .enable_mask = ACT8600_LDO10_ENA, + .owner = THIS_MODULE, + }, +}; + static const struct regulator_desc act8846_regulators[] = { ACT88xx_REG("REG1", ACT8846, REG1, VSET), ACT88xx_REG("REG2", ACT8846, REG2, VSET0), @@ -169,6 +262,7 @@ static const struct regulator_desc act8865_regulators[] = { #ifdef CONFIG_OF static const struct of_device_id act8865_dt_ids[] = { + { .compatible = "active-semi,act8600", .data = (void *)ACT8600 }, { .compatible = "active-semi,act8846", .data = (void *)ACT8846 }, { .compatible = "active-semi,act8865", .data = (void *)ACT8865 }, { } @@ -200,6 +294,19 @@ static struct of_regulator_match act8865_matches[] = { [ACT8865_ID_LDO4] = { .name = "LDO_REG4"}, }; +static struct of_regulator_match act8600_matches[] = { + [ACT8600_ID_DCDC1] = { .name = "DCDC_REG1"}, + [ACT8600_ID_DCDC2] = { .name = "DCDC_REG2"}, + [ACT8600_ID_DCDC3] = { .name = "DCDC_REG3"}, + [ACT8600_ID_SUDCDC4] = { .name = "SUDCDC_REG4"}, + [ACT8600_ID_LDO5] = { .name = "LDO_REG5"}, + [ACT8600_ID_LDO6] = { .name = "LDO_REG6"}, + [ACT8600_ID_LDO7] = { .name = "LDO_REG7"}, + [ACT8600_ID_LDO8] = { .name = "LDO_REG8"}, + [ACT8600_ID_LDO9] = { .name = "LDO_REG9"}, + [ACT8600_ID_LDO10] = { .name = "LDO_REG10"}, +}; + static int act8865_pdata_from_dt(struct device *dev, struct device_node **of_node, struct act8865_platform_data *pdata, @@ -217,6 +324,10 @@ static int act8865_pdata_from_dt(struct device *dev, } switch (type) { + case ACT8600: + matches = act8600_matches; + num_matches = ARRAY_SIZE(act8600_matches); + break; case ACT8846: matches = act8846_matches; num_matches = ARRAY_SIZE(act8846_matches); @@ -317,6 +428,12 @@ static int act8865_pmic_probe(struct i2c_client *client, } switch (type) { + case ACT8600: + regulators = act8600_regulators; + num_regulators = ARRAY_SIZE(act8600_regulators); + off_reg = -1; + off_mask = -1; + break; case ACT8846: regulators = act8846_regulators; num_regulators = ARRAY_SIZE(act8846_regulators); @@ -366,7 +483,7 @@ static int act8865_pmic_probe(struct i2c_client *client, } if (of_device_is_system_power_controller(dev->of_node)) { - if (!pm_power_off) { + if (!pm_power_off && (off_reg > 0)) { act8865_i2c_client = client; act8865->off_reg = off_reg; act8865->off_mask = off_mask; @@ -402,6 +519,7 @@ static int act8865_pmic_probe(struct i2c_client *client, } static const struct i2c_device_id act8865_ids[] = { + { .name = "act8600", .driver_data = ACT8600 }, { .name = "act8846", .driver_data = ACT8846 }, { .name = "act8865", .driver_data = ACT8865 }, { }, diff --git a/include/linux/regulator/act8865.h b/include/linux/regulator/act8865.h index b6c4909b33af..15fa8f2d35c9 100644 --- a/include/linux/regulator/act8865.h +++ b/include/linux/regulator/act8865.h @@ -18,6 +18,19 @@ #include +enum { + ACT8600_ID_DCDC1, + ACT8600_ID_DCDC2, + ACT8600_ID_DCDC3, + ACT8600_ID_SUDCDC4, + ACT8600_ID_LDO5, + ACT8600_ID_LDO6, + ACT8600_ID_LDO7, + ACT8600_ID_LDO8, + ACT8600_ID_LDO9, + ACT8600_ID_LDO10, +}; + enum { ACT8865_ID_DCDC1, ACT8865_ID_DCDC2, @@ -46,6 +59,7 @@ enum { }; enum { + ACT8600, ACT8865, ACT8846, }; From c8b263cc03eaaa324c9222474191e6d849cb6dda Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Sat, 7 Mar 2015 16:33:53 +0100 Subject: [PATCH 13/34] regulator: act8865: add input supply handling The act88600/act8846/act8865 regulators have a number of input supplies supplying the individual regulators. This may even be recursively like on most Rockchip boards using the act8846 where REG4 is most of the time connected to the inl1-supply. Therefore add the ability to specify the input supplies for the individual inputs. The input-names are taken from the datasheets of act8600, act8846 and act8865. On the act8600 some regulators do not have separate input supplies. Signed-off-by: Heiko Stuebner Signed-off-by: Mark Brown --- .../bindings/regulator/act8865-regulator.txt | 22 ++++++++ drivers/regulator/act8865-regulator.c | 55 ++++++++++--------- 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt index e170df2357df..e91485d11241 100644 --- a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt @@ -9,6 +9,28 @@ Optional properties: - system-power-controller: Telling whether or not this pmic is controlling the system power. See Documentation/devicetree/bindings/power/power-controller.txt . +Optional input supply properties: +- for act8600: + - vp1-supply: The input supply for DCDC_REG1 + - vp2-supply: The input supply for DCDC_REG2 + - vp3-supply: The input supply for DCDC_REG3 + - inl-supply: The input supply for LDO_REG5, LDO_REG6, LDO_REG7 and LDO_REG8 + SUDCDC_REG4, LDO_REG9 and LDO_REG10 do not have separate supplies. +- for act8846: + - vp1-supply: The input supply for REG1 + - vp2-supply: The input supply for REG2 + - vp3-supply: The input supply for REG3 + - vp4-supply: The input supply for REG4 + - inl1-supply: The input supply for REG5, REG6 and REG7 + - inl2-supply: The input supply for REG8 and LDO_REG9 + - inl3-supply: The input supply for REG10, REG11 and REG12 +- for act8865: + - vp1-supply: The input supply for DCDC_REG1 + - vp2-supply: The input supply for DCDC_REG2 + - vp3-supply: The input supply for DCDC_REG3 + - inl45-supply: The input supply for LDO_REG1 and LDO_REG2 + - inl67-supply: The input supply for LDO_REG3 and LDO_REG4 + Any standard regulator properties can be used to configure the single regulator. The valid names for regulators are: diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 3781f6e289d8..2ff73d72ca34 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -173,9 +173,10 @@ static struct regulator_ops act8865_ldo_ops = { .is_enabled = regulator_is_enabled_regmap, }; -#define ACT88xx_REG(_name, _family, _id, _vsel_reg) \ +#define ACT88xx_REG(_name, _family, _id, _vsel_reg, _supply) \ [_family##_ID_##_id] = { \ .name = _name, \ + .supply_name = _supply, \ .id = _family##_ID_##_id, \ .type = REGULATOR_VOLTAGE, \ .ops = &act8865_ops, \ @@ -190,9 +191,9 @@ static struct regulator_ops act8865_ldo_ops = { } static const struct regulator_desc act8600_regulators[] = { - ACT88xx_REG("DCDC1", ACT8600, DCDC1, VSET), - ACT88xx_REG("DCDC2", ACT8600, DCDC2, VSET), - ACT88xx_REG("DCDC3", ACT8600, DCDC3, VSET), + ACT88xx_REG("DCDC1", ACT8600, DCDC1, VSET, "vp1"), + ACT88xx_REG("DCDC2", ACT8600, DCDC2, VSET, "vp2"), + ACT88xx_REG("DCDC3", ACT8600, DCDC3, VSET, "vp3"), { .name = "SUDCDC_REG4", .id = ACT8600_ID_SUDCDC4, @@ -207,10 +208,10 @@ static const struct regulator_desc act8600_regulators[] = { .enable_mask = ACT8865_ENA, .owner = THIS_MODULE, }, - ACT88xx_REG("LDO5", ACT8600, LDO5, VSET), - ACT88xx_REG("LDO6", ACT8600, LDO6, VSET), - ACT88xx_REG("LDO7", ACT8600, LDO7, VSET), - ACT88xx_REG("LDO8", ACT8600, LDO8, VSET), + ACT88xx_REG("LDO5", ACT8600, LDO5, VSET, "inl"), + ACT88xx_REG("LDO6", ACT8600, LDO6, VSET, "inl"), + ACT88xx_REG("LDO7", ACT8600, LDO7, VSET, "inl"), + ACT88xx_REG("LDO8", ACT8600, LDO8, VSET, "inl"), { .name = "LDO_REG9", .id = ACT8600_ID_LDO9, @@ -236,28 +237,28 @@ static const struct regulator_desc act8600_regulators[] = { }; static const struct regulator_desc act8846_regulators[] = { - ACT88xx_REG("REG1", ACT8846, REG1, VSET), - ACT88xx_REG("REG2", ACT8846, REG2, VSET0), - ACT88xx_REG("REG3", ACT8846, REG3, VSET0), - ACT88xx_REG("REG4", ACT8846, REG4, VSET0), - ACT88xx_REG("REG5", ACT8846, REG5, VSET), - ACT88xx_REG("REG6", ACT8846, REG6, VSET), - ACT88xx_REG("REG7", ACT8846, REG7, VSET), - ACT88xx_REG("REG8", ACT8846, REG8, VSET), - ACT88xx_REG("REG9", ACT8846, REG9, VSET), - ACT88xx_REG("REG10", ACT8846, REG10, VSET), - ACT88xx_REG("REG11", ACT8846, REG11, VSET), - ACT88xx_REG("REG12", ACT8846, REG12, VSET), + ACT88xx_REG("REG1", ACT8846, REG1, VSET, "vp1"), + ACT88xx_REG("REG2", ACT8846, REG2, VSET0, "vp2"), + ACT88xx_REG("REG3", ACT8846, REG3, VSET0, "vp3"), + ACT88xx_REG("REG4", ACT8846, REG4, VSET0, "vp4"), + ACT88xx_REG("REG5", ACT8846, REG5, VSET, "inl1"), + ACT88xx_REG("REG6", ACT8846, REG6, VSET, "inl1"), + ACT88xx_REG("REG7", ACT8846, REG7, VSET, "inl1"), + ACT88xx_REG("REG8", ACT8846, REG8, VSET, "inl2"), + ACT88xx_REG("REG9", ACT8846, REG9, VSET, "inl2"), + ACT88xx_REG("REG10", ACT8846, REG10, VSET, "inl3"), + ACT88xx_REG("REG11", ACT8846, REG11, VSET, "inl3"), + ACT88xx_REG("REG12", ACT8846, REG12, VSET, "inl3"), }; static const struct regulator_desc act8865_regulators[] = { - ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET1), - ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET1), - ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET1), - ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET), - ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET), - ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET), - ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET), + ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET1, "vp1"), + ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET1, "vp2"), + ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET1, "vp3"), + ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET, "inl45"), + ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET, "inl45"), + ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET, "inl67"), + ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"), }; #ifdef CONFIG_OF From e39ce48f5362df9f87400b4909a6fb0f51b109ac Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 11 Feb 2015 19:35:27 -0800 Subject: [PATCH 14/34] regulator: Rename regulator_set_optimum_mode Rename the regulator_set_optimum_mode() function regulator_set_load() to better represent what's going on. Signed-off-by: Bjorn Andersson Signed-off-by: Mark Brown --- Documentation/power/regulator/consumer.txt | 2 +- drivers/regulator/core.c | 8 ++++---- include/linux/regulator/consumer.h | 12 +++++++++--- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Documentation/power/regulator/consumer.txt b/Documentation/power/regulator/consumer.txt index 8afb236ca765..e51564c1a140 100644 --- a/Documentation/power/regulator/consumer.txt +++ b/Documentation/power/regulator/consumer.txt @@ -137,7 +137,7 @@ Indirect operating mode control. Consumer drivers can request a change in their supply regulator operating mode by calling :- -int regulator_set_optimum_mode(struct regulator *regulator, int load_uA); +int regulator_set_load(struct regulator *regulator, int load_uA); This will cause the core to recalculate the total load on the regulator (based on all its consumers) and change operating mode (if necessary and permitted) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b899947d839d..03088f9c3d4f 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2994,7 +2994,7 @@ unsigned int regulator_get_mode(struct regulator *regulator) EXPORT_SYMBOL_GPL(regulator_get_mode); /** - * regulator_set_optimum_mode - set regulator optimum operating mode + * regulator_set_load - set regulator load * @regulator: regulator source * @uA_load: load current * @@ -3017,9 +3017,9 @@ EXPORT_SYMBOL_GPL(regulator_get_mode); * DRMS will sum the total requested load on the regulator and change * to the most efficient operating mode if platform constraints allow. * - * Returns the new regulator mode or error. + * On error a negative errno is returned. */ -int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) +int regulator_set_load(struct regulator *regulator, int uA_load) { struct regulator_dev *rdev = regulator->rdev; int ret; @@ -3031,7 +3031,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) return ret; } -EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); +EXPORT_SYMBOL_GPL(regulator_set_load); /** * regulator_allow_bypass - allow the regulator to go into bypass mode diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index d17e1ff7ad01..6d4e9d2289f0 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -238,7 +238,7 @@ int regulator_get_current_limit(struct regulator *regulator); int regulator_set_mode(struct regulator *regulator, unsigned int mode); unsigned int regulator_get_mode(struct regulator *regulator); -int regulator_set_optimum_mode(struct regulator *regulator, int load_uA); +int regulator_set_load(struct regulator *regulator, int load_uA); int regulator_allow_bypass(struct regulator *regulator, bool allow); @@ -479,8 +479,7 @@ static inline unsigned int regulator_get_mode(struct regulator *regulator) return REGULATOR_MODE_NORMAL; } -static inline int regulator_set_optimum_mode(struct regulator *regulator, - int load_uA) +static inline int regulator_set_load(struct regulator *regulator, int load_uA) { return REGULATOR_MODE_NORMAL; } @@ -555,4 +554,11 @@ static inline int regulator_is_supported_voltage_tol(struct regulator *regulator target_uV + tol_uV); } +/* TEMP: Wrapper to keep bisectability */ +static inline int regulator_set_optimum_mode(struct regulator *regulator, + int load_uA) +{ + return regulator_set_load(regulator, load_uA); +} + #endif From 7b16a07c32935ea7f59f4408b7c9200d9cd0cced Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 11 Feb 2015 19:35:28 -0800 Subject: [PATCH 15/34] ufs: Rename of regulator_set_optimum_mode The function regulator_set_optimum_mode() is changing name to regulator_set_load(), so update the code accordingly. Also cleaned up ufshcd_config_vreg_load() while touching the code. Signed-off-by: Bjorn Andersson Signed-off-by: Mark Brown --- drivers/scsi/ufs/ufshcd.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 5d60a868830d..2aa85e398f76 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4225,22 +4225,15 @@ static struct scsi_host_template ufshcd_driver_template = { static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg, int ua) { - int ret = 0; - struct regulator *reg = vreg->reg; - const char *name = vreg->name; + int ret; - BUG_ON(!vreg); + if (!vreg) + return 0; - ret = regulator_set_optimum_mode(reg, ua); - if (ret >= 0) { - /* - * regulator_set_optimum_mode() returns new regulator - * mode upon success. - */ - ret = 0; - } else { - dev_err(dev, "%s: %s set optimum mode(ua=%d) failed, err=%d\n", - __func__, name, ua, ret); + ret = regulator_set_load(vreg->reg, ua); + if (ret < 0) { + dev_err(dev, "%s: %s set load (ua=%d) failed, err=%d\n", + __func__, vreg->name, ua, ret); } return ret; @@ -4249,18 +4242,12 @@ static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg, static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba, struct ufs_vreg *vreg) { - if (!vreg) - return 0; - return ufshcd_config_vreg_load(hba->dev, vreg, UFS_VREG_LPM_LOAD_UA); } static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba, struct ufs_vreg *vreg) { - if (!vreg) - return 0; - return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA); } From 1d61a6948121d73e897df0f96a0fd8aa3b3b1ac9 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 11 Feb 2015 19:35:29 -0800 Subject: [PATCH 16/34] usb: phy: ab8500-usb: Rename regulator_set_optimum_mode The function regulator_set_optimum_mode() is changing name to regulator_set_load(), so update the code accordingly. Signed-off-by: Bjorn Andersson Acked-by: Felipe Balbi Signed-off-by: Mark Brown --- drivers/usb/phy/phy-ab8500-usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 0b1bd2369293..f5b3b928941b 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -277,7 +277,7 @@ static void ab8500_usb_regulator_enable(struct ab8500_usb *ab) dev_err(ab->dev, "Failed to set the Vintcore to 1.3V, ret=%d\n", ret); - ret = regulator_set_optimum_mode(ab->v_ulpi, 28000); + ret = regulator_set_load(ab->v_ulpi, 28000); if (ret < 0) dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n", ret); @@ -317,7 +317,7 @@ static void ab8500_usb_regulator_disable(struct ab8500_usb *ab) ab->saved_v_ulpi, ret); } - ret = regulator_set_optimum_mode(ab->v_ulpi, 0); + ret = regulator_set_load(ab->v_ulpi, 0); if (ret < 0) dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n", ret); From fa53e351e81259644717b381e095eaf9173c9ca8 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 11 Feb 2015 19:35:30 -0800 Subject: [PATCH 17/34] usb: phy: phy-msm-usb: Rename regulator_set_optimum_mode The function regulator_set_optimum_mode() is changing name to regulator_set_load(), so update the code accordingly. Signed-off-by: Bjorn Andersson Acked-by: Felipe Balbi Signed-off-by: Mark Brown --- drivers/usb/phy/phy-msm-usb.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 000fd892455f..6ed67ea4ef7e 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -142,27 +142,22 @@ static int msm_hsusb_ldo_set_mode(struct msm_otg *motg, int on) int ret = 0; if (on) { - ret = regulator_set_optimum_mode(motg->v1p8, - USB_PHY_1P8_HPM_LOAD); + ret = regulator_set_load(motg->v1p8, USB_PHY_1P8_HPM_LOAD); if (ret < 0) { pr_err("Could not set HPM for v1p8\n"); return ret; } - ret = regulator_set_optimum_mode(motg->v3p3, - USB_PHY_3P3_HPM_LOAD); + ret = regulator_set_load(motg->v3p3, USB_PHY_3P3_HPM_LOAD); if (ret < 0) { pr_err("Could not set HPM for v3p3\n"); - regulator_set_optimum_mode(motg->v1p8, - USB_PHY_1P8_LPM_LOAD); + regulator_set_load(motg->v1p8, USB_PHY_1P8_LPM_LOAD); return ret; } } else { - ret = regulator_set_optimum_mode(motg->v1p8, - USB_PHY_1P8_LPM_LOAD); + ret = regulator_set_load(motg->v1p8, USB_PHY_1P8_LPM_LOAD); if (ret < 0) pr_err("Could not set LPM for v1p8\n"); - ret = regulator_set_optimum_mode(motg->v3p3, - USB_PHY_3P3_LPM_LOAD); + ret = regulator_set_load(motg->v3p3, USB_PHY_3P3_LPM_LOAD); if (ret < 0) pr_err("Could not set LPM for v3p3\n"); } From ae6e808f15742fcbc0097ac2fb3055d553266965 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 11 Feb 2015 19:35:31 -0800 Subject: [PATCH 18/34] regulator: Drop temporary regulator_set_optimum_mode wrapper Signed-off-by: Bjorn Andersson Signed-off-by: Mark Brown --- include/linux/regulator/consumer.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index 6d4e9d2289f0..d8944f508235 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -554,11 +554,4 @@ static inline int regulator_is_supported_voltage_tol(struct regulator *regulator target_uV + tol_uV); } -/* TEMP: Wrapper to keep bisectability */ -static inline int regulator_set_optimum_mode(struct regulator *regulator, - int load_uA) -{ - return regulator_set_load(regulator, load_uA); -} - #endif From 7e476c7dd8d39b03a4dd8447be907d3517579c51 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 10 Mar 2015 13:44:41 +1100 Subject: [PATCH 19/34] regulator: fixes for regulator_set_optimum_mode name change Signed-off-by: Stephen Rothwell Signed-off-by: Mark Brown --- drivers/gpu/drm/msm/edp/edp_ctrl.c | 6 +++--- drivers/phy/phy-qcom-ufs.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c index 3e246210c46f..0ec5abdba5c4 100644 --- a/drivers/gpu/drm/msm/edp/edp_ctrl.c +++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c @@ -332,7 +332,7 @@ static int edp_regulator_enable(struct edp_ctrl *ctrl) goto vdda_set_fail; } - ret = regulator_set_optimum_mode(ctrl->vdda_vreg, VDDA_UA_ON_LOAD); + ret = regulator_set_load(ctrl->vdda_vreg, VDDA_UA_ON_LOAD); if (ret < 0) { pr_err("%s: vdda_vreg set regulator mode failed.\n", __func__); goto vdda_set_fail; @@ -356,7 +356,7 @@ static int edp_regulator_enable(struct edp_ctrl *ctrl) lvl_enable_fail: regulator_disable(ctrl->vdda_vreg); vdda_enable_fail: - regulator_set_optimum_mode(ctrl->vdda_vreg, VDDA_UA_OFF_LOAD); + regulator_set_load(ctrl->vdda_vreg, VDDA_UA_OFF_LOAD); vdda_set_fail: return ret; } @@ -365,7 +365,7 @@ static void edp_regulator_disable(struct edp_ctrl *ctrl) { regulator_disable(ctrl->lvl_vreg); regulator_disable(ctrl->vdda_vreg); - regulator_set_optimum_mode(ctrl->vdda_vreg, VDDA_UA_OFF_LOAD); + regulator_set_load(ctrl->vdda_vreg, VDDA_UA_OFF_LOAD); } static int edp_gpio_config(struct edp_ctrl *ctrl) diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c index 44ee983d57fe..86665e9dc399 100644 --- a/drivers/phy/phy-qcom-ufs.c +++ b/drivers/phy/phy-qcom-ufs.c @@ -346,10 +346,10 @@ int ufs_qcom_phy_cfg_vreg(struct phy *phy, goto out; } uA_load = on ? vreg->max_uA : 0; - ret = regulator_set_optimum_mode(reg, uA_load); + ret = regulator_set_load(reg, uA_load); if (ret >= 0) { /* - * regulator_set_optimum_mode() returns new regulator + * regulator_set_load() returns new regulator * mode upon success. */ ret = 0; From cdbf6f0e8e58ec4601546d0ab67da905d4a2e6f5 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 16 Mar 2015 20:17:08 +0100 Subject: [PATCH 20/34] regulator: constify of_device_id array of_device_id is always used as const. (See driver.of_match_table and open firmware functions) Signed-off-by: Fabian Frederick Signed-off-by: Mark Brown --- drivers/regulator/palmas-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 9205f433573c..eecce1e66320 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -1505,7 +1505,7 @@ static void palmas_dt_to_pdata(struct device *dev, pdata->ldo6_vibrator = of_property_read_bool(node, "ti,ldo6-vibrator"); } -static struct of_device_id of_palmas_match_tbl[] = { +static const struct of_device_id of_palmas_match_tbl[] = { { .compatible = "ti,palmas-pmic", .data = &palmas_ddata, From e999c7289cf2e542e8be8bc72ba5dc0f8f06c88e Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 17 Mar 2015 15:56:05 +0530 Subject: [PATCH 21/34] regulator: palmas: Add has_regen3 check for TPS659038 Palmas driver is used to cater to even TPS659038 but TPS659038 does not have REGEN3 resource. Adding another field in the driver data to check on that. Signed-off-by: Keerthy Signed-off-by: Mark Brown --- drivers/regulator/palmas-regulator.c | 9 ++++++++- include/linux/mfd/palmas.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 9518a76ad29e..8217613807d3 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -916,6 +916,9 @@ static int palmas_ldo_registration(struct palmas_pmic *pmic, (id == PALMAS_REG_LDO6)) desc->enable_time = 2000; } else { + if (!ddata->has_regen3 && id == PALMAS_REG_REGEN3) + continue; + desc->n_voltages = 1; if (reg_init && reg_init->roof_floor) desc->ops = &palmas_ops_ext_control_extreg; @@ -1398,6 +1401,7 @@ static struct palmas_pmic_driver_data palmas_ddata = { .ldo_begin = PALMAS_REG_LDO1, .ldo_end = PALMAS_REG_LDOUSB, .max_reg = PALMAS_NUM_REGS, + .has_regen3 = true, .palmas_regs_info = palmas_generic_regs_info, .palmas_matches = palmas_matches, .sleep_req_info = palma_sleep_req_info, @@ -1411,6 +1415,7 @@ static struct palmas_pmic_driver_data tps65917_ddata = { .ldo_begin = TPS65917_REG_LDO1, .ldo_end = TPS65917_REG_LDO5, .max_reg = TPS65917_NUM_REGS, + .has_regen3 = true, .palmas_regs_info = tps65917_regs_info, .palmas_matches = tps65917_matches, .sleep_req_info = tps65917_sleep_req_info, @@ -1572,9 +1577,11 @@ static int palmas_regulators_probe(struct platform_device *pdev) if (!pmic) return -ENOMEM; - if (of_device_is_compatible(node, "ti,tps659038-pmic")) + if (of_device_is_compatible(node, "ti,tps659038-pmic")) { palmas_generic_regs_info[PALMAS_REG_REGEN2].ctrl_addr = TPS659038_REGEN2_CTRL; + palmas_ddata.has_regen3 = false; + } pmic->dev = &pdev->dev; pmic->palmas = palmas; diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index ee7b1ce7a6f8..bb270bd03eed 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -117,6 +117,7 @@ struct palmas_pmic_driver_data { int ldo_begin; int ldo_end; int max_reg; + bool has_regen3; struct palmas_regs_info *palmas_regs_info; struct of_regulator_match *palmas_matches; struct palmas_sleep_requestor_info *sleep_req_info; From 14aef2919d06bd132f2e6f74f5ccb3caa4c92d54 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 20 Mar 2015 07:53:06 +0800 Subject: [PATCH 22/34] regulator: stw481x: Remove unused fields from struct stw481x The mutex lock is not used at all, remove it. The *vmmc_regulator is not necessary, use a local variable in stw481x_vmmc_regulator_probe() instead. Signed-off-by: Axel Lin Reviewed-by: Linus Walleij Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/stw481x-vmmc.c | 8 ++++---- include/linux/mfd/stw481x.h | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/regulator/stw481x-vmmc.c b/drivers/regulator/stw481x-vmmc.c index 89025f560259..7d2ae3e9e942 100644 --- a/drivers/regulator/stw481x-vmmc.c +++ b/drivers/regulator/stw481x-vmmc.c @@ -56,6 +56,7 @@ static int stw481x_vmmc_regulator_probe(struct platform_device *pdev) { struct stw481x *stw481x = dev_get_platdata(&pdev->dev); struct regulator_config config = { }; + struct regulator_dev *rdev; int ret; /* First disable the external VMMC if it's active */ @@ -75,12 +76,11 @@ static int stw481x_vmmc_regulator_probe(struct platform_device *pdev) pdev->dev.of_node, &vmmc_regulator); - stw481x->vmmc_regulator = devm_regulator_register(&pdev->dev, - &vmmc_regulator, &config); - if (IS_ERR(stw481x->vmmc_regulator)) { + rdev = devm_regulator_register(&pdev->dev, &vmmc_regulator, &config); + if (IS_ERR(rdev)) { dev_err(&pdev->dev, "error initializing STw481x VMMC regulator\n"); - return PTR_ERR(stw481x->vmmc_regulator); + return PTR_ERR(rdev); } dev_info(&pdev->dev, "initialized STw481x VMMC regulator\n"); diff --git a/include/linux/mfd/stw481x.h b/include/linux/mfd/stw481x.h index eda121556e5d..833074b766bd 100644 --- a/include/linux/mfd/stw481x.h +++ b/include/linux/mfd/stw481x.h @@ -41,15 +41,11 @@ /** * struct stw481x - state holder for the Stw481x drivers - * @mutex: mutex to serialize I2C accesses * @i2c_client: corresponding I2C client - * @regulator: regulator device for regulator children * @map: regmap handle to access device registers */ struct stw481x { - struct mutex lock; struct i2c_client *client; - struct regulator_dev *vmmc_regulator; struct regmap *map; }; From a9eaa8130707d4013fb109b80323489c0d0111ac Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 17 Oct 2014 08:17:03 -0700 Subject: [PATCH 23/34] regulator: Ensure unique regulator debugfs directory names If multiple regulator devices of the same type exist in a system, the regulator driver assigns generic names for the regulators it provides, and debugfs is enabled, the regulator subsystem attempts to create multiple entries with the same name in the regulator debugfs directory. This fails for all but the first regulator, resulting in multiple "Failed to create debugfs directory" log entries. To avoid the problem, prepend the debugfs directory name for a regulator with its parent device name if available, but only if no explicit regulator name was provided. Cc: Alan Tull Signed-off-by: Guenter Roeck Signed-off-by: Mark Brown --- drivers/regulator/core.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b899947d839d..cc242aa368ef 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3502,7 +3502,18 @@ static struct class regulator_class = { static void rdev_init_debugfs(struct regulator_dev *rdev) { - rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root); + struct device *parent = rdev->dev.parent; + const char *rname = rdev_get_name(rdev); + char name[NAME_MAX]; + + /* Avoid duplicate debugfs directory names */ + if (parent && rname == rdev->desc->name) { + snprintf(name, sizeof(name), "%s-%s", dev_name(parent), + rname); + rname = name; + } + + rdev->debugfs = debugfs_create_dir(rname, debugfs_root); if (!rdev->debugfs) { rdev_warn(rdev, "Failed to create debugfs directory\n"); return; From 222d0f04340c686b136ec3a610cc50ba46baaea1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 26 Mar 2015 11:35:58 +0100 Subject: [PATCH 24/34] regulator: max77693: Let core parse DT and drop board files support Simplify the driver by removing board file support and letting regulator core to parse DT. The max77693 regulator driver is used only on Exynos based boards which are DT-only. Board files for Exynos are not supported. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/max77693.c | 93 ++++-------------------------------- 1 file changed, 9 insertions(+), 84 deletions(-) diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c index 07b313e51b21..9665a488e2f1 100644 --- a/drivers/regulator/max77693.c +++ b/drivers/regulator/max77693.c @@ -128,6 +128,8 @@ static struct regulator_ops max77693_charger_ops = { #define regulator_desc_esafeout(_num) { \ .name = "ESAFEOUT"#_num, \ .id = MAX77693_ESAFEOUT##_num, \ + .of_match = of_match_ptr("ESAFEOUT"#_num), \ + .regulators_node = of_match_ptr("regulators"), \ .n_voltages = 4, \ .ops = &max77693_safeout_ops, \ .type = REGULATOR_VOLTAGE, \ @@ -145,6 +147,8 @@ static const struct regulator_desc regulators[] = { { .name = "CHARGER", .id = MAX77693_CHARGER, + .of_match = of_match_ptr("CHARGER"), + .regulators_node = of_match_ptr("regulators"), .ops = &max77693_charger_ops, .type = REGULATOR_CURRENT, .owner = THIS_MODULE, @@ -154,102 +158,23 @@ static const struct regulator_desc regulators[] = { }, }; -#ifdef CONFIG_OF -static int max77693_pmic_dt_parse_rdata(struct device *dev, - struct max77693_regulator_data **rdata) -{ - struct device_node *np; - struct of_regulator_match *rmatch; - struct max77693_regulator_data *tmp; - int i, matched = 0; - - np = of_get_child_by_name(dev->parent->of_node, "regulators"); - if (!np) - return -EINVAL; - - rmatch = devm_kzalloc(dev, - sizeof(*rmatch) * ARRAY_SIZE(regulators), GFP_KERNEL); - if (!rmatch) { - of_node_put(np); - return -ENOMEM; - } - - for (i = 0; i < ARRAY_SIZE(regulators); i++) - rmatch[i].name = regulators[i].name; - - matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(regulators)); - of_node_put(np); - if (matched <= 0) - return matched; - *rdata = devm_kzalloc(dev, sizeof(**rdata) * matched, GFP_KERNEL); - if (!(*rdata)) - return -ENOMEM; - - tmp = *rdata; - - for (i = 0; i < matched; i++) { - tmp->initdata = rmatch[i].init_data; - tmp->of_node = rmatch[i].of_node; - tmp->id = regulators[i].id; - tmp++; - } - - return matched; -} -#else -static int max77693_pmic_dt_parse_rdata(struct device *dev, - struct max77693_regulator_data **rdata) -{ - return 0; -} -#endif /* CONFIG_OF */ - -static int max77693_pmic_init_rdata(struct device *dev, - struct max77693_regulator_data **rdata) -{ - struct max77693_platform_data *pdata; - int num_regulators = 0; - - pdata = dev_get_platdata(dev->parent); - if (pdata) { - *rdata = pdata->regulators; - num_regulators = pdata->num_regulators; - } - - if (!(*rdata) && dev->parent->of_node) - num_regulators = max77693_pmic_dt_parse_rdata(dev, rdata); - - return num_regulators; -} - static int max77693_pmic_probe(struct platform_device *pdev) { struct max77693_dev *iodev = dev_get_drvdata(pdev->dev.parent); - struct max77693_regulator_data *rdata = NULL; - int num_rdata, i; + int i; struct regulator_config config = { }; - num_rdata = max77693_pmic_init_rdata(&pdev->dev, &rdata); - if (!rdata || num_rdata <= 0) { - dev_err(&pdev->dev, "No init data supplied.\n"); - return -ENODEV; - } - - config.dev = &pdev->dev; + config.dev = iodev->dev; config.regmap = iodev->regmap; - for (i = 0; i < num_rdata; i++) { - int id = rdata[i].id; + for (i = 0; i < ARRAY_SIZE(regulators); i++) { struct regulator_dev *rdev; - config.init_data = rdata[i].initdata; - config.of_node = rdata[i].of_node; - rdev = devm_regulator_register(&pdev->dev, - ®ulators[id], &config); + ®ulators[i], &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, - "Failed to initialize regulator-%d\n", id); + "Failed to initialize regulator-%d\n", i); return PTR_ERR(rdev); } } From eb2d90c058280b41c8493cb17271e053b5ebba39 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 26 Mar 2015 11:35:59 +0100 Subject: [PATCH 25/34] mfd: max77693: Remove unused structures The max77693 regulator driver no longer supports board files. Remove the left-overs. Additionally fix name of device in comment. Signed-off-by: Krzysztof Kozlowski Acked-by: Lee Jones Signed-off-by: Mark Brown --- include/linux/mfd/max77693.h | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/include/linux/mfd/max77693.h b/include/linux/mfd/max77693.h index f0b6585cd874..09a4dedaeea8 100644 --- a/include/linux/mfd/max77693.h +++ b/include/linux/mfd/max77693.h @@ -30,7 +30,7 @@ #ifndef __LINUX_MFD_MAX77693_H #define __LINUX_MFD_MAX77693_H -/* MAX77686 regulator IDs */ +/* MAX77693 regulator IDs */ enum max77693_regulators { MAX77693_ESAFEOUT1 = 0, MAX77693_ESAFEOUT2, @@ -38,12 +38,6 @@ enum max77693_regulators { MAX77693_REG_MAX, }; -struct max77693_regulator_data { - int id; - struct regulator_init_data *initdata; - struct device_node *of_node; -}; - struct max77693_reg_data { u8 addr; u8 data; @@ -103,10 +97,6 @@ struct max77693_led_platform_data { /* MAX77693 */ struct max77693_platform_data { - /* regulator data */ - struct max77693_regulator_data *regulators; - int num_regulators; - /* muic data */ struct max77693_muic_platform_data *muic_data; struct max77693_led_platform_data *led_data; From 6261b06de565baafa590e58a531a1a5522cea0b6 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 24 Mar 2015 18:56:05 -0700 Subject: [PATCH 26/34] regulator: Defer lookup of supply to regulator_get Instead of resolving regulator supplies during registration move this to the time of a consumer retrieving a handle. The benefit is that it's possible for one driver to register regulators with internal dependencies out of order. Signed-off-by: Bjorn Andersson Signed-off-by: Mark Brown --- drivers/regulator/core.c | 92 +++++++++++++++++++------------- include/linux/regulator/driver.h | 1 + 2 files changed, 57 insertions(+), 36 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b899947d839d..a291a6b9cd44 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1316,6 +1316,54 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, return NULL; } +static int regulator_resolve_supply(struct regulator_dev *rdev) +{ + struct regulator_dev *r; + struct device *dev = rdev->dev.parent; + int ret; + + /* No supply to resovle? */ + if (!rdev->supply_name) + return 0; + + /* Supply already resolved? */ + if (rdev->supply) + return 0; + + r = regulator_dev_lookup(dev, rdev->supply_name, &ret); + if (ret == -ENODEV) { + /* + * No supply was specified for this regulator and + * there will never be one. + */ + return 0; + } + + if (!r) { + dev_err(dev, "Failed to resolve %s-supply for %s\n", + rdev->supply_name, rdev->desc->name); + return -EPROBE_DEFER; + } + + /* Recursively resolve the supply of the supply */ + ret = regulator_resolve_supply(r); + if (ret < 0) + return ret; + + ret = set_supply(rdev, r); + if (ret < 0) + return ret; + + /* Cascade always-on state to supply */ + if (_regulator_is_enabled(rdev)) { + ret = regulator_enable(rdev->supply); + if (ret < 0) + return ret; + } + + return 0; +} + /* Internal regulator request function */ static struct regulator *_regulator_get(struct device *dev, const char *id, bool exclusive, bool allow_dummy) @@ -1385,6 +1433,12 @@ found: goto out; } + ret = regulator_resolve_supply(rdev); + if (ret < 0) { + regulator = ERR_PTR(ret); + goto out; + } + if (!try_module_get(rdev->owner)) goto out; @@ -3536,7 +3590,6 @@ regulator_register(const struct regulator_desc *regulator_desc, struct regulator_dev *rdev; struct device *dev; int ret, i; - const char *supply = NULL; if (regulator_desc == NULL || cfg == NULL) return ERR_PTR(-EINVAL); @@ -3650,41 +3703,10 @@ regulator_register(const struct regulator_desc *regulator_desc, goto scrub; if (init_data && init_data->supply_regulator) - supply = init_data->supply_regulator; + rdev->supply_name = init_data->supply_regulator; else if (regulator_desc->supply_name) - supply = regulator_desc->supply_name; + rdev->supply_name = regulator_desc->supply_name; - if (supply) { - struct regulator_dev *r; - - r = regulator_dev_lookup(dev, supply, &ret); - - if (ret == -ENODEV) { - /* - * No supply was specified for this regulator and - * there will never be one. - */ - ret = 0; - goto add_dev; - } else if (!r) { - dev_err(dev, "Failed to find supply %s\n", supply); - ret = -EPROBE_DEFER; - goto scrub; - } - - ret = set_supply(rdev, r); - if (ret < 0) - goto scrub; - - /* Enable supply if rail is enabled */ - if (_regulator_is_enabled(rdev)) { - ret = regulator_enable(rdev->supply); - if (ret < 0) - goto scrub; - } - } - -add_dev: /* add consumers devices */ if (init_data) { for (i = 0; i < init_data->num_consumer_supplies; i++) { @@ -3711,8 +3733,6 @@ unset_supplies: unset_regulator_supplies(rdev); scrub: - if (rdev->supply) - _regulator_put(rdev->supply); regulator_ena_gpio_free(rdev); kfree(rdev->constraints); wash: diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index d4ad5b5a02bb..6d9fcd0c33d6 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -367,6 +367,7 @@ struct regulator_dev { struct device dev; struct regulation_constraints *constraints; struct regulator *supply; /* for tree */ + const char *supply_name; struct regmap *regmap; struct delayed_work disable_work; From dfb85ba1140ab649f6f0bf3e502ac37c0f69dbcb Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 7 Apr 2015 23:06:46 +0100 Subject: [PATCH 27/34] regulator: max8660: fix assignment of pdata to data that becomes dead pdata is assigned to &pdata_of, however, pdata_of becomes dead (when it goes out of scope) so pdata effectively becomes a dead pointer to the out of scope object. This is detected by static analysis: [drivers/regulator/max8660.c:411]: (error) Dead pointer usage. Pointer 'pdata' is dead if it has been assigned '&pdata_of' at line 404. Move declaration of pdata_of so it is always in scope. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- drivers/regulator/max8660.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index 7eee2ca18541..f187c8f13e22 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -382,7 +382,7 @@ static int max8660_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { struct device *dev = &client->dev; - struct max8660_platform_data *pdata = dev_get_platdata(dev); + struct max8660_platform_data pdata_of, *pdata = dev_get_platdata(dev); struct regulator_config config = { }; struct max8660 *max8660; int boot_on, i, id, ret = -EINVAL; @@ -391,7 +391,6 @@ static int max8660_probe(struct i2c_client *client, if (dev->of_node && !pdata) { const struct of_device_id *id; - struct max8660_platform_data pdata_of; id = of_match_device(of_match_ptr(max8660_dt_ids), dev); if (!id) From 4d1e4d629a484b725d5fc88d7e0f967435ab6edd Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 6 Apr 2015 16:33:57 -0700 Subject: [PATCH 28/34] regulator: qcom: Don't enable DRMS in driver The driver itself should not flag regulators as being DRMS compatible, this should come from board or dt files. Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Signed-off-by: Mark Brown --- drivers/regulator/qcom_rpm-regulator.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c index 15e07c233c1e..ddca8cb363ad 100644 --- a/drivers/regulator/qcom_rpm-regulator.c +++ b/drivers/regulator/qcom_rpm-regulator.c @@ -732,10 +732,6 @@ static int rpm_reg_probe(struct platform_device *pdev) return -EINVAL; } - /* Regulators with ia property suppports drms */ - if (vreg->parts->ia.mask) - initdata->constraints.valid_ops_mask |= REGULATOR_CHANGE_DRMS; - key = "bias-pull-down"; if (of_property_read_bool(pdev->dev.of_node, key)) { ret = rpm_reg_set(vreg, &vreg->parts->pd, 1); From 469a951446460da843028014a90100428ff6e0c1 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 6 Apr 2015 16:33:58 -0700 Subject: [PATCH 29/34] regulator: qcom: Refactor of-parsing code Refactor out all custom property parsing code from the probe function into a function suitable for regulator_desc->of_parse_cb usage. Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Signed-off-by: Mark Brown --- drivers/regulator/qcom_rpm-regulator.c | 187 ++++++++++++++----------- 1 file changed, 104 insertions(+), 83 deletions(-) diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c index ddca8cb363ad..bd8360ca7750 100644 --- a/drivers/regulator/qcom_rpm-regulator.c +++ b/drivers/regulator/qcom_rpm-regulator.c @@ -645,7 +645,9 @@ static int rpm_reg_set(struct qcom_rpm_reg *vreg, return 0; } -static int rpm_reg_of_parse_freq(struct device *dev, struct qcom_rpm_reg *vreg) +static int rpm_reg_of_parse_freq(struct device *dev, + struct device_node *node, + struct qcom_rpm_reg *vreg) { static const int freq_table[] = { 19200000, 9600000, 6400000, 4800000, 3840000, 3200000, 2740000, @@ -659,7 +661,7 @@ static int rpm_reg_of_parse_freq(struct device *dev, struct qcom_rpm_reg *vreg) int i; key = "qcom,switch-mode-frequency"; - ret = of_property_read_u32(dev->of_node, key, &freq); + ret = of_property_read_u32(node, key, &freq); if (ret) { dev_err(dev, "regulator requires %s property\n", key); return -EINVAL; @@ -676,6 +678,101 @@ static int rpm_reg_of_parse_freq(struct device *dev, struct qcom_rpm_reg *vreg) return -EINVAL; } +static int rpm_reg_of_parse(struct device_node *node, + const struct regulator_desc *desc, + struct regulator_config *config) +{ + struct qcom_rpm_reg *vreg = config->driver_data; + struct device *dev = config->dev; + const char *key; + u32 force_mode; + bool pwm; + u32 val; + int ret; + + key = "bias-pull-down"; + if (of_property_read_bool(node, key)) { + ret = rpm_reg_set(vreg, &vreg->parts->pd, 1); + if (ret) { + dev_err(dev, "%s is invalid", key); + return ret; + } + } + + if (vreg->parts->freq.mask) { + ret = rpm_reg_of_parse_freq(dev, node, vreg); + if (ret < 0) + return ret; + } + + if (vreg->parts->pm.mask) { + key = "qcom,power-mode-hysteretic"; + pwm = !of_property_read_bool(node, key); + + ret = rpm_reg_set(vreg, &vreg->parts->pm, pwm); + if (ret) { + dev_err(dev, "failed to set power mode\n"); + return ret; + } + } + + if (vreg->parts->fm.mask) { + force_mode = -1; + + key = "qcom,force-mode"; + ret = of_property_read_u32(node, key, &val); + if (ret == -EINVAL) { + val = QCOM_RPM_FORCE_MODE_NONE; + } else if (ret < 0) { + dev_err(dev, "failed to read %s\n", key); + return ret; + } + + /* + * If force-mode is encoded as 2 bits then the + * possible register values are: + * NONE, LPM, HPM + * otherwise: + * NONE, LPM, AUTO, HPM, BYPASS + */ + switch (val) { + case QCOM_RPM_FORCE_MODE_NONE: + force_mode = 0; + break; + case QCOM_RPM_FORCE_MODE_LPM: + force_mode = 1; + break; + case QCOM_RPM_FORCE_MODE_HPM: + if (FORCE_MODE_IS_2_BITS(vreg)) + force_mode = 2; + else + force_mode = 3; + break; + case QCOM_RPM_FORCE_MODE_AUTO: + if (vreg->supports_force_mode_auto) + force_mode = 2; + break; + case QCOM_RPM_FORCE_MODE_BYPASS: + if (vreg->supports_force_mode_bypass) + force_mode = 4; + break; + } + + if (force_mode == -1) { + dev_err(dev, "invalid force mode\n"); + return -EINVAL; + } + + ret = rpm_reg_set(vreg, &vreg->parts->fm, force_mode); + if (ret) { + dev_err(dev, "failed to set force mode\n"); + return ret; + } + } + + return 0; +} + static int rpm_reg_probe(struct platform_device *pdev) { struct regulator_init_data *initdata; @@ -685,8 +782,6 @@ static int rpm_reg_probe(struct platform_device *pdev) struct regulator_dev *rdev; struct qcom_rpm_reg *vreg; const char *key; - u32 force_mode; - bool pwm; u32 val; int ret; @@ -732,90 +827,16 @@ static int rpm_reg_probe(struct platform_device *pdev) return -EINVAL; } - key = "bias-pull-down"; - if (of_property_read_bool(pdev->dev.of_node, key)) { - ret = rpm_reg_set(vreg, &vreg->parts->pd, 1); - if (ret) { - dev_err(&pdev->dev, "%s is invalid", key); - return ret; - } - } - - if (vreg->parts->freq.mask) { - ret = rpm_reg_of_parse_freq(&pdev->dev, vreg); - if (ret < 0) - return ret; - } - - if (vreg->parts->pm.mask) { - key = "qcom,power-mode-hysteretic"; - pwm = !of_property_read_bool(pdev->dev.of_node, key); - - ret = rpm_reg_set(vreg, &vreg->parts->pm, pwm); - if (ret) { - dev_err(&pdev->dev, "failed to set power mode\n"); - return ret; - } - } - - if (vreg->parts->fm.mask) { - force_mode = -1; - - key = "qcom,force-mode"; - ret = of_property_read_u32(pdev->dev.of_node, key, &val); - if (ret == -EINVAL) { - val = QCOM_RPM_FORCE_MODE_NONE; - } else if (ret < 0) { - dev_err(&pdev->dev, "failed to read %s\n", key); - return ret; - } - - /* - * If force-mode is encoded as 2 bits then the - * possible register values are: - * NONE, LPM, HPM - * otherwise: - * NONE, LPM, AUTO, HPM, BYPASS - */ - switch (val) { - case QCOM_RPM_FORCE_MODE_NONE: - force_mode = 0; - break; - case QCOM_RPM_FORCE_MODE_LPM: - force_mode = 1; - break; - case QCOM_RPM_FORCE_MODE_HPM: - if (FORCE_MODE_IS_2_BITS(vreg)) - force_mode = 2; - else - force_mode = 3; - break; - case QCOM_RPM_FORCE_MODE_AUTO: - if (vreg->supports_force_mode_auto) - force_mode = 2; - break; - case QCOM_RPM_FORCE_MODE_BYPASS: - if (vreg->supports_force_mode_bypass) - force_mode = 4; - break; - } - - if (force_mode == -1) { - dev_err(&pdev->dev, "invalid force mode\n"); - return -EINVAL; - } - - ret = rpm_reg_set(vreg, &vreg->parts->fm, force_mode); - if (ret) { - dev_err(&pdev->dev, "failed to set force mode\n"); - return ret; - } - } config.dev = &pdev->dev; config.init_data = initdata; config.driver_data = vreg; config.of_node = pdev->dev.of_node; + + ret = rpm_reg_of_parse(pdev->dev.of_node, &vreg->desc, &config); + if (ret) + return ret; + rdev = devm_regulator_register(&pdev->dev, &vreg->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "can't register regulator\n"); From 087a1b5cdd555970feb8a340dc008b6914f05128 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 6 Apr 2015 16:33:59 -0700 Subject: [PATCH 30/34] regulator: qcom: Rework to single platform device Modeling the individual RPM resources as platform devices consumes at least 12-15kb of RAM, just to hold the platform_device structs. Rework this to instead have one device per pmic exposed by the RPM. With this representation we can more accurately define the input pins on the pmic and have the supply description match the data sheet. Suggested-by: Stephen Boyd Signed-off-by: Bjorn Andersson Reviewed-by: Stephen Boyd Signed-off-by: Mark Brown --- drivers/regulator/qcom_rpm-regulator.c | 240 ++++++++++++++++--------- 1 file changed, 159 insertions(+), 81 deletions(-) diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c index bd8360ca7750..40cf6ff0d1ff 100644 --- a/drivers/regulator/qcom_rpm-regulator.c +++ b/drivers/regulator/qcom_rpm-regulator.c @@ -607,31 +607,6 @@ static const struct qcom_rpm_reg smb208_smps = { .supports_force_mode_bypass = false, }; -static const struct of_device_id rpm_of_match[] = { - { .compatible = "qcom,rpm-pm8058-pldo", .data = &pm8058_pldo }, - { .compatible = "qcom,rpm-pm8058-nldo", .data = &pm8058_nldo }, - { .compatible = "qcom,rpm-pm8058-smps", .data = &pm8058_smps }, - { .compatible = "qcom,rpm-pm8058-ncp", .data = &pm8058_ncp }, - { .compatible = "qcom,rpm-pm8058-switch", .data = &pm8058_switch }, - - { .compatible = "qcom,rpm-pm8901-pldo", .data = &pm8901_pldo }, - { .compatible = "qcom,rpm-pm8901-nldo", .data = &pm8901_nldo }, - { .compatible = "qcom,rpm-pm8901-ftsmps", .data = &pm8901_ftsmps }, - { .compatible = "qcom,rpm-pm8901-switch", .data = &pm8901_switch }, - - { .compatible = "qcom,rpm-pm8921-pldo", .data = &pm8921_pldo }, - { .compatible = "qcom,rpm-pm8921-nldo", .data = &pm8921_nldo }, - { .compatible = "qcom,rpm-pm8921-nldo1200", .data = &pm8921_nldo1200 }, - { .compatible = "qcom,rpm-pm8921-smps", .data = &pm8921_smps }, - { .compatible = "qcom,rpm-pm8921-ftsmps", .data = &pm8921_ftsmps }, - { .compatible = "qcom,rpm-pm8921-ncp", .data = &pm8921_ncp }, - { .compatible = "qcom,rpm-pm8921-switch", .data = &pm8921_switch }, - - { .compatible = "qcom,rpm-smb208", .data = &smb208_smps }, - { } -}; -MODULE_DEVICE_TABLE(of, rpm_of_match); - static int rpm_reg_set(struct qcom_rpm_reg *vreg, const struct request_member *req, const int value) @@ -773,74 +748,177 @@ static int rpm_reg_of_parse(struct device_node *node, return 0; } +struct rpm_regulator_data { + const char *name; + int resource; + const struct qcom_rpm_reg *template; + const char *supply; +}; + +static const struct rpm_regulator_data rpm_pm8058_regulators[] = { + { "l0", QCOM_RPM_PM8058_LDO0, &pm8058_nldo, "vdd_l0_l1_lvs" }, + { "l1", QCOM_RPM_PM8058_LDO1, &pm8058_nldo, "vdd_l0_l1_lvs" }, + { "l2", QCOM_RPM_PM8058_LDO2, &pm8058_pldo, "vdd_l2_l11_l12" }, + { "l3", QCOM_RPM_PM8058_LDO3, &pm8058_pldo, "vdd_l3_l4_l5" }, + { "l4", QCOM_RPM_PM8058_LDO4, &pm8058_pldo, "vdd_l3_l4_l5" }, + { "l5", QCOM_RPM_PM8058_LDO5, &pm8058_pldo, "vdd_l3_l4_l5" }, + { "l6", QCOM_RPM_PM8058_LDO6, &pm8058_pldo, "vdd_l6_l7" }, + { "l7", QCOM_RPM_PM8058_LDO7, &pm8058_pldo, "vdd_l6_l7" }, + { "l8", QCOM_RPM_PM8058_LDO8, &pm8058_pldo, "vdd_l8" }, + { "l9", QCOM_RPM_PM8058_LDO9, &pm8058_pldo, "vdd_l9" }, + { "l10", QCOM_RPM_PM8058_LDO10, &pm8058_pldo, "vdd_l10" }, + { "l11", QCOM_RPM_PM8058_LDO11, &pm8058_pldo, "vdd_l2_l11_l12" }, + { "l12", QCOM_RPM_PM8058_LDO12, &pm8058_pldo, "vdd_l2_l11_l12" }, + { "l13", QCOM_RPM_PM8058_LDO13, &pm8058_pldo, "vdd_l13_l16" }, + { "l14", QCOM_RPM_PM8058_LDO14, &pm8058_pldo, "vdd_l14_l15" }, + { "l15", QCOM_RPM_PM8058_LDO15, &pm8058_pldo, "vdd_l14_l15" }, + { "l16", QCOM_RPM_PM8058_LDO16, &pm8058_pldo, "vdd_l13_l16" }, + { "l17", QCOM_RPM_PM8058_LDO17, &pm8058_pldo, "vdd_l17_l18" }, + { "l18", QCOM_RPM_PM8058_LDO18, &pm8058_pldo, "vdd_l17_l18" }, + { "l19", QCOM_RPM_PM8058_LDO19, &pm8058_pldo, "vdd_l19_l20" }, + { "l20", QCOM_RPM_PM8058_LDO20, &pm8058_pldo, "vdd_l19_l20" }, + { "l21", QCOM_RPM_PM8058_LDO21, &pm8058_nldo, "vdd_l21" }, + { "l22", QCOM_RPM_PM8058_LDO22, &pm8058_nldo, "vdd_l22" }, + { "l23", QCOM_RPM_PM8058_LDO23, &pm8058_nldo, "vdd_l23_l24_l25" }, + { "l24", QCOM_RPM_PM8058_LDO24, &pm8058_nldo, "vdd_l23_l24_l25" }, + { "l25", QCOM_RPM_PM8058_LDO25, &pm8058_nldo, "vdd_l23_l24_l25" }, + + { "s0", QCOM_RPM_PM8058_SMPS0, &pm8058_smps, "vdd_s0" }, + { "s1", QCOM_RPM_PM8058_SMPS1, &pm8058_smps, "vdd_s1" }, + { "s2", QCOM_RPM_PM8058_SMPS2, &pm8058_smps, "vdd_s2" }, + { "s3", QCOM_RPM_PM8058_SMPS3, &pm8058_smps, "vdd_s3" }, + { "s4", QCOM_RPM_PM8058_SMPS4, &pm8058_smps, "vdd_s4" }, + + { "lvs0", QCOM_RPM_PM8058_LVS0, &pm8058_switch, "vdd_l0_l1_lvs" }, + { "lvs1", QCOM_RPM_PM8058_LVS1, &pm8058_switch, "vdd_l0_l1_lvs" }, + + { "ncp", QCOM_RPM_PM8058_NCP, &pm8058_ncp, "vdd_ncp" }, + { } +}; + +static const struct rpm_regulator_data rpm_pm8901_regulators[] = { + { "l0", QCOM_RPM_PM8901_LDO0, &pm8901_nldo, "vdd_l0" }, + { "l1", QCOM_RPM_PM8901_LDO1, &pm8901_pldo, "vdd_l1" }, + { "l2", QCOM_RPM_PM8901_LDO2, &pm8901_pldo, "vdd_l2" }, + { "l3", QCOM_RPM_PM8901_LDO3, &pm8901_pldo, "vdd_l3" }, + { "l4", QCOM_RPM_PM8901_LDO4, &pm8901_pldo, "vdd_l4" }, + { "l5", QCOM_RPM_PM8901_LDO5, &pm8901_pldo, "vdd_l5" }, + { "l6", QCOM_RPM_PM8901_LDO6, &pm8901_pldo, "vdd_l6" }, + + { "s0", QCOM_RPM_PM8901_SMPS0, &pm8901_ftsmps, "vdd_s0" }, + { "s1", QCOM_RPM_PM8901_SMPS1, &pm8901_ftsmps, "vdd_s1" }, + { "s2", QCOM_RPM_PM8901_SMPS2, &pm8901_ftsmps, "vdd_s2" }, + { "s3", QCOM_RPM_PM8901_SMPS3, &pm8901_ftsmps, "vdd_s3" }, + { "s4", QCOM_RPM_PM8901_SMPS4, &pm8901_ftsmps, "vdd_s4" }, + + { "lvs0", QCOM_RPM_PM8901_LVS0, &pm8901_switch, "lvs0_in" }, + { "lvs1", QCOM_RPM_PM8901_LVS1, &pm8901_switch, "lvs1_in" }, + { "lvs2", QCOM_RPM_PM8901_LVS2, &pm8901_switch, "lvs2_in" }, + { "lvs3", QCOM_RPM_PM8901_LVS3, &pm8901_switch, "lvs3_in" }, + + { "mvs", QCOM_RPM_PM8901_MVS, &pm8901_switch, "mvs_in" }, + { } +}; + +static const struct rpm_regulator_data rpm_pm8921_regulators[] = { + { "s1", QCOM_RPM_PM8921_SMPS1, &pm8921_smps, "vdd_s1" }, + { "s2", QCOM_RPM_PM8921_SMPS2, &pm8921_smps, "vdd_s2" }, + { "s3", QCOM_RPM_PM8921_SMPS3, &pm8921_smps }, + { "s4", QCOM_RPM_PM8921_SMPS4, &pm8921_smps, "vdd_s4" }, + { "s7", QCOM_RPM_PM8921_SMPS7, &pm8921_smps, "vdd_s7" }, + { "s8", QCOM_RPM_PM8921_SMPS8, &pm8921_smps, "vdd_s8" }, + + { "l1", QCOM_RPM_PM8921_LDO1, &pm8921_nldo, "vdd_l1_l2_l12_l18" }, + { "l2", QCOM_RPM_PM8921_LDO2, &pm8921_nldo, "vdd_l1_l2_l12_l18" }, + { "l3", QCOM_RPM_PM8921_LDO3, &pm8921_pldo, "vdd_l3_l15_l17" }, + { "l4", QCOM_RPM_PM8921_LDO4, &pm8921_pldo, "vdd_l4_l14" }, + { "l5", QCOM_RPM_PM8921_LDO5, &pm8921_pldo, "vdd_l5_l8_l16" }, + { "l6", QCOM_RPM_PM8921_LDO6, &pm8921_pldo, "vdd_l6_l7" }, + { "l7", QCOM_RPM_PM8921_LDO7, &pm8921_pldo, "vdd_l6_l7" }, + { "l8", QCOM_RPM_PM8921_LDO8, &pm8921_pldo, "vdd_l5_l8_l16" }, + { "l9", QCOM_RPM_PM8921_LDO9, &pm8921_pldo, "vdd_l9_l11" }, + { "l10", QCOM_RPM_PM8921_LDO10, &pm8921_pldo, "vdd_l10_l22" }, + { "l11", QCOM_RPM_PM8921_LDO11, &pm8921_pldo, "vdd_l9_l11" }, + { "l12", QCOM_RPM_PM8921_LDO12, &pm8921_nldo, "vdd_l1_l2_l12_l18" }, + { "l14", QCOM_RPM_PM8921_LDO14, &pm8921_pldo, "vdd_l4_l14" }, + { "l15", QCOM_RPM_PM8921_LDO15, &pm8921_pldo, "vdd_l3_l15_l17" }, + { "l16", QCOM_RPM_PM8921_LDO16, &pm8921_pldo, "vdd_l5_l8_l16" }, + { "l17", QCOM_RPM_PM8921_LDO17, &pm8921_pldo, "vdd_l3_l15_l17" }, + { "l18", QCOM_RPM_PM8921_LDO18, &pm8921_nldo, "vdd_l1_l2_l12_l18" }, + { "l21", QCOM_RPM_PM8921_LDO21, &pm8921_pldo, "vdd_l21_l23_l29" }, + { "l22", QCOM_RPM_PM8921_LDO22, &pm8921_pldo, "vdd_l10_l22" }, + { "l23", QCOM_RPM_PM8921_LDO23, &pm8921_pldo, "vdd_l21_l23_l29" }, + { "l24", QCOM_RPM_PM8921_LDO24, &pm8921_nldo1200, "vdd_l24" }, + { "l25", QCOM_RPM_PM8921_LDO25, &pm8921_nldo1200, "vdd_l25" }, + { "l26", QCOM_RPM_PM8921_LDO26, &pm8921_nldo1200, "vdd_l26" }, + { "l27", QCOM_RPM_PM8921_LDO27, &pm8921_nldo1200, "vdd_l27" }, + { "l28", QCOM_RPM_PM8921_LDO28, &pm8921_nldo1200, "vdd_l28" }, + { "l29", QCOM_RPM_PM8921_LDO29, &pm8921_pldo, "vdd_l21_l23_l29" }, + + { "lvs1", QCOM_RPM_PM8921_LVS1, &pm8921_switch, "vin_lvs1_3_6" }, + { "lvs2", QCOM_RPM_PM8921_LVS2, &pm8921_switch, "vin_lvs2" }, + { "lvs3", QCOM_RPM_PM8921_LVS3, &pm8921_switch, "vin_lvs1_3_6" }, + { "lvs4", QCOM_RPM_PM8921_LVS4, &pm8921_switch, "vin_lvs4_5_7" }, + { "lvs5", QCOM_RPM_PM8921_LVS5, &pm8921_switch, "vin_lvs4_5_7" }, + { "lvs6", QCOM_RPM_PM8921_LVS6, &pm8921_switch, "vin_lvs1_3_6" }, + { "lvs7", QCOM_RPM_PM8921_LVS7, &pm8921_switch, "vin_lvs4_5_7" }, + + { "usb-switch", QCOM_RPM_USB_OTG_SWITCH, &pm8921_switch, "vin_5vs" }, + { "hdmi-switch", QCOM_RPM_HDMI_SWITCH, &pm8921_switch, "vin_5vs" }, + { "ncp", QCOM_RPM_PM8921_NCP, &pm8921_ncp, "vdd_ncp" }, + { } +}; + +static const struct of_device_id rpm_of_match[] = { + { .compatible = "qcom,rpm-pm8058-regulators", .data = &rpm_pm8058_regulators }, + { .compatible = "qcom,rpm-pm8901-regulators", .data = &rpm_pm8901_regulators }, + { .compatible = "qcom,rpm-pm8921-regulators", .data = &rpm_pm8921_regulators }, + { } +}; +MODULE_DEVICE_TABLE(of, rpm_of_match); + static int rpm_reg_probe(struct platform_device *pdev) { - struct regulator_init_data *initdata; - const struct qcom_rpm_reg *template; + const struct rpm_regulator_data *reg; const struct of_device_id *match; struct regulator_config config = { }; struct regulator_dev *rdev; struct qcom_rpm_reg *vreg; - const char *key; - u32 val; - int ret; match = of_match_device(rpm_of_match, &pdev->dev); - template = match->data; + for (reg = match->data; reg->name; reg++) { + vreg = devm_kmalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL); + if (!vreg) { + dev_err(&pdev->dev, "failed to allocate vreg\n"); + return -ENOMEM; + } + memcpy(vreg, reg->template, sizeof(*vreg)); + mutex_init(&vreg->lock); - vreg = devm_kmalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL); - if (!vreg) { - dev_err(&pdev->dev, "failed to allocate vreg\n"); - return -ENOMEM; - } - memcpy(vreg, template, sizeof(*vreg)); - mutex_init(&vreg->lock); - vreg->dev = &pdev->dev; - vreg->desc.id = -1; - vreg->desc.owner = THIS_MODULE; - vreg->desc.type = REGULATOR_VOLTAGE; - vreg->desc.name = pdev->dev.of_node->name; - vreg->desc.supply_name = "vin"; + vreg->dev = &pdev->dev; + vreg->resource = reg->resource; - vreg->rpm = dev_get_drvdata(pdev->dev.parent); - if (!vreg->rpm) { - dev_err(&pdev->dev, "unable to retrieve handle to rpm\n"); - return -ENODEV; - } + vreg->desc.id = -1; + vreg->desc.owner = THIS_MODULE; + vreg->desc.type = REGULATOR_VOLTAGE; + vreg->desc.name = reg->name; + vreg->desc.supply_name = reg->supply; + vreg->desc.of_match = reg->name; + vreg->desc.of_parse_cb = rpm_reg_of_parse; - initdata = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node, - &vreg->desc); - if (!initdata) - return -EINVAL; + vreg->rpm = dev_get_drvdata(pdev->dev.parent); + if (!vreg->rpm) { + dev_err(&pdev->dev, "unable to retrieve handle to rpm\n"); + return -ENODEV; + } - key = "reg"; - ret = of_property_read_u32(pdev->dev.of_node, key, &val); - if (ret) { - dev_err(&pdev->dev, "failed to read %s\n", key); - return ret; - } - vreg->resource = val; - - if ((vreg->parts->uV.mask || vreg->parts->mV.mask) && - (!initdata->constraints.min_uV || !initdata->constraints.max_uV)) { - dev_err(&pdev->dev, "no voltage specified for regulator\n"); - return -EINVAL; - } - - - config.dev = &pdev->dev; - config.init_data = initdata; - config.driver_data = vreg; - config.of_node = pdev->dev.of_node; - - ret = rpm_reg_of_parse(pdev->dev.of_node, &vreg->desc, &config); - if (ret) - return ret; - - rdev = devm_regulator_register(&pdev->dev, &vreg->desc, &config); - if (IS_ERR(rdev)) { - dev_err(&pdev->dev, "can't register regulator\n"); - return PTR_ERR(rdev); + config.dev = &pdev->dev; + config.driver_data = vreg; + rdev = devm_regulator_register(&pdev->dev, &vreg->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "can't register regulator\n"); + return PTR_ERR(rdev); + } } return 0; From ce8ae17c5d86db92cecd8291ad6a137dc19031ad Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 6 Apr 2015 16:34:00 -0700 Subject: [PATCH 31/34] regulator: qcom: Tidy up probe() Tidy up error reporting and move rpm reference retrieval out of the for loop for improved readability. Signed-off-by: Bjorn Andersson Reviewed-by: Stephen Boyd Signed-off-by: Mark Brown --- drivers/regulator/qcom_rpm-regulator.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c index 40cf6ff0d1ff..e254272585b2 100644 --- a/drivers/regulator/qcom_rpm-regulator.c +++ b/drivers/regulator/qcom_rpm-regulator.c @@ -884,19 +884,26 @@ static int rpm_reg_probe(struct platform_device *pdev) struct regulator_config config = { }; struct regulator_dev *rdev; struct qcom_rpm_reg *vreg; + struct qcom_rpm *rpm; + + rpm = dev_get_drvdata(pdev->dev.parent); + if (!rpm) { + dev_err(&pdev->dev, "unable to retrieve handle to rpm\n"); + return -ENODEV; + } match = of_match_device(rpm_of_match, &pdev->dev); for (reg = match->data; reg->name; reg++) { vreg = devm_kmalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL); - if (!vreg) { - dev_err(&pdev->dev, "failed to allocate vreg\n"); + if (!vreg) return -ENOMEM; - } + memcpy(vreg, reg->template, sizeof(*vreg)); mutex_init(&vreg->lock); vreg->dev = &pdev->dev; vreg->resource = reg->resource; + vreg->rpm = rpm; vreg->desc.id = -1; vreg->desc.owner = THIS_MODULE; @@ -906,17 +913,11 @@ static int rpm_reg_probe(struct platform_device *pdev) vreg->desc.of_match = reg->name; vreg->desc.of_parse_cb = rpm_reg_of_parse; - vreg->rpm = dev_get_drvdata(pdev->dev.parent); - if (!vreg->rpm) { - dev_err(&pdev->dev, "unable to retrieve handle to rpm\n"); - return -ENODEV; - } - config.dev = &pdev->dev; config.driver_data = vreg; rdev = devm_regulator_register(&pdev->dev, &vreg->desc, &config); if (IS_ERR(rdev)) { - dev_err(&pdev->dev, "can't register regulator\n"); + dev_err(&pdev->dev, "failed to register %s\n", reg->name); return PTR_ERR(rdev); } } From 7c225ec90c368a474daa9803922f4b7d6fe6d5c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Tue, 7 Apr 2015 16:16:39 +0200 Subject: [PATCH 32/34] regulator: add a summary tree in debugfs On modern systems the regulator hierarchy can get quite long and nested with regulators supplying other regulators. In some cases when debugging it might be nice to get a tree of these regulators, their consumers and the regulation constraints in one go. To achieve this add a regulator_summary sysfs node, similar to clk_summary in the common clock framework, that walks the regulator list and creates a tree out of the regulators, their consumers and core per-regulator settings. On a rk3288-firefly the regulator_summary would for example look something like: regulator use open bypass value min max ----------------------------------------------------------------------- vcc_sys 0 12 0 5000mV 5000mV 5000mV vcc_lan 1 1 0 3300mV 3300mV 3300mV ff290000.ethernet 0mV 0mV vcca_33 0 0 0 3300mV 3300mV 3300mV vcca_18 0 0 0 1800mV 1800mV 1800mV vdd10_lcd 0 0 0 1000mV 1000mV 1000mV vccio_sd 0 0 0 3300mV 3300mV 3300mV vcc_20 0 3 0 2000mV 2000mV 2000mV vcc18_lcd 0 0 0 1800mV 1800mV 1800mV vcc_18 0 2 0 1800mV 1800mV 1800mV ff100000.saradc 0mV 0mV ff0d0000.dwmmc 1650mV 1950mV vdd_10 0 0 0 1000mV 1000mV 1000mV vdd_log 0 0 0 1100mV 1100mV 1100mV vcc_io 0 3 0 3300mV 3300mV 3300mV ff0f0000.dwmmc 3300mV 3400mV vcc_flash 1 1 0 1800mV 1800mV 1800mV ff0f0000.dwmmc 1700mV 1950mV vcc_sd 1 1 0 3300mV 3300mV 3300mV ff0c0000.dwmmc 3300mV 3400mV vcc_ddr 0 0 0 1200mV 1200mV 1200mV vdd_gpu 0 0 0 1000mV 850mV 1350mV vdd_cpu 0 1 0 900mV 850mV 1350mV cpu0 900mV 900mV vcc_5v 0 2 0 5000mV 5000mV 5000mV vcc_otg_5v 0 0 0 5000mV 5000mV 5000mV vcc_host_5v 0 0 0 5000mV 5000mV 5000mV regulator-dummy 0 0 0 0mV 0mV 0mV Signed-off-by: Heiko Stuebner Signed-off-by: Mark Brown --- drivers/regulator/core.c | 121 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index cc242aa368ef..5aae1bd61151 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3954,6 +3954,124 @@ static const struct file_operations supply_map_fops = { #endif }; +#ifdef CONFIG_DEBUG_FS +static void regulator_summary_show_subtree(struct seq_file *s, + struct regulator_dev *rdev, + int level) +{ + struct list_head *list = s->private; + struct regulator_dev *child; + struct regulation_constraints *c; + struct regulator *consumer; + + if (!rdev) + return; + + mutex_lock(&rdev->mutex); + + seq_printf(s, "%*s%-*s %3d %4d %6d ", + level * 3 + 1, "", + 30 - level * 3, rdev_get_name(rdev), + rdev->use_count, rdev->open_count, rdev->bypass_count); + + switch (rdev->desc->type) { + case REGULATOR_VOLTAGE: + seq_printf(s, "%5dmV ", + _regulator_get_voltage(rdev) / 1000); + break; + case REGULATOR_CURRENT: + seq_printf(s, "%5dmA ", + _regulator_get_current_limit(rdev) / 1000); + break; + } + + c = rdev->constraints; + if (c) { + switch (rdev->desc->type) { + case REGULATOR_VOLTAGE: + seq_printf(s, "%5dmV %5dmV ", + c->min_uV / 1000, c->max_uV / 1000); + break; + case REGULATOR_CURRENT: + seq_printf(s, "%5dmA %5dmA ", + c->min_uA / 1000, c->max_uA / 1000); + break; + } + } + + seq_puts(s, "\n"); + + list_for_each_entry(consumer, &rdev->consumer_list, list) { + if (consumer->dev->class == ®ulator_class) + continue; + + seq_printf(s, "%*s%-*s ", + (level + 1) * 3 + 1, "", + 30 - (level + 1) * 3, dev_name(consumer->dev)); + + switch (rdev->desc->type) { + case REGULATOR_VOLTAGE: + seq_printf(s, "%29dmV %5dmV", + consumer->min_uV / 1000, + consumer->max_uV / 1000); + break; + case REGULATOR_CURRENT: + seq_printf(s, "%37dmA", + regulator_get_current_limit(consumer) / 1000); + break; + } + + seq_puts(s, "\n"); + } + + mutex_unlock(&rdev->mutex); + + list_for_each_entry(child, list, list) { + /* handle only non-root regulators supplied by current rdev */ + if (!child->supply || child->supply->rdev != rdev) + continue; + + regulator_summary_show_subtree(s, child, level + 1); + } +} + +static int regulator_summary_show(struct seq_file *s, void *data) +{ + struct list_head *list = s->private; + struct regulator_dev *rdev; + + seq_puts(s, " regulator use open bypass value min max\n"); + seq_puts(s, "-----------------------------------------------------------------------\n"); + + mutex_lock(®ulator_list_mutex); + + list_for_each_entry(rdev, list, list) { + if (rdev->supply) + continue; + + regulator_summary_show_subtree(s, rdev, 0); + } + + mutex_unlock(®ulator_list_mutex); + + return 0; +} + +static int regulator_summary_open(struct inode *inode, struct file *file) +{ + return single_open(file, regulator_summary_show, inode->i_private); +} +#endif + +static const struct file_operations regulator_summary_fops = { +#ifdef CONFIG_DEBUG_FS + .open = regulator_summary_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +#endif +}; + static int __init regulator_init(void) { int ret; @@ -3967,6 +4085,9 @@ static int __init regulator_init(void) debugfs_create_file("supply_map", 0444, debugfs_root, NULL, &supply_map_fops); + debugfs_create_file("regulator_summary", 0444, debugfs_root, + ®ulator_list, ®ulator_summary_fops); + regulator_dummy_init(); return ret; From 23296099e70854a272fc369bab8ddcc57f27f97a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Fri, 10 Apr 2015 13:48:41 +0200 Subject: [PATCH 33/34] regulator: output current-limit for all regulators in summary Voltage regulators can have (unregulated) current limits too, so we should probably output both voltage and current for all regulators. Holding the rdev->mutex actually conflicts with _regulator_get_current_limit but also is not really necessary, as the global regulator_list_mutex already protects us from the regulator vanishing while we go through the list. On the rk3288-firefly the summary now looks like: regulator use open bypass voltage current min max ------------------------------------------------------------------------------- vcc_sys 0 12 0 5000mV 0mA 5000mV 5000mV vcc_lan 1 1 0 3300mV 0mA 3300mV 3300mV ff290000.ethernet 0mV 0mV vcca_33 0 0 0 3300mV 0mA 3300mV 3300mV vcca_18 0 0 0 1800mV 0mA 1800mV 1800mV vdd10_lcd 0 0 0 1000mV 0mA 1000mV 1000mV [...] Suggested-by: Mark Brown Signed-off-by: Heiko Stuebner Signed-off-by: Mark Brown --- drivers/regulator/core.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 5aae1bd61151..0ea0a019dc57 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3967,23 +3967,13 @@ static void regulator_summary_show_subtree(struct seq_file *s, if (!rdev) return; - mutex_lock(&rdev->mutex); - seq_printf(s, "%*s%-*s %3d %4d %6d ", level * 3 + 1, "", 30 - level * 3, rdev_get_name(rdev), rdev->use_count, rdev->open_count, rdev->bypass_count); - switch (rdev->desc->type) { - case REGULATOR_VOLTAGE: - seq_printf(s, "%5dmV ", - _regulator_get_voltage(rdev) / 1000); - break; - case REGULATOR_CURRENT: - seq_printf(s, "%5dmA ", - _regulator_get_current_limit(rdev) / 1000); - break; - } + seq_printf(s, "%5dmV ", _regulator_get_voltage(rdev) / 1000); + seq_printf(s, "%5dmA ", _regulator_get_current_limit(rdev) / 1000); c = rdev->constraints; if (c) { @@ -4011,21 +4001,17 @@ static void regulator_summary_show_subtree(struct seq_file *s, switch (rdev->desc->type) { case REGULATOR_VOLTAGE: - seq_printf(s, "%29dmV %5dmV", + seq_printf(s, "%37dmV %5dmV", consumer->min_uV / 1000, consumer->max_uV / 1000); break; case REGULATOR_CURRENT: - seq_printf(s, "%37dmA", - regulator_get_current_limit(consumer) / 1000); break; } seq_puts(s, "\n"); } - mutex_unlock(&rdev->mutex); - list_for_each_entry(child, list, list) { /* handle only non-root regulators supplied by current rdev */ if (!child->supply || child->supply->rdev != rdev) @@ -4040,8 +4026,8 @@ static int regulator_summary_show(struct seq_file *s, void *data) struct list_head *list = s->private; struct regulator_dev *rdev; - seq_puts(s, " regulator use open bypass value min max\n"); - seq_puts(s, "-----------------------------------------------------------------------\n"); + seq_puts(s, " regulator use open bypass voltage current min max\n"); + seq_puts(s, "-------------------------------------------------------------------------------\n"); mutex_lock(®ulator_list_mutex); From c0cf5a59fb69527151eb8e332a1b9660200f66c6 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Fri, 10 Apr 2015 15:23:42 +0200 Subject: [PATCH 34/34] regulator: max8660: Handle empty regulator data It is not necessary to have regulator init data for a regulator. This patch removes the necessity of this data and handles a NULL pointer properly. Signed-off-by: Markus Pargmann Signed-off-by: Mark Brown --- drivers/regulator/max8660.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index f187c8f13e22..4071d74fa828 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -442,9 +442,9 @@ static int max8660_probe(struct i2c_client *client, for (i = 0; i < pdata->num_subdevs; i++) { if (!pdata->subdevs[i].platform_data) - return ret; - - boot_on = pdata->subdevs[i].platform_data->constraints.boot_on; + boot_on = false; + else + boot_on = pdata->subdevs[i].platform_data->constraints.boot_on; switch (pdata->subdevs[i].id) { case MAX8660_V3: