From 2f94b8d7bdf854c76d5b0b6f70cd097dd80f19d7 Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Wed, 29 Oct 2014 19:20:13 -0700 Subject: [PATCH] scsi: ufs-qcom: add device ref_clk pad regulator voting support UFS device's phy ref_clk is sourced via MSM's ref_clk pad. This pad is having its own power domain which is powered by 1.2v rail. This change adds the voting support for this pad rail. Change-Id: I179b2b9bb7ef2e7938ba0aaa87faed09cdad6139 Signed-off-by: Subhash Jadavani [venkatg@codeaurora.org: dropped ufs-qcom.h and include/linux/phy/phy-qcom-ufs.h changes] Signed-off-by: Venkat Gopalakrishnan --- drivers/phy/phy-qcom-ufs.c | 41 ++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c index d3574c20d9ee..dc823f52e586 100644 --- a/drivers/phy/phy-qcom-ufs.c +++ b/drivers/phy/phy-qcom-ufs.c @@ -232,12 +232,19 @@ ufs_qcom_phy_init_vregulators(struct phy *generic_phy, err = ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vdda_phy, "vdda-phy"); + + if (err) + goto out; + + /* vddp-ref-clk-* properties are optional */ + __ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vddp_ref_clk, + "vddp-ref-clk", true); out: return err; } -int ufs_qcom_phy_init_vreg(struct phy *phy, - struct ufs_qcom_phy_vreg *vreg, const char *name) +static int __ufs_qcom_phy_init_vreg(struct phy *phy, + struct ufs_qcom_phy_vreg *vreg, const char *name, bool optional) { int err = 0; struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy); @@ -254,7 +261,9 @@ int ufs_qcom_phy_init_vreg(struct phy *phy, vreg->reg = devm_regulator_get(dev, name); if (IS_ERR(vreg->reg)) { err = PTR_ERR(vreg->reg); - dev_err(dev, "failed to get %s, %d\n", name, err); + vreg->reg = NULL; + if (!optional) + dev_err(dev, "failed to get %s, %d\n", name, err); goto out; } @@ -274,6 +283,11 @@ int ufs_qcom_phy_init_vreg(struct phy *phy, } err = 0; } + snprintf(prop_name, MAX_PROP_NAME, "%s-always-on", name); + if (of_get_property(dev->of_node, prop_name, NULL)) + vreg->is_always_on = true; + else + vreg->is_always_on = false; } if (!strcmp(name, "vdda-pll")) { @@ -282,6 +296,9 @@ int ufs_qcom_phy_init_vreg(struct phy *phy, } else if (!strcmp(name, "vdda-phy")) { vreg->max_uV = VDDA_PHY_MAX_UV; vreg->min_uV = VDDA_PHY_MIN_UV; + } else if (!strcmp(name, "vddp-ref-clk")) { + vreg->max_uV = VDDP_REF_CLK_MAX_UV; + vreg->min_uV = VDDP_REF_CLK_MIN_UV; } out: @@ -425,7 +442,7 @@ int ufs_qcom_phy_disable_vreg(struct phy *phy, struct device *dev = ufs_qcom_phy->dev; int ret = 0; - if (!vreg || !vreg->enabled) + if (!vreg || !vreg->enabled || vreg->is_always_on) goto out; ret = regulator_disable(vreg->reg); @@ -643,9 +660,22 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy) goto out_disable_pll; } + /* enable device PHY ref_clk pad rail */ + if (phy_common->vddp_ref_clk.reg) { + err = ufs_qcom_phy_enable_vreg(generic_phy, + &phy_common->vddp_ref_clk); + if (err) { + dev_err(dev, "%s enable vddp_ref_clk failed, err=%d\n", + __func__, err); + goto out_disable_ref_clk; + } + } + phy_common->is_powered_on = true; goto out; +out_disable_ref_clk: + ufs_qcom_phy_disable_ref_clk(generic_phy); out_disable_pll: ufs_qcom_phy_disable_vreg(generic_phy, &phy_common->vdda_pll); out_disable_phy: @@ -660,6 +690,9 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy) phy_common->phy_spec_ops->power_control(phy_common, false); + if (phy_common->vddp_ref_clk.reg) + ufs_qcom_phy_disable_vreg(generic_phy, + &phy_common->vddp_ref_clk); ufs_qcom_phy_disable_ref_clk(generic_phy); ufs_qcom_phy_disable_vreg(generic_phy, &phy_common->vdda_pll);