Skip to content

Commit 8b95d1c

Browse files
Russ DillTero Kristo
authored andcommitted
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>
1 parent dffa905 commit 8b95d1c

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

drivers/clk/clk.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,80 @@ static int clk_core_enable_lock(struct clk_core *core)
923923
return ret;
924924
}
925925

926+
static 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+
943+
static 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+
*/
961+
int 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+
}
980+
EXPORT_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+
*/
988+
void 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+
}
998+
EXPORT_SYMBOL_GPL(clk_restore_context);
999+
9261000
/**
9271001
* clk_enable - ungate a clock
9281002
* @clk: the clk being ungated

include/linux/clk-provider.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ struct clk_duty {
119119
* Called with enable_lock held. This function must not
120120
* sleep.
121121
*
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+
*
122127
* @recalc_rate Recalculate the rate of this clock, by querying hardware. The
123128
* parent rate is an input parameter. It is up to the caller to
124129
* ensure that the prepare_mutex is held across this call.
@@ -223,6 +228,8 @@ struct clk_ops {
223228
void (*disable)(struct clk_hw *hw);
224229
int (*is_enabled)(struct clk_hw *hw);
225230
void (*disable_unused)(struct clk_hw *hw);
231+
int (*save_context)(struct clk_hw *hw);
232+
void (*restore_context)(struct clk_hw *hw);
226233
unsigned long (*recalc_rate)(struct clk_hw *hw,
227234
unsigned long parent_rate);
228235
long (*round_rate)(struct clk_hw *hw, unsigned long rate,

include/linux/clk.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,23 @@ struct clk *clk_get_parent(struct clk *clk);
629629
*/
630630
struct clk *clk_get_sys(const char *dev_id, const char *con_id);
631631

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+
*/
639+
int 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+
*/
647+
void clk_restore_context(void);
648+
632649
#else /* !CONFIG_HAVE_CLK */
633650

634651
static 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)
728745
{
729746
return NULL;
730747
}
748+
749+
static inline int clk_save_context(void)
750+
{
751+
return 0;
752+
}
753+
754+
static inline void clk_restore_context(void) {}
755+
731756
#endif
732757

733758
/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */

0 commit comments

Comments
 (0)