summaryrefslogtreecommitdiffstats
path: root/drivers/phy/qualcomm/phy-qcom-ufs.c
diff options
context:
space:
mode:
authorEvan Green <evgreen@chromium.org>2019-03-21 10:18:00 -0700
committerKishon Vijay Abraham I <kishon@ti.com>2019-04-17 14:12:57 +0530
commit3f6d1767b1a011165cb404df1acdf003252df153 (patch)
tree6a51f27705c832c2fd860853245874c98d432096 /drivers/phy/qualcomm/phy-qcom-ufs.c
parentc9b589791fc1b37fdca35b621dae62e98e4c95fc (diff)
downloadlinux-3f6d1767b1a011165cb404df1acdf003252df153.tar.bz2
phy: ufs-qcom: Refactor all init steps into phy_poweron
The phy code was using implicit sequencing between the PHY driver and the UFS driver to implement certain hardware requirements. Specifically, the PHY reset register in the UFS controller needs to be deasserted before serdes start occurs in the PHY. Before this change, the code was doing this by utilizing the two phy callbacks, phy_init() and phy_poweron(), as "init step 1" and "init step 2", where the UFS driver would deassert reset between these two steps. This makes it challenging to power off the regulators in suspend, as regulators are initialized in init, not in poweron(), but only poweroff() is called during suspend, not exit(). For UFS, move the actual firing up of the PHY to phy_poweron() and phy_poweroff() callbacks, rather than init()/exit(). UFS calls phy_poweroff() during suspend, so now all clocks and regulators for the phy can be powered down during suspend. QMP is a little tricky because the PHY is also shared with PCIe and USB3, which have their own definitions for init() and poweron(). Rename the meaty functions to _enable() and _disable() to disentangle from the PHY core names, and then create two different ops structures: one for UFS and one for the other PHY types. In phy-qcom-ufs, remove the 'is_powered_on' and 'is_started' guards, as the generic PHY code does the reference counting. The 14/20nm-specific init functions get collapsed into the generic power_on() function, with the addition of a calibrate() callback specific to 14/20nm. Signed-off-by: Evan Green <evgreen@chromium.org> Reviewed-by: Stephen Boyd <swboyd@chromium.org> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Diffstat (limited to 'drivers/phy/qualcomm/phy-qcom-ufs.c')
-rw-r--r--drivers/phy/qualcomm/phy-qcom-ufs.c42
1 files changed, 22 insertions, 20 deletions
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c
index fe59785a55f2..0a9f50f086b6 100644
--- a/drivers/phy/qualcomm/phy-qcom-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-ufs.c
@@ -147,7 +147,7 @@ out:
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_generic_probe);
-int ufs_qcom_phy_get_reset(struct ufs_qcom_phy *phy_common)
+static int ufs_qcom_phy_get_reset(struct ufs_qcom_phy *phy_common)
{
struct reset_control *reset;
@@ -161,7 +161,6 @@ int ufs_qcom_phy_get_reset(struct ufs_qcom_phy *phy_common)
phy_common->ufs_reset = reset;
return 0;
}
-EXPORT_SYMBOL_GPL(ufs_qcom_phy_get_reset);
static int __ufs_qcom_phy_clk_get(struct device *dev,
const char *name, struct clk **clk_out, bool err_print)
@@ -544,10 +543,23 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy)
{
struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
struct device *dev = phy_common->dev;
+ bool is_rate_B = false;
int err;
- if (phy_common->is_powered_on)
- return 0;
+ err = ufs_qcom_phy_get_reset(phy_common);
+ if (err)
+ return err;
+
+ err = reset_control_assert(phy_common->ufs_reset);
+ if (err)
+ return err;
+
+ if (phy_common->mode == PHY_MODE_UFS_HS_B)
+ is_rate_B = true;
+
+ err = phy_common->phy_spec_ops->calibrate(phy_common, is_rate_B);
+ if (err)
+ return err;
err = reset_control_deassert(phy_common->ufs_reset);
if (err) {
@@ -555,17 +567,13 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy)
return err;
}
- if (!phy_common->is_started) {
- err = ufs_qcom_phy_start_serdes(phy_common);
- if (err)
- return err;
-
- err = ufs_qcom_phy_is_pcs_ready(phy_common);
- if (err)
- return err;
+ err = ufs_qcom_phy_start_serdes(phy_common);
+ if (err)
+ return err;
- phy_common->is_started = true;
- }
+ err = ufs_qcom_phy_is_pcs_ready(phy_common);
+ if (err)
+ return err;
err = ufs_qcom_phy_enable_vreg(dev, &phy_common->vdda_phy);
if (err) {
@@ -609,7 +617,6 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy)
}
}
- phy_common->is_powered_on = true;
goto out;
out_disable_ref_clk:
@@ -629,9 +636,6 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy)
{
struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
- if (!phy_common->is_powered_on)
- return 0;
-
phy_common->phy_spec_ops->power_control(phy_common, false);
if (phy_common->vddp_ref_clk.reg)
@@ -643,8 +647,6 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy)
ufs_qcom_phy_disable_vreg(phy_common->dev, &phy_common->vdda_pll);
ufs_qcom_phy_disable_vreg(phy_common->dev, &phy_common->vdda_phy);
reset_control_assert(phy_common->ufs_reset);
- phy_common->is_powered_on = false;
-
return 0;
}
EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off);