aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/clk/ti/clock.h2
-rw-r--r--drivers/clk/ti/divider.c36
-rw-r--r--drivers/clk/ti/dpll.c6
-rw-r--r--drivers/clk/ti/dpll3xxx.c124
-rw-r--r--drivers/clk/ti/gate.c3
-rw-r--r--drivers/clk/ti/mux.c29
-rw-r--r--include/linux/clk/ti.h6
7 files changed, 206 insertions, 0 deletions
diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h
index 5a781067a0e7..9f312a219510 100644
--- a/drivers/clk/ti/clock.h
+++ b/drivers/clk/ti/clock.h
@@ -24,6 +24,7 @@ struct clk_omap_divider {
24 u8 flags; 24 u8 flags;
25 s8 latch; 25 s8 latch;
26 const struct clk_div_table *table; 26 const struct clk_div_table *table;
27 u32 context;
27}; 28};
28 29
29#define to_clk_omap_divider(_hw) container_of(_hw, struct clk_omap_divider, hw) 30#define to_clk_omap_divider(_hw) container_of(_hw, struct clk_omap_divider, hw)
@@ -36,6 +37,7 @@ struct clk_omap_mux {
36 u8 shift; 37 u8 shift;
37 s8 latch; 38 s8 latch;
38 u8 flags; 39 u8 flags;
40 u8 saved_parent;
39}; 41};
40 42
41#define to_clk_omap_mux(_hw) container_of(_hw, struct clk_omap_mux, hw) 43#define to_clk_omap_mux(_hw) container_of(_hw, struct clk_omap_mux, hw)
diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c
index ccfb4d9a152a..373f620f49cb 100644
--- a/drivers/clk/ti/divider.c
+++ b/drivers/clk/ti/divider.c
@@ -268,10 +268,46 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
268 return 0; 268 return 0;
269} 269}
270 270
271/**
272 * clk_divider_save_context - Save the divider value
273 * @hw: pointer struct clk_hw
274 *
275 * Save the divider value
276 */
277static 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 */
294static 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
271const struct clk_ops ti_clk_divider_ops = { 305const struct clk_ops ti_clk_divider_ops = {
272 .recalc_rate = ti_clk_divider_recalc_rate, 306 .recalc_rate = ti_clk_divider_recalc_rate,
273 .round_rate = ti_clk_divider_round_rate, 307 .round_rate = ti_clk_divider_round_rate,
274 .set_rate = ti_clk_divider_set_rate, 308 .set_rate = ti_clk_divider_set_rate,
309 .save_context = clk_divider_save_context,
310 .restore_context = clk_divider_restore_context,
275}; 311};
276 312
277static struct clk *_register_divider(struct device *dev, const char *name, 313static struct clk *_register_divider(struct device *dev, const char *name,
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c
index dc86d07d0921..25d86d5ebb36 100644
--- a/drivers/clk/ti/dpll.c
+++ b/drivers/clk/ti/dpll.c
@@ -39,6 +39,8 @@ static const struct clk_ops dpll_m4xen_ck_ops = {
39 .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, 39 .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
40 .determine_rate = &omap4_dpll_regm4xen_determine_rate, 40 .determine_rate = &omap4_dpll_regm4xen_determine_rate,
41 .get_parent = &omap2_init_dpll_parent, 41 .get_parent = &omap2_init_dpll_parent,
42 .save_context = &omap3_core_dpll_save_context,
43 .restore_context = &omap3_core_dpll_restore_context,
42}; 44};
43#else 45#else
44static const struct clk_ops dpll_m4xen_ck_ops = {}; 46static const struct clk_ops dpll_m4xen_ck_ops = {};
@@ -62,6 +64,8 @@ static const struct clk_ops dpll_ck_ops = {
62 .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, 64 .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
63 .determine_rate = &omap3_noncore_dpll_determine_rate, 65 .determine_rate = &omap3_noncore_dpll_determine_rate,
64 .get_parent = &omap2_init_dpll_parent, 66 .get_parent = &omap2_init_dpll_parent,
67 .save_context = &omap3_noncore_dpll_save_context,
68 .restore_context = &omap3_noncore_dpll_restore_context,
65}; 69};
66 70
67static const struct clk_ops dpll_no_gate_ck_ops = { 71static const struct clk_ops dpll_no_gate_ck_ops = {
@@ -72,6 +76,8 @@ static const struct clk_ops dpll_no_gate_ck_ops = {
72 .set_parent = &omap3_noncore_dpll_set_parent, 76 .set_parent = &omap3_noncore_dpll_set_parent,
73 .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, 77 .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
74 .determine_rate = &omap3_noncore_dpll_determine_rate, 78 .determine_rate = &omap3_noncore_dpll_determine_rate,
79 .save_context = &omap3_noncore_dpll_save_context,
80 .restore_context = &omap3_noncore_dpll_restore_context
75}; 81};
76#else 82#else
77static const struct clk_ops dpll_core_ck_ops = {}; 83static const struct clk_ops dpll_core_ck_ops = {};
diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c
index 4534de2ef455..44b6b6403753 100644
--- a/drivers/clk/ti/dpll3xxx.c
+++ b/drivers/clk/ti/dpll3xxx.c
@@ -782,6 +782,130 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
782 return rate; 782 return rate;
783} 783}
784 784
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 */
792int 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 */
821void 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 */
853int 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