summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/regulator/gdsc-regulator.txt6
-rw-r--r--drivers/clk/msm/gdsc.c46
2 files changed, 46 insertions, 6 deletions
diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
index 526c51836402..20e5c5be37ce 100644
--- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
@@ -50,6 +50,12 @@ Optional properties:
to enable.
- qcom,reset-aon-logic: If present, the GPU DEMET cells need to be reset while
enabling the GX GDSC.
+ - resets: reset specifier pair consisting of phandle for the reset controller
+ and reset lines used by this controller. These can be
+ supplied only if we support qcom,skip-logic-collapse.
+ - reset-names: reset signal name strings sorted in the same order as the resets
+ property. These can be supplied only if we support
+ qcom,skip-logic-collapse.
Example:
gdsc_oxili_gx: qcom,gdsc@fd8c4024 {
diff --git a/drivers/clk/msm/gdsc.c b/drivers/clk/msm/gdsc.c
index 5ea2a9ccd1bb..cdaba72532d4 100644
--- a/drivers/clk/msm/gdsc.c
+++ b/drivers/clk/msm/gdsc.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/reset.h>
#include <linux/regulator/of_regulator.h>
#include <linux/slab.h>
#include <linux/clk.h>
@@ -48,7 +49,9 @@ struct gdsc {
struct regulator_desc rdesc;
void __iomem *gdscr;
struct clk **clocks;
+ struct reset_control **reset_clocks;
int clock_count;
+ int reset_count;
bool toggle_mem;
bool toggle_periph;
bool toggle_logic;
@@ -247,9 +250,8 @@ static int gdsc_enable(struct regulator_dev *rdev)
}
}
} else {
- for (i = 0; i < sc->clock_count; i++)
- if (likely(i != sc->root_clk_idx))
- clk_reset(sc->clocks[i], CLK_RESET_DEASSERT);
+ for (i = 0; i < sc->reset_count; i++)
+ reset_control_deassert(sc->reset_clocks[i]);
sc->resets_asserted = false;
}
@@ -342,9 +344,8 @@ static int gdsc_disable(struct regulator_dev *rdev)
wmb();
}
} else {
- for (i = sc->clock_count-1; i >= 0; i--)
- if (likely(i != sc->root_clk_idx))
- clk_reset(sc->clocks[i], CLK_RESET_ASSERT);
+ for (i = sc->reset_count-1; i >= 0; i--)
+ reset_control_assert(sc->reset_clocks[i]);
sc->resets_asserted = true;
}
@@ -605,6 +606,39 @@ static int gdsc_probe(struct platform_device *pdev)
}
if (!sc->toggle_logic) {
+ sc->reset_count = of_property_count_strings(pdev->dev.of_node,
+ "reset-names");
+ if (sc->reset_count == -EINVAL) {
+ sc->reset_count = 0;
+ } else if (IS_ERR_VALUE(sc->reset_count)) {
+ dev_err(&pdev->dev, "Failed to get reset reset names\n");
+ return -EINVAL;
+ }
+
+ sc->reset_clocks = devm_kzalloc(&pdev->dev,
+ sizeof(struct reset_control *) *
+ sc->reset_count,
+ GFP_KERNEL);
+ if (!sc->reset_clocks)
+ return -ENOMEM;
+
+ for (i = 0; i < sc->reset_count; i++) {
+ const char *reset_name;
+
+ of_property_read_string_index(pdev->dev.of_node,
+ "reset-names", i, &reset_name);
+ sc->reset_clocks[i] = devm_reset_control_get(&pdev->dev,
+ reset_name);
+ if (IS_ERR(sc->reset_clocks[i])) {
+ int rc = PTR_ERR(sc->reset_clocks[i]);
+
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get %s\n",
+ reset_name);
+ return rc;
+ }
+ }
+
regval &= ~SW_COLLAPSE_MASK;
writel_relaxed(regval, sc->gdscr);