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;
        if (ret)
                goto err_lane_rst;
 
-       /*
-        * 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.
                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);
 
                goto err_pcs_ready;
        }
        qmp->phy_initialized = true;
-
-out:
-       return ret;
+       return 0;
 
 err_pcs_ready:
+       reset_control_assert(qmp->ufs_reset);
        clk_disable_unprepare(qphy->pipe_clk);
 err_clk_enable:
        if (cfg->has_lane_rst)
        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;
        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)
 {
 }
 
 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,
 };
        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;
 
                }
        }
 
-       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);
 
        char name[UFS_QCOM_PHY_NAME_LEN];
        struct ufs_qcom_phy_calibration *cached_regs;
        int cached_regs_table_size;
-       bool is_powered_on;
-       bool is_started;
        struct ufs_qcom_phy_specific_ops *phy_spec_ops;
 
        enum phy_mode mode;
  * and writes to QSERDES_RX_SIGDET_CNTRL attribute
  */
 struct ufs_qcom_phy_specific_ops {
+       int (*calibrate)(struct ufs_qcom_phy *ufs_qcom_phy, bool is_rate_B);
        void (*start_serdes)(struct ufs_qcom_phy *phy);
        int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy);
        void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val);
                        struct ufs_qcom_phy *common_cfg,
                        const struct phy_ops *ufs_qcom_phy_gen_ops,
                        struct ufs_qcom_phy_specific_ops *phy_spec_ops);
-int ufs_qcom_phy_get_reset(struct ufs_qcom_phy *phy_common);
 int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
                        struct ufs_qcom_phy_calibration *tbl_A, int tbl_size_A,
                        struct ufs_qcom_phy_calibration *tbl_B, int tbl_size_B,
 
                UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE;
 }
 
-static int ufs_qcom_phy_qmp_14nm_init(struct phy *generic_phy)
-{
-       struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
-       bool is_rate_B = false;
-       int ret;
-
-       ret = ufs_qcom_phy_get_reset(phy_common);
-       if (ret)
-               return ret;
-
-       ret = reset_control_assert(phy_common->ufs_reset);
-       if (ret)
-               return ret;
-
-       if (phy_common->mode == PHY_MODE_UFS_HS_B)
-               is_rate_B = true;
-
-       ret = ufs_qcom_phy_qmp_14nm_phy_calibrate(phy_common, is_rate_B);
-       if (!ret)
-               /* phy calibrated, but yet to be started */
-               phy_common->is_started = false;
-
-       return ret;
-}
-
-static int ufs_qcom_phy_qmp_14nm_exit(struct phy *generic_phy)
-{
-       return 0;
-}
-
 static
 int ufs_qcom_phy_qmp_14nm_set_mode(struct phy *generic_phy,
                                   enum phy_mode mode, int submode)
 }
 
 static const struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = {
-       .init           = ufs_qcom_phy_qmp_14nm_init,
-       .exit           = ufs_qcom_phy_qmp_14nm_exit,
        .power_on       = ufs_qcom_phy_power_on,
        .power_off      = ufs_qcom_phy_power_off,
        .set_mode       = ufs_qcom_phy_qmp_14nm_set_mode,
 };
 
 static struct ufs_qcom_phy_specific_ops phy_14nm_ops = {
+       .calibrate              = ufs_qcom_phy_qmp_14nm_phy_calibrate,
        .start_serdes           = ufs_qcom_phy_qmp_14nm_start_serdes,
        .is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_14nm_is_pcs_ready,
        .set_tx_lane_enable     = ufs_qcom_phy_qmp_14nm_set_tx_lane_enable,
 
                UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE;
 }
 
-static int ufs_qcom_phy_qmp_20nm_init(struct phy *generic_phy)
-{
-       struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
-       bool is_rate_B = false;
-       int ret;
-
-       ret = ufs_qcom_phy_get_reset(phy_common);
-       if (ret)
-               return ret;
-
-       ret = reset_control_assert(phy_common->ufs_reset);
-       if (ret)
-               return ret;
-
-       if (phy_common->mode == PHY_MODE_UFS_HS_B)
-               is_rate_B = true;
-
-       ret = ufs_qcom_phy_qmp_20nm_phy_calibrate(phy_common, is_rate_B);
-       if (!ret)
-               /* phy calibrated, but yet to be started */
-               phy_common->is_started = false;
-
-       return ret;
-}
-
-static int ufs_qcom_phy_qmp_20nm_exit(struct phy *generic_phy)
-{
-       return 0;
-}
-
 static
 int ufs_qcom_phy_qmp_20nm_set_mode(struct phy *generic_phy,
                                   enum phy_mode mode, int submode)
 }
 
 static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = {
-       .init           = ufs_qcom_phy_qmp_20nm_init,
-       .exit           = ufs_qcom_phy_qmp_20nm_exit,
        .power_on       = ufs_qcom_phy_power_on,
        .power_off      = ufs_qcom_phy_power_off,
        .set_mode       = ufs_qcom_phy_qmp_20nm_set_mode,
 };
 
 static struct ufs_qcom_phy_specific_ops phy_20nm_ops = {
+       .calibrate              = ufs_qcom_phy_qmp_20nm_phy_calibrate,
        .start_serdes           = ufs_qcom_phy_qmp_20nm_start_serdes,
        .is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_20nm_is_pcs_ready,
        .set_tx_lane_enable     = ufs_qcom_phy_qmp_20nm_set_tx_lane_enable,
 
 }
 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;
 
        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)
 {
        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) {
                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) {
                }
        }
 
-       phy_common->is_powered_on = true;
        goto out;
 
 out_disable_ref_clk:
 {
        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)
        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);
 
                 */
                ufs_qcom_disable_lane_clks(host);
                phy_power_off(phy);
-               goto out;
-       }
 
-       /*
-        * If UniPro link is not active, PHY ref_clk, main PHY analog power
-        * rail and low noise analog power rail for PLL can be switched off.
-        */
-       if (!ufs_qcom_is_link_active(hba)) {
+       } else if (!ufs_qcom_is_link_active(hba)) {
                ufs_qcom_disable_lane_clks(host);
-               phy_power_off(phy);
        }
 
-out:
        return ret;
 }
 
        struct phy *phy = host->generic_phy;
        int err;
 
-       err = phy_power_on(phy);
-       if (err) {
-               dev_err(hba->dev, "%s: failed enabling regs, err = %d\n",
-                       __func__, err);
-               goto out;
-       }
+       if (ufs_qcom_is_link_off(hba)) {
+               err = phy_power_on(phy);
+               if (err) {
+                       dev_err(hba->dev, "%s: failed PHY power on: %d\n",
+                               __func__, err);
+                       return err;
+               }
 
-       err = ufs_qcom_enable_lane_clks(host);
-       if (err)
-               goto out;
+               err = ufs_qcom_enable_lane_clks(host);
+               if (err)
+                       return err;
 
-       hba->is_sys_suspended = false;
+       } else if (!ufs_qcom_is_link_active(hba)) {
+               err = ufs_qcom_enable_lane_clks(host);
+               if (err)
+                       return err;
+       }
 
-out:
-       return err;
+       hba->is_sys_suspended = false;
+       return 0;
 }
 
 struct ufs_qcom_dev_params {
                return 0;
 
        if (on && (status == POST_CHANGE)) {
-               phy_power_on(host->generic_phy);
-
                /* enable the device ref clock for HS mode*/
                if (ufshcd_is_hs_mode(&hba->pwr_info))
                        ufs_qcom_dev_ref_clk_ctrl(host, true);
                if (!ufs_qcom_is_link_active(hba)) {
                        /* disable device ref_clk */
                        ufs_qcom_dev_ref_clk_ctrl(host, false);
-
-                       /* powering off PHY during aggressive clk gating */
-                       phy_power_off(host->generic_phy);
                }
 
                vote = host->bus_vote.min_bw_vote;