clk: qcom: gdsc: Handle GDSC regulator supplies
Certain GDSCs, such as the GPU_GX on MSM8996, requires that the upstream regulator supply is powered in order to be turned on. It's not guaranteed that the bootloader will leave these supplies on and the driver core will attempt to enable any GDSCs before allowing the individual drivers to probe defer on the PMIC regulator driver not yet being present. So the gdsc driver needs to be made aware of supplying regulators and probe defer on their absence, and it needs to enable and disable the regulator accordingly. Voltage adjustments of the supplying regulator are deferred to the client drivers themselves. Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> Link: https://lkml.kernel.org/r/20200417070044.1376212-2-bjorn.andersson@linaro.org Reviewed-by: Vinod Koul <vkoul@kernel.org> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
This commit is contained in:
parent
f47ab3c2f5
commit
37416e5549
|
@ -11,6 +11,7 @@
|
|||
#include <linux/ktime.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/slab.h>
|
||||
#include "gdsc.h"
|
||||
|
@ -112,6 +113,12 @@ static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
|
|||
int ret;
|
||||
u32 val = (status == GDSC_ON) ? 0 : SW_COLLAPSE_MASK;
|
||||
|
||||
if (status == GDSC_ON && sc->rsupply) {
|
||||
ret = regulator_enable(sc->rsupply);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(sc->regmap, sc->gdscr, SW_COLLAPSE_MASK, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -143,6 +150,13 @@ 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 && sc->rsupply) {
|
||||
ret = regulator_disable(sc->rsupply);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -371,6 +385,15 @@ int gdsc_register(struct gdsc_desc *desc,
|
|||
if (!data->domains)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (!scs[i] || !scs[i]->supply)
|
||||
continue;
|
||||
|
||||
scs[i]->rsupply = devm_regulator_get(dev, scs[i]->supply);
|
||||
if (IS_ERR(scs[i]->rsupply))
|
||||
return PTR_ERR(scs[i]->rsupply);
|
||||
}
|
||||
|
||||
data->num_domains = num;
|
||||
for (i = 0; i < num; i++) {
|
||||
if (!scs[i])
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/pm_domain.h>
|
||||
|
||||
struct regmap;
|
||||
struct regulator;
|
||||
struct reset_controller_dev;
|
||||
|
||||
/**
|
||||
|
@ -52,6 +53,9 @@ struct gdsc {
|
|||
struct reset_controller_dev *rcdev;
|
||||
unsigned int *resets;
|
||||
unsigned int reset_count;
|
||||
|
||||
const char *supply;
|
||||
struct regulator *rsupply;
|
||||
};
|
||||
|
||||
struct gdsc_desc {
|
||||
|
|
Loading…
Reference in New Issue