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