aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRuss Dill <Russ.Dill@ti.com>2018-09-04 02:49:35 -0400
committerTero Kristo <t-kristo@ti.com>2018-10-03 08:29:04 -0400
commit8b95d1ce3300c411728954473316bd04d0ba9883 (patch)
tree1d7260045ce7f4563f479d7b3bd1f5680b6a992f
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>
-rw-r--r--drivers/clk/clk.c74
-rw-r--r--include/linux/clk-provider.h7
-rw-r--r--include/linux/clk.h25
3 files changed, 106 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)
923 return ret; 923 return ret;
924} 924}
925 925
926static int _clk_save_context(struct clk_core *clk)
927{
928 struct clk_core *child;
929 int ret = 0;
930
931 hlist_for_each_entry(child, &clk->children, child_node) {
932 ret = _clk_save_context(child);
933 if (ret < 0)
934 return ret;
935 }
936
937 if (clk->ops && clk->ops->save_context)
938 ret = clk->ops->save_context(clk->hw);
939
940 return ret;
941}
942
943static void _clk_restore_context(struct clk_core *clk)
944{
945 struct clk_core *child;
946
947 if (clk->ops && clk->ops->restore_context)
948 clk->ops->restore_context(clk->hw);
949
950 hlist_for_each_entry(child, &clk->children, child_node)
951 _clk_restore_context(child);
952}
953
954/**
955 * clk_save_context - save clock context for poweroff
956 *
957 * Saves the context of the clock register for powerstates in which the
958 * contents of the registers will be lost. Occurs deep within the suspend
959 * code. Returns 0 on success.
960 */
961int clk_save_context(void)
962{
963 struct clk_core *clk;
964 int ret;
965
966 hlist_for_each_entry(clk, &clk_root_list, child_node) {
967 ret = _clk_save_context(clk);
968 if (ret < 0)
969 return ret;
970 }
971
972 hlist_for_each_entry(clk, &clk_orphan_list, child_node) {
973 ret = _clk_save_context(clk);
974 if (ret < 0)
975 return ret;
976 }
977
978 return 0;
979}
980EXPORT_SYMBOL_GPL(clk_save_context);
981
982/**
983 * clk_restore_context - restore clock context after poweroff
984 *
985 * Restore the saved clock context upon resume.
986 *
987 */
988void clk_restore_context(void)
989{
990 struct clk_core *clk;
991
992 hlist_for_each_entry(clk, &clk_root_list, child_node)
993 _clk_restore_context(clk);
994
995 hlist_for_each_entry(clk, &clk_orphan_list, child_node)
996 _clk_restore_context(clk);
997}
998EXPORT_SYMBOL_GPL(clk_restore_context);
999
926/** 1000/**
927 * clk_enable - ungate a clock 1001 * clk_enable - ungate a clock
928 * @clk: the clk being ungated 1002 * @clk: the clk being ungated
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 08b1aa70a38d..df7379da6269 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -119,6 +119,11 @@ struct clk_duty {
119 * Called with enable_lock held. This function must not 119 * Called with enable_lock held. This function must not
120 * sleep. 120 * sleep.
121 * 121 *
122 * @save_context: Save the context of the clock in prepration for poweroff.
123 *
124 * @restore_context: Restore the context of the clock after a restoration
125 * of power.
126 *
122 * @recalc_rate Recalculate the rate of this clock, by querying hardware. The 127 * @recalc_rate Recalculate the rate of this clock, by querying hardware. The
123 * parent rate is an input parameter. It is up to the caller to 128 * parent rate is an input parameter. It is up to the caller to
124 * ensure that the prepare_mutex is held across this call. 129 * ensure that the prepare_mutex is held across this call.
@@ -223,6 +228,8 @@ struct clk_ops {
223 void (*disable)(struct clk_hw *hw); 228 void (*disable)(struct clk_hw *hw);
224 int (*is_enabled)(struct clk_hw *hw); 229 int (*is_enabled)(struct clk_hw *hw);
225 void (*disable_unused)(struct clk_hw *hw); 230 void (*disable_unused)(struct clk_hw *hw);
231 int (*save_context)(struct clk_hw *hw);
232 void (*restore_context)(struct clk_hw *hw);
226 unsigned long (*recalc_rate)(struct clk_hw *hw, 233 unsigned long (*recalc_rate)(struct clk_hw *hw,
227 unsigned long parent_rate); 234 unsigned long parent_rate);
228 long (*round_rate)(struct clk_hw *hw, unsigned long rate, 235 long (*round_rate)(struct clk_hw *hw, unsigned long rate,
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 4f750c481b82..7da754d79f9d 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -629,6 +629,23 @@ struct clk *clk_get_parent(struct clk *clk);
629 */ 629 */
630struct clk *clk_get_sys(const char *dev_id, const char *con_id); 630struct clk *clk_get_sys(const char *dev_id, const char *con_id);
631 631
632/**
633 * clk_save_context - save clock context for poweroff
634 *
635 * Saves the context of the clock register for powerstates in which the
636 * contents of the registers will be lost. Occurs deep within the suspend
637 * code so locking is not necessary.
638 */
639int clk_save_context(void);
640
641/**
642 * clk_restore_context - restore clock context after poweroff
643 *
644 * This occurs with all clocks enabled. Occurs deep within the resume code
645 * so locking is not necessary.
646 */
647void clk_restore_context(void);
648
632#else /* !CONFIG_HAVE_CLK */ 649#else /* !CONFIG_HAVE_CLK */
633 650
634static inline struct clk *clk_get(struct device *dev, const char *id) 651static inline struct clk *clk_get(struct device *dev, const char *id)
@@ -728,6 +745,14 @@ static inline struct clk *clk_get_sys(const char *dev_id, const char *con_id)
728{ 745{
729 return NULL; 746 return NULL;
730} 747}
748
749static inline int clk_save_context(void)
750{
751 return 0;
752}
753
754static inline void clk_restore_context(void) {}
755
731#endif 756#endif
732 757
733/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */ 758/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */