On some platform (eg.qcs615), the current that phy consumes will exceed the maximum current the regulator can provide in LPM mode, leading to over current protection and system boot up stuck. Fix this issue by setting regulator load to an expected value getting from phy device tree node during init so that the regulator can scale up to HPM to allow a larger current load. This change will also set load to zero during deinit to let regulator scale down to LPM mode to reduce itself's power consumptionif PCIe suspend. Signed-off-by: Ziyue Zhang <quic_ziyuzhan@xxxxxxxxxxx> --- drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 35 ++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index c8e39c147ba4..782d51ab5cf1 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -39,6 +39,7 @@ #include "phy-qcom-qmp-pcie-qhp.h" #define PHY_INIT_COMPLETE_TIMEOUT 10000 +#define MAX_PROP_SIZE 32 /* set of registers with offsets different per-PHY */ enum qphy_reg_layout { @@ -2905,6 +2906,7 @@ struct qmp_pcie { struct reset_control_bulk_data *resets; struct reset_control *nocsr_reset; struct regulator_bulk_data *vregs; + u32 *max_current_load; struct phy *phy; int mode; @@ -4087,6 +4089,17 @@ static int qmp_pcie_init(struct phy *phy) const struct qmp_phy_cfg *cfg = qmp->cfg; int ret; + for (int i = 0; i < cfg->num_vregs; i++) { + if (qmp->max_current_load[i]) { + ret = regulator_set_load(qmp->vregs[i].consumer, qmp->max_current_load[i]); + if (ret) { + dev_err(&phy->dev, + "failed to set load at %s\n", qmp->vregs[i].supply); + return ret; + } + } + } + ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); if (ret) { dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret); @@ -4129,6 +4142,7 @@ static int qmp_pcie_init(struct phy *phy) static int qmp_pcie_exit(struct phy *phy) { + int ret; struct qmp_pcie *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -4137,7 +4151,16 @@ static int qmp_pcie_exit(struct phy *phy) clk_bulk_disable_unprepare(ARRAY_SIZE(qmp_pciephy_clk_l), qmp->clks); regulator_bulk_disable(cfg->num_vregs, qmp->vregs); - + for (int i = 0; i < cfg->num_vregs; i++) { + if (qmp->max_current_load[i]) { + ret = regulator_set_load(qmp->vregs[i].consumer, 0); + if (ret) { + dev_err(&phy->dev, + "failed to set load at %s\n", qmp->vregs[i].supply); + return ret; + } + } + } return 0; } @@ -4274,14 +4297,22 @@ static int qmp_pcie_vreg_init(struct qmp_pcie *qmp) const struct qmp_phy_cfg *cfg = qmp->cfg; struct device *dev = qmp->dev; int num = cfg->num_vregs; + char prop_name[MAX_PROP_SIZE]; int i; qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); if (!qmp->vregs) return -ENOMEM; - for (i = 0; i < num; i++) + qmp->max_current_load = devm_kcalloc(dev, num, sizeof(*qmp->max_current_load), GFP_KERNEL); + if (!qmp->max_current_load) + return -ENOMEM; + + for (i = 0; i < num; i++) { qmp->vregs[i].supply = cfg->vreg_list[i]; + snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", qmp->vregs[i].supply); + of_property_read_u32(qmp->dev->of_node, prop_name, &qmp->max_current_load[i]); + } return devm_regulator_bulk_get(dev, num, qmp->vregs); } -- 2.34.1