Skip to content

Commit d6e7bbc

Browse files
Russ DillTero Kristo
authored andcommitted
clk: ti: Add functions to save/restore clk context
SoCs like AM43XX lose clock registers context during RTC-only suspend. Hence add functions to save/restore the clock registers 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 4353654 commit d6e7bbc

File tree

7 files changed

+206
-0
lines changed

7 files changed

+206
-0
lines changed

drivers/clk/ti/clock.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ struct clk_omap_divider {
2424
u8 flags;
2525
s8 latch;
2626
const struct clk_div_table *table;
27+
u32 context;
2728
};
2829

2930
#define to_clk_omap_divider(_hw) container_of(_hw, struct clk_omap_divider, hw)
@@ -36,6 +37,7 @@ struct clk_omap_mux {
3637
u8 shift;
3738
s8 latch;
3839
u8 flags;
40+
u8 saved_parent;
3941
};
4042

4143
#define to_clk_omap_mux(_hw) container_of(_hw, struct clk_omap_mux, hw)

drivers/clk/ti/divider.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,46 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
268268
return 0;
269269
}
270270

271+
/**
272+
* clk_divider_save_context - Save the divider value
273+
* @hw: pointer struct clk_hw
274+
*
275+
* Save the divider value
276+
*/
277+
static int clk_divider_save_context(struct clk_hw *hw)
278+
{
279+
struct clk_omap_divider *divider = to_clk_omap_divider(hw);
280+
u32 val;
281+
282+
val = ti_clk_ll_ops->clk_readl(&divider->reg) >> divider->shift;
283+
divider->context = val & div_mask(divider);
284+
285+
return 0;
286+
}
287+
288+
/**
289+
* clk_divider_restore_context - restore the saved the divider value
290+
* @hw: pointer struct clk_hw
291+
*
292+
* Restore the saved the divider value
293+
*/
294+
static void clk_divider_restore_context(struct clk_hw *hw)
295+
{
296+
struct clk_omap_divider *divider = to_clk_omap_divider(hw);
297+
u32 val;
298+
299+
val = ti_clk_ll_ops->clk_readl(&divider->reg);
300+
val &= ~(div_mask(divider) << divider->shift);
301+
val |= divider->context << divider->shift;
302+
ti_clk_ll_ops->clk_writel(val, &divider->reg);
303+
}
304+
271305
const struct clk_ops ti_clk_divider_ops = {
272306
.recalc_rate = ti_clk_divider_recalc_rate,
273307
.round_rate = ti_clk_divider_round_rate,
274308
.set_rate = ti_clk_divider_set_rate,
309+
.save_context = clk_divider_save_context,
310+
.restore_context = clk_divider_restore_context,
275311
};
276312

277313
static struct clk *_register_divider(struct device *dev, const char *name,

drivers/clk/ti/dpll.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ static const struct clk_ops dpll_m4xen_ck_ops = {
3939
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
4040
.determine_rate = &omap4_dpll_regm4xen_determine_rate,
4141
.get_parent = &omap2_init_dpll_parent,
42+
.save_context = &omap3_core_dpll_save_context,
43+
.restore_context = &omap3_core_dpll_restore_context,
4244
};
4345
#else
4446
static const struct clk_ops dpll_m4xen_ck_ops = {};
@@ -62,6 +64,8 @@ static const struct clk_ops dpll_ck_ops = {
6264
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
6365
.determine_rate = &omap3_noncore_dpll_determine_rate,
6466
.get_parent = &omap2_init_dpll_parent,
67+
.save_context = &omap3_noncore_dpll_save_context,
68+
.restore_context = &omap3_noncore_dpll_restore_context,
6569
};
6670

6771
static const struct clk_ops dpll_no_gate_ck_ops = {
@@ -72,6 +76,8 @@ static const struct clk_ops dpll_no_gate_ck_ops = {
7276
.set_parent = &omap3_noncore_dpll_set_parent,
7377
.set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
7478
.determine_rate = &omap3_noncore_dpll_determine_rate,
79+
.save_context = &omap3_noncore_dpll_save_context,
80+
.restore_context = &omap3_noncore_dpll_restore_context
7581
};
7682
#else
7783
static const struct clk_ops dpll_core_ck_ops = {};

drivers/clk/ti/dpll3xxx.c

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,130 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
782782
return rate;
783783
}
784784

785+
/**
786+
* omap3_core_dpll_save_context - Save the m and n values of the divider
787+
* @hw: pointer struct clk_hw
788+
*
789+
* Before the dpll registers are lost save the last rounded rate m and n
790+
* and the enable mask.
791+
*/
792+
int omap3_core_dpll_save_context(struct clk_hw *hw)
793+
{
794+
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
795+
struct dpll_data *dd;
796+
u32 v;
797+
798+
dd = clk->dpll_data;
799+
800+
v = ti_clk_ll_ops->clk_readl(&dd->control_reg);
801+
clk->context = (v & dd->enable_mask) >> __ffs(dd->enable_mask);
802+
803+
if (clk->context == DPLL_LOCKED) {
804+
v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg);
805+
dd->last_rounded_m = (v & dd->mult_mask) >>
806+
__ffs(dd->mult_mask);
807+
dd->last_rounded_n = ((v & dd->div1_mask) >>
808+
__ffs(dd->div1_mask)) + 1;
809+
}
810+
811+
return 0;
812+
}
813+
814+
/**
815+
* omap3_core_dpll_restore_context - restore the m and n values of the divider
816+
* @hw: pointer struct clk_hw
817+
*
818+
* Restore the last rounded rate m and n
819+
* and the enable mask.
820+
*/
821+
void omap3_core_dpll_restore_context(struct clk_hw *hw)
822+
{
823+
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
824+
const struct dpll_data *dd;
825+
u32 v;
826+
827+
dd = clk->dpll_data;
828+
829+
if (clk->context == DPLL_LOCKED) {
830+
_omap3_dpll_write_clken(clk, 0x4);
831+
_omap3_wait_dpll_status(clk, 0);
832+
833+
v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg);
834+
v &= ~(dd->mult_mask | dd->div1_mask);
835+
v |= dd->last_rounded_m << __ffs(dd->mult_mask);
836+
v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask);
837+
ti_clk_ll_ops->clk_writel(v, &dd->mult_div1_reg);
838+
839+
_omap3_dpll_write_clken(clk, DPLL_LOCKED);
840+
_omap3_wait_dpll_status(clk, 1);
841+
} else {
842+
_omap3_dpll_write_clken(clk, clk->context);
843+
}
844+
}
845+
846+
/**
847+
* omap3_non_core_dpll_save_context - Save the m and n values of the divider
848+
* @hw: pointer struct clk_hw
849+
*
850+
* Before the dpll registers are lost save the last rounded rate m and n
851+
* and the enable mask.
852+
*/
853+
int omap3_noncore_dpll_save_context(struct clk_hw *hw)
854+
{
855+
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
856+
struct dpll_data *dd;
857+
u32 v;
858+
859+
dd = clk->dpll_data;
860+
861+
v = ti_clk_ll_ops->clk_readl(&dd->control_reg);
862+
clk->context = (v & dd->enable_mask) >> __ffs(dd->enable_mask);
863+
864+
if (clk->context == DPLL_LOCKED) {
865+
v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg);
866+
dd->last_rounded_m = (v & dd->mult_mask) >>
867+
__ffs(dd->mult_mask);
868+
dd->last_rounded_n = ((v & dd->div1_mask) >>
869+
__ffs(dd->div1_mask)) + 1;
870+
}
871+
872+
return 0;
873+
}
874+
875+
/**
876+
* omap3_core_dpll_restore_context - restore the m and n values of the divider
877+
* @hw: pointer struct clk_hw
878+
*
879+
* Restore the last rounded rate m and n
880+
* and the enable mask.
881+
*/
882+
void omap3_noncore_dpll_restore_context(struct clk_hw *hw)
883+
{
884+
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
885+
const struct dpll_data *dd;
886+
u32 ctrl, mult_div1;
887+
888+
dd = clk->dpll_data;
889+
890+
ctrl = ti_clk_ll_ops->clk_readl(&dd->control_reg);
891+
mult_div1 = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg);
892+
893+
if (clk->context == ((ctrl & dd->enable_mask) >>
894+
__ffs(dd->enable_mask)) &&
895+
dd->last_rounded_m == ((mult_div1 & dd->mult_mask) >>
896+
__ffs(dd->mult_mask)) &&
897+
dd->last_rounded_n == ((mult_div1 & dd->div1_mask) >>
898+
__ffs(dd->div1_mask)) + 1) {
899+
/* nothing to be done */
900+
return;
901+
}
902+
903+
if (clk->context == DPLL_LOCKED)
904+
omap3_noncore_dpll_program(clk, 0);
905+
else
906+
_omap3_dpll_write_clken(clk, clk->context);
907+
}
908+
785909
/* OMAP3/4 non-CORE DPLL clkops */
786910
const struct clk_hw_omap_ops clkhwops_omap3_dpll = {
787911
.allow_idle = omap3_dpll_allow_idle,

drivers/clk/ti/gate.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,23 @@ static const struct clk_ops omap_gate_clkdm_clk_ops = {
3333
.init = &omap2_init_clk_clkdm,
3434
.enable = &omap2_clkops_enable_clkdm,
3535
.disable = &omap2_clkops_disable_clkdm,
36+
.restore_context = clk_gate_restore_context,
3637
};
3738

3839
const struct clk_ops omap_gate_clk_ops = {
3940
.init = &omap2_init_clk_clkdm,
4041
.enable = &omap2_dflt_clk_enable,
4142
.disable = &omap2_dflt_clk_disable,
4243
.is_enabled = &omap2_dflt_clk_is_enabled,
44+
.restore_context = clk_gate_restore_context,
4345
};
4446

4547
static const struct clk_ops omap_gate_clk_hsdiv_restore_ops = {
4648
.init = &omap2_init_clk_clkdm,
4749
.enable = &omap36xx_gate_clk_enable_with_hsdiv_restore,
4850
.disable = &omap2_dflt_clk_disable,
4951
.is_enabled = &omap2_dflt_clk_is_enabled,
52+
.restore_context = clk_gate_restore_context,
5053
};
5154

5255
/**

drivers/clk/ti/mux.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,39 @@ static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index)
9191
return 0;
9292
}
9393

94+
/**
95+
* clk_mux_save_context - Save the parent selcted in the mux
96+
* @hw: pointer struct clk_hw
97+
*
98+
* Save the parent mux value.
99+
*/
100+
static int clk_mux_save_context(struct clk_hw *hw)
101+
{
102+
struct clk_omap_mux *mux = to_clk_omap_mux(hw);
103+
104+
mux->saved_parent = ti_clk_mux_get_parent(hw);
105+
return 0;
106+
}
107+
108+
/**
109+
* clk_mux_restore_context - Restore the parent in the mux
110+
* @hw: pointer struct clk_hw
111+
*
112+
* Restore the saved parent mux value.
113+
*/
114+
static void clk_mux_restore_context(struct clk_hw *hw)
115+
{
116+
struct clk_omap_mux *mux = to_clk_omap_mux(hw);
117+
118+
ti_clk_mux_set_parent(hw, mux->saved_parent);
119+
}
120+
94121
const struct clk_ops ti_clk_mux_ops = {
95122
.get_parent = ti_clk_mux_get_parent,
96123
.set_parent = ti_clk_mux_set_parent,
97124
.determine_rate = __clk_mux_determine_rate,
125+
.save_context = clk_mux_save_context,
126+
.restore_context = clk_mux_restore_context,
98127
};
99128

100129
static struct clk *_register_mux(struct device *dev, const char *name,

include/linux/clk/ti.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ struct clk_hw_omap {
159159
const char *clkdm_name;
160160
struct clockdomain *clkdm;
161161
const struct clk_hw_omap_ops *ops;
162+
u32 context;
162163
};
163164

164165
/*
@@ -294,6 +295,11 @@ struct ti_clk_features {
294295

295296
void ti_clk_setup_features(struct ti_clk_features *features);
296297
const struct ti_clk_features *ti_clk_get_features(void);
298+
int omap3_noncore_dpll_save_context(struct clk_hw *hw);
299+
void omap3_noncore_dpll_restore_context(struct clk_hw *hw);
300+
301+
int omap3_core_dpll_save_context(struct clk_hw *hw);
302+
void omap3_core_dpll_restore_context(struct clk_hw *hw);
297303

298304
extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll;
299305

0 commit comments

Comments
 (0)