diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index 95aa07120245..ee5f86ca50cb 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -147,6 +148,12 @@ static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status, return ret; } + if (status == GDSC_ON) { + ret = icc_set_bw(sc->icc_path, 1, 1); + if (ret) + goto err_disable_supply; + } + ret = gdsc_update_collapse_bit(sc, status == GDSC_OFF); /* If disabling votable gdscs, don't poll on status */ @@ -177,6 +184,12 @@ static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status, ret = gdsc_poll_status(sc, status); WARN(ret, "%s status stuck at 'o%s'", sc->pd.name, status ? "ff" : "n"); + if (!ret && status == GDSC_OFF) { + ret = icc_set_bw(sc->icc_path, 0, 0); + if (ret) + return ret; + } + if (!ret && status == GDSC_OFF && sc->rsupply) { ret = regulator_disable(sc->rsupply); if (ret < 0) @@ -184,6 +197,12 @@ static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status, } return ret; + +err_disable_supply: + if (status == GDSC_ON && sc->rsupply) + regulator_disable(sc->rsupply); + + return ret; } static inline int gdsc_deassert_reset(struct gdsc *sc) @@ -584,6 +603,20 @@ int gdsc_register(struct gdsc_desc *desc, if (!data->domains) return -ENOMEM; + for (i = 0; i < num; i++) { + if (!scs[i] || !scs[i]->needs_icc) + continue; + + scs[i]->icc_path = devm_of_icc_get_by_index(dev, scs[i]->icc_path_index); + if (IS_ERR(scs[i]->icc_path)) { + ret = PTR_ERR(scs[i]->icc_path); + if (ret != -ENODEV) + return ret; + + scs[i]->icc_path = NULL; + } + } + for (i = 0; i < num; i++) { if (!scs[i] || !scs[i]->supply) continue; diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h index dd843e86c05b..92ff6bcce7b1 100644 --- a/drivers/clk/qcom/gdsc.h +++ b/drivers/clk/qcom/gdsc.h @@ -9,6 +9,7 @@ #include #include +struct icc_path; struct regmap; struct regulator; struct reset_controller_dev; @@ -74,6 +75,10 @@ struct gdsc { const char *supply; struct regulator *rsupply; + + bool needs_icc; + unsigned int icc_path_index; + struct icc_path *icc_path; }; struct gdsc_desc {