OSDN Git Service

clk: msm: Add support for reset controller for GDSC
authorTaniya Das <tdas@codeaurora.org>
Fri, 29 Jul 2016 07:15:45 +0000 (12:45 +0530)
committerGerrit - the friendly Code Review server <code-review@localhost>
Mon, 8 Aug 2016 11:39:18 +0000 (04:39 -0700)
GDSC regulators in case of 'qcom,skip-logic-collapse', would require block
assert/deassert of the clocks. Add support for the same to use the reset
controller APIs.

Change-Id: I83651b3b3515e0923d7431cfe8b70e6059b51067
Signed-off-by: Taniya Das <tdas@codeaurora.org>
Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
drivers/clk/msm/gdsc.c

index 526c518..20e5c5b 100644 (file)
@@ -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 {
index 5ea2a9c..cdaba72 100644 (file)
@@ -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);