diff options
| -rw-r--r-- | drivers/clk/ti/clock.h | 2 | ||||
| -rw-r--r-- | drivers/clk/ti/divider.c | 36 | ||||
| -rw-r--r-- | drivers/clk/ti/dpll.c | 6 | ||||
| -rw-r--r-- | drivers/clk/ti/dpll3xxx.c | 124 | ||||
| -rw-r--r-- | drivers/clk/ti/gate.c | 3 | ||||
| -rw-r--r-- | drivers/clk/ti/mux.c | 29 | ||||
| -rw-r--r-- | include/linux/clk/ti.h | 6 |
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 | */ | ||
| 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(÷r->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(÷r->reg); | ||
| 300 | val &= ~(div_mask(divider) << divider->shift); | ||
| 301 | val |= divider->context << divider->shift; | ||
| 302 | ti_clk_ll_ops->clk_writel(val, ÷r->reg); | ||
| 303 | } | ||
| 304 | |||
| 271 | const struct clk_ops ti_clk_divider_ops = { | 305 | const 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 | ||
| 277 | static struct clk *_register_divider(struct device *dev, const char *name, | 313 | static 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 |
| 44 | static const struct clk_ops dpll_m4xen_ck_ops = {}; | 46 | static 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 | ||
| 67 | static const struct clk_ops dpll_no_gate_ck_ops = { | 71 | static 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 |
| 77 | static const struct clk_ops dpll_core_ck_ops = {}; | 83 | static 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 | */ | ||
| 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 | |||
