summaryrefslogtreecommitdiff
path: root/drivers/clk/clk.c
diff options
context:
space:
mode:
authorRuss Dill <Russ.Dill@ti.com>2018-09-04 12:19:35 +0530
committerTero Kristo <t-kristo@ti.com>2018-10-03 15:29:04 +0300
commit8b95d1ce3300c411728954473316bd04d0ba9883 (patch)
tree1d7260045ce7f4563f479d7b3bd1f5680b6a992f /drivers/clk/clk.c
parentdffa9051d54672a7d7f5951e074c4393672c03e9 (diff)
clk: Add functions to save/restore clock context en-masse
Deep enough power saving mode can result into losing context of the clock registers also, and they need to be restored once coming back from the power saving mode. Hence add functions to save/restore clock context. Signed-off-by: Keerthy <j-keerthy@ti.com> Signed-off-by: Russ Dill <Russ.Dill@ti.com> Acked-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Tero Kristo <t-kristo@ti.com>
Diffstat (limited to 'drivers/clk/clk.c')
-rw-r--r--drivers/clk/clk.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index d31055ae6ec6..8a0254a1c303 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -923,6 +923,80 @@ static int clk_core_enable_lock(struct clk_core *core)
return ret;
}
+static int _clk_save_context(struct clk_core *clk)
+{
+ struct clk_core *child;
+ int ret = 0;
+
+ hlist_for_each_entry(child, &clk->children, child_node) {
+ ret = _clk_save_context(child);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (clk->ops && clk->ops->save_context)
+ ret = clk->ops->save_context(clk->hw);
+
+ return ret;
+}
+
+static void _clk_restore_context(struct clk_core *clk)
+{
+ struct clk_core *child;
+
+ if (clk->ops && clk->ops->restore_context)
+ clk->ops->restore_context(clk->hw);
+
+ hlist_for_each_entry(child, &clk->children, child_node)
+ _clk_restore_context(child);
+}
+
+/**
+ * clk_save_context - save clock context for poweroff
+ *
+ * Saves the context of the clock register for powerstates in which the
+ * contents of the registers will be lost. Occurs deep within the suspend
+ * code. Returns 0 on success.
+ */
+int clk_save_context(void)
+{
+ struct clk_core *clk;
+ int ret;
+
+ hlist_for_each_entry(clk, &clk_root_list, child_node) {
+ ret = _clk_save_context(clk);
+ if (ret < 0)
+ return ret;
+ }
+
+ hlist_for_each_entry(clk, &clk_orphan_list, child_node) {
+ ret = _clk_save_context(clk);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(clk_save_context);
+
+/**
+ * clk_restore_context - restore clock context after poweroff
+ *
+ * Restore the saved clock context upon resume.
+ *
+ */
+void clk_restore_context(void)
+{
+ struct clk_core *clk;
+
+ hlist_for_each_entry(clk, &clk_root_list, child_node)
+ _clk_restore_context(clk);
+
+ hlist_for_each_entry(clk, &clk_orphan_list, child_node)
+ _clk_restore_context(clk);
+}
+EXPORT_SYMBOL_GPL(clk_restore_context);
+
/**
* clk_enable - ungate a clock
* @clk: the clk being ungated