summaryrefslogtreecommitdiffstats
path: root/drivers/clk
diff options
context:
space:
mode:
authorStephen Boyd2018-05-02 08:58:47 +0200
committerStephen Boyd2018-05-08 20:22:55 +0200
commit88051f55de502811472fe25d4a710bc7e6e60fd1 (patch)
tree47421eb5538f2c491b1f9367fab448dd833480b6 /drivers/clk
parentclk: qcom: gdsc: Add support to poll CFG register to check GDSC state (diff)
downloadkernel-qcow2-linux-88051f55de502811472fe25d4a710bc7e6e60fd1.tar.gz
kernel-qcow2-linux-88051f55de502811472fe25d4a710bc7e6e60fd1.tar.xz
kernel-qcow2-linux-88051f55de502811472fe25d4a710bc7e6e60fd1.zip
clk: qcom: Simplify gdsc status checking logic
The code is complicated because we want to check if the GDSC is enabled or disabled based on different bits in different registers while the GDSC hardware is slightly different across chips. Furthermore, we poll the status of the enable or disable state by checking if the gdsc is enabled or not, and then comparing that to if the gdsc is being enabled or disabled. Let's push all that into one function, so we can ask if the status matches what we want, either on or off. Then the call site can just ask that question, and the logic to check that state can simply return yes or no, and not 1 or 0 or 0 or 1 depending on if we're enabling or disabling respectively. Tested-by: Taniya Das <tdas@codeaurora.org> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/qcom/gdsc.c56
1 files changed, 37 insertions, 19 deletions
diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index 2a6b0ff7d451..4696e241db89 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -50,7 +50,13 @@
#define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd)
-static int gdsc_is_enabled(struct gdsc *sc, bool en)
+enum gdsc_status {
+ GDSC_OFF,
+ GDSC_ON
+};
+
+/* Returns 1 if GDSC status is status, 0 if not, and < 0 on error */
+static int gdsc_check_status(struct gdsc *sc, enum gdsc_status status)
{
unsigned int reg;
u32 val;
@@ -58,21 +64,32 @@ static int gdsc_is_enabled(struct gdsc *sc, bool en)
if (sc->flags & POLL_CFG_GDSCR)
reg = sc->gdscr + CFG_GDSCR_OFFSET;
+ else if (sc->gds_hw_ctrl)
+ reg = sc->gds_hw_ctrl;
else
- reg = sc->gds_hw_ctrl ? sc->gds_hw_ctrl : sc->gdscr;
+ reg = sc->gdscr;
ret = regmap_read(sc->regmap, reg, &val);
if (ret)
return ret;
if (sc->flags & POLL_CFG_GDSCR) {
- if (en)
+ switch (status) {
+ case GDSC_ON:
return !!(val & GDSC_POWER_UP_COMPLETE);
- else
- return !(val & GDSC_POWER_DOWN_COMPLETE);
+ case GDSC_OFF:
+ return !!(val & GDSC_POWER_DOWN_COMPLETE);
+ }
+ }
+
+ switch (status) {
+ case GDSC_ON:
+ return !!(val & PWR_ON_MASK);
+ case GDSC_OFF:
+ return !(val & PWR_ON_MASK);
}
- return !!(val & PWR_ON_MASK);
+ return -EINVAL;
}
static int gdsc_hwctrl(struct gdsc *sc, bool en)
@@ -82,33 +99,33 @@ static int gdsc_hwctrl(struct gdsc *sc, bool en)
return regmap_update_bits(sc->regmap, sc->gdscr, HW_CONTROL_MASK, val);
}
-static int gdsc_poll_status(struct gdsc *sc, bool en)
+static int gdsc_poll_status(struct gdsc *sc, enum gdsc_status status)
{
ktime_t start;
start = ktime_get();
do {
- if (gdsc_is_enabled(sc, en) == en)
+ if (gdsc_check_status(sc, status))
return 0;
} while (ktime_us_delta(ktime_get(), start) < TIMEOUT_US);
- if (gdsc_is_enabled(sc, en) == en)
+ if (gdsc_check_status(sc, status))
return 0;
return -ETIMEDOUT;
}
-static int gdsc_toggle_logic(struct gdsc *sc, bool en)
+static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status)
{
int ret;
- u32 val = en ? 0 : SW_COLLAPSE_MASK;
+ u32 val = (status == GDSC_ON) ? 0 : SW_COLLAPSE_MASK;
ret = regmap_update_bits(sc->regmap, sc->gdscr, SW_COLLAPSE_MASK, val);
if (ret)
return ret;
/* If disabling votable gdscs, don't poll on status */
- if ((sc->flags & VOTABLE) && !en) {
+ if ((sc->flags & VOTABLE) && status == GDSC_OFF) {
/*
* Add a short delay here to ensure that an enable
* right after it was disabled does not put it in an
@@ -118,7 +135,7 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
return 0;
}
- if (sc->gds_hw_ctrl)
+ if (sc->gds_hw_ctrl) {
/*
* The gds hw controller asserts/de-asserts the status bit soon
* after it receives a power on/off request from a master.
@@ -130,8 +147,9 @@ static int gdsc_toggle_logic(struct gdsc *sc, bool en)
* and polling the status bit.
*/
udelay(1);
+ }
- return gdsc_poll_status(sc, en);
+ return gdsc_poll_status(sc, status);
}
static inline int gdsc_deassert_reset(struct gdsc *sc)
@@ -210,7 +228,7 @@ static int gdsc_enable(struct generic_pm_domain *domain)
gdsc_deassert_clamp_io(sc);
}
- ret = gdsc_toggle_logic(sc, true);
+ ret = gdsc_toggle_logic(sc, GDSC_ON);
if (ret)
return ret;
@@ -266,7 +284,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
*/
udelay(1);
- ret = gdsc_poll_status(sc, true);
+ ret = gdsc_poll_status(sc, GDSC_ON);
if (ret)
return ret;
}
@@ -274,7 +292,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
if (sc->pwrsts & PWRSTS_OFF)
gdsc_clear_mem_on(sc);
- ret = gdsc_toggle_logic(sc, false);
+ ret = gdsc_toggle_logic(sc, GDSC_OFF);
if (ret)
return ret;
@@ -303,12 +321,12 @@ static int gdsc_init(struct gdsc *sc)
/* Force gdsc ON if only ON state is supported */
if (sc->pwrsts == PWRSTS_ON) {
- ret = gdsc_toggle_logic(sc, true);
+ ret = gdsc_toggle_logic(sc, GDSC_ON);
if (ret)
return ret;
}
- on = gdsc_is_enabled(sc, true);
+ on = gdsc_check_status(sc, GDSC_ON);
if (on < 0)
return on;