From 046db763aaaeb987ea01ea8c7e6d618e0ad1e6b8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 5 Mar 2015 15:39:20 +0000 Subject: [PATCH 01/14] 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 e39ce48f5362df9f87400b4909a6fb0f51b109ac Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 11 Feb 2015 19:35:27 -0800 Subject: [PATCH 02/14] 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 03/14] 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 04/14] 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 05/14] 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 06/14] 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 07/14] 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 08/14] 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 09/14] 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 10/14] 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 4d1e4d629a484b725d5fc88d7e0f967435ab6edd Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 6 Apr 2015 16:33:57 -0700 Subject: [PATCH 11/14] 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 12/14] 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 13/14] 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 14/14] 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); } }