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.

Signed-off-by: Evan Green <evgr...@chromium.org>

---

 drivers/phy/qualcomm/phy-qcom-qmp.c | 82 ++++++++---------------------
 1 file changed, 23 insertions(+), 59 deletions(-)

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c 
b/drivers/phy/qualcomm/phy-qcom-qmp.c
index eb1cac8f0fd4e..7766c6384d0a8 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -1209,8 +1209,7 @@ static int qcom_qmp_phy_com_exit(struct qcom_qmp *qmp)
        return 0;
 }
 
-/* PHY Initialization */
-static int qcom_qmp_phy_init(struct phy *phy)
+static int qcom_qmp_phy_enable(struct phy *phy)
 {
        struct qmp_phy *qphy = phy_get_drvdata(phy);
        struct qcom_qmp *qmp = qphy->qmp;
@@ -1224,7 +1223,6 @@ static int qcom_qmp_phy_init(struct phy *phy)
        int ret;
 
        dev_vdbg(qmp->dev, "Initializing QMP phy\n");
-
        if (cfg->has_ufsphy_reset) {
                /*
                 * Get UFS reset, which is delayed until now to avoid a
@@ -1292,14 +1290,6 @@ static int qcom_qmp_phy_init(struct phy *phy)
                }
        }
 
-       /*
-        * UFS PHY requires the deassert of software reset before serdes start.
-        * For UFS PHYs that do not have software reset control bits, defer
-        * starting serdes until the power on callback.
-        */
-       if ((cfg->type == PHY_TYPE_UFS) && cfg->no_pcs_sw_reset)
-               goto out;
-
        /*
         * Pull out PHY from POWER DOWN state.
         * This is active low enable signal to power-down PHY.
@@ -1311,7 +1301,9 @@ static int qcom_qmp_phy_init(struct phy *phy)
                usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max);
 
        /* Pull PHY out of reset state */
-       qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
+       if (!cfg->no_pcs_sw_reset)
+               qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
+
        if (cfg->has_phy_dp_com_ctrl)
                qphy_clrbits(dp_com, QPHY_V3_DP_COM_SW_RESET, SW_RESET);
 
@@ -1328,11 +1320,12 @@ static int qcom_qmp_phy_init(struct phy *phy)
                goto err_pcs_ready;
        }
        qmp->phy_initialized = true;
-
-out:
-       return ret;
+       return 0;
 
 err_pcs_ready:
+       if (qmp->ufs_reset)
+               reset_control_assert(qmp->ufs_reset);
+
        clk_disable_unprepare(qphy->pipe_clk);
 err_clk_enable:
        if (cfg->has_lane_rst)
@@ -1343,7 +1336,7 @@ static int qcom_qmp_phy_init(struct phy *phy)
        return ret;
 }
 
-static int qcom_qmp_phy_exit(struct phy *phy)
+static int qcom_qmp_phy_disable(struct phy *phy)
 {
        struct qmp_phy *qphy = phy_get_drvdata(phy);
        struct qcom_qmp *qmp = qphy->qmp;
@@ -1360,7 +1353,6 @@ static int qcom_qmp_phy_exit(struct phy *phy)
 
        /* Put PHY into POWER DOWN state: active low */
        qphy_clrbits(qphy->pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
-
        if (cfg->has_lane_rst)
                reset_control_assert(qphy->lane_rst);
 
@@ -1371,44 +1363,6 @@ static int qcom_qmp_phy_exit(struct phy *phy)
        return 0;
 }
 
-static int qcom_qmp_phy_poweron(struct phy *phy)
-{
-       struct qmp_phy *qphy = phy_get_drvdata(phy);
-       struct qcom_qmp *qmp = qphy->qmp;
-       const struct qmp_phy_cfg *cfg = qmp->cfg;
-       void __iomem *pcs = qphy->pcs;
-       void __iomem *status;
-       unsigned int mask, val;
-       int ret = 0;
-
-       if (cfg->type != PHY_TYPE_UFS)
-               return 0;
-
-       /*
-        * For UFS PHY that has not software reset control, serdes start
-        * should only happen when UFS driver explicitly calls phy_power_on
-        * after it deasserts software reset.
-        */
-       if (cfg->no_pcs_sw_reset && !qmp->phy_initialized &&
-           (qmp->init_count != 0)) {
-               /* start SerDes and Phy-Coding-Sublayer */
-               qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
-
-               status = pcs + cfg->regs[QPHY_PCS_READY_STATUS];
-               mask = cfg->mask_pcs_ready;
-
-               ret = readl_poll_timeout(status, val, !(val & mask), 1,
-                                        PHY_INIT_COMPLETE_TIMEOUT);
-               if (ret) {
-                       dev_err(qmp->dev, "phy initialization timed-out\n");
-                       return ret;
-               }
-               qmp->phy_initialized = true;
-       }
-
-       return ret;
-}
-
 static int qcom_qmp_phy_set_mode(struct phy *phy,
                                 enum phy_mode mode, int submode)
 {
@@ -1658,9 +1612,15 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, 
struct device_node *np)
 }
 
 static const struct phy_ops qcom_qmp_phy_gen_ops = {
-       .init           = qcom_qmp_phy_init,
-       .exit           = qcom_qmp_phy_exit,
-       .power_on       = qcom_qmp_phy_poweron,
+       .init           = qcom_qmp_phy_enable,
+       .exit           = qcom_qmp_phy_disable,
+       .set_mode       = qcom_qmp_phy_set_mode,
+       .owner          = THIS_MODULE,
+};
+
+static const struct phy_ops qcom_qmp_ufs_ops = {
+       .power_on       = qcom_qmp_phy_enable,
+       .power_off      = qcom_qmp_phy_disable,
        .set_mode       = qcom_qmp_phy_set_mode,
        .owner          = THIS_MODULE,
 };
@@ -1671,6 +1631,7 @@ int qcom_qmp_phy_create(struct device *dev, struct 
device_node *np, int id)
        struct qcom_qmp *qmp = dev_get_drvdata(dev);
        struct phy *generic_phy;
        struct qmp_phy *qphy;
+       const struct phy_ops *ops = &qcom_qmp_phy_gen_ops;
        char prop_name[MAX_PROP_NAME];
        int ret;
 
@@ -1757,7 +1718,10 @@ int qcom_qmp_phy_create(struct device *dev, struct 
device_node *np, int id)
                }
        }
 
-       generic_phy = devm_phy_create(dev, np, &qcom_qmp_phy_gen_ops);
+       if (qmp->cfg->type == PHY_TYPE_UFS)
+               ops = &qcom_qmp_ufs_ops;
+
+       generic_phy = devm_phy_create(dev, np, ops);
        if (IS_ERR(generic_phy)) {
                ret = PTR_ERR(generic_phy);
                dev_err(dev, "failed to create qphy %d\n", ret);
-- 
2.18.1

Reply via email to