diff options
| -rw-r--r-- | Documentation/devicetree/bindings/regulator/gdsc-regulator.txt | 6 | ||||
| -rw-r--r-- | drivers/clk/msm/gdsc.c | 46 |
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); |
