diff options
Diffstat (limited to 'arch/arm/mach-omap2/dpll44xx.c')
-rw-r--r-- | arch/arm/mach-omap2/dpll44xx.c | 64 |
1 files changed, 55 insertions, 9 deletions
diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c index d3326c474fdc..d28b0f726715 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/arch/arm/mach-omap2/dpll44xx.c | |||
@@ -20,6 +20,15 @@ | |||
20 | #include "clock44xx.h" | 20 | #include "clock44xx.h" |
21 | #include "cm-regbits-44xx.h" | 21 | #include "cm-regbits-44xx.h" |
22 | 22 | ||
23 | /* | ||
24 | * Maximum DPLL input frequency (FINT) and output frequency (FOUT) that | ||
25 | * can supported when using the DPLL low-power mode. Frequencies are | ||
26 | * defined in OMAP4430/60 Public TRM section 3.6.3.3.2 "Enable Control, | ||
27 | * Status, and Low-Power Operation Mode". | ||
28 | */ | ||
29 | #define OMAP4_DPLL_LP_FINT_MAX 1000000 | ||
30 | #define OMAP4_DPLL_LP_FOUT_MAX 100000000 | ||
31 | |||
23 | /* Supported only on OMAP4 */ | 32 | /* Supported only on OMAP4 */ |
24 | int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk) | 33 | int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk) |
25 | { | 34 | { |
@@ -82,6 +91,31 @@ const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = { | |||
82 | }; | 91 | }; |
83 | 92 | ||
84 | /** | 93 | /** |
94 | * omap4_dpll_lpmode_recalc - compute DPLL low-power setting | ||
95 | * @dd: pointer to the dpll data structure | ||
96 | * | ||
97 | * Calculates if low-power mode can be enabled based upon the last | ||
98 | * multiplier and divider values calculated. If low-power mode can be | ||
99 | * enabled, then the bit to enable low-power mode is stored in the | ||
100 | * last_rounded_lpmode variable. This implementation is based upon the | ||
101 | * criteria for enabling low-power mode as described in the OMAP4430/60 | ||
102 | * Public TRM section 3.6.3.3.2 "Enable Control, Status, and Low-Power | ||
103 | * Operation Mode". | ||
104 | */ | ||
105 | static void omap4_dpll_lpmode_recalc(struct dpll_data *dd) | ||
106 | { | ||
107 | long fint, fout; | ||
108 | |||
109 | fint = __clk_get_rate(dd->clk_ref) / (dd->last_rounded_n + 1); | ||
110 | fout = fint * dd->last_rounded_m; | ||
111 | |||
112 | if ((fint < OMAP4_DPLL_LP_FINT_MAX) && (fout < OMAP4_DPLL_LP_FOUT_MAX)) | ||
113 | dd->last_rounded_lpmode = 1; | ||
114 | else | ||
115 | dd->last_rounded_lpmode = 0; | ||
116 | } | ||
117 | |||
118 | /** | ||
85 | * omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit | 119 | * omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit |
86 | * @clk: struct clk * of the DPLL to compute the rate for | 120 | * @clk: struct clk * of the DPLL to compute the rate for |
87 | * | 121 | * |
@@ -130,7 +164,6 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, | |||
130 | unsigned long *parent_rate) | 164 | unsigned long *parent_rate) |
131 | { | 165 | { |
132 | struct clk_hw_omap *clk = to_clk_hw_omap(hw); | 166 | struct clk_hw_omap *clk = to_clk_hw_omap(hw); |
133 | u32 v; | ||
134 | struct dpll_data *dd; | 167 | struct dpll_data *dd; |
135 | long r; | 168 | long r; |
136 | 169 | ||
@@ -139,18 +172,31 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, | |||
139 | 172 | ||
140 | dd = clk->dpll_data; | 173 | dd = clk->dpll_data; |
141 | 174 | ||
142 | /* regm4xen adds a multiplier of 4 to DPLL calculations */ | 175 | dd->last_rounded_m4xen = 0; |
143 | v = __raw_readl(dd->control_reg) & OMAP4430_DPLL_REGM4XEN_MASK; | ||
144 | |||
145 | if (v) | ||
146 | target_rate = target_rate / OMAP4430_REGM4XEN_MULT; | ||
147 | 176 | ||
177 | /* | ||
178 | * First try to compute the DPLL configuration for | ||
179 | * target rate without using the 4X multiplier. | ||
180 | */ | ||
148 | r = omap2_dpll_round_rate(hw, target_rate, NULL); | 181 | r = omap2_dpll_round_rate(hw, target_rate, NULL); |
182 | if (r != ~0) | ||
183 | goto out; | ||
184 | |||
185 | /* | ||
186 | * If we did not find a valid DPLL configuration, try again, but | ||
187 | * this time see if using the 4X multiplier can help. Enabling the | ||
188 | * 4X multiplier is equivalent to dividing the target rate by 4. | ||
189 | */ | ||
190 | r = omap2_dpll_round_rate(hw, target_rate / OMAP4430_REGM4XEN_MULT, | ||
191 | NULL); | ||
149 | if (r == ~0) | 192 | if (r == ~0) |
150 | return r; | 193 | return r; |
151 | 194 | ||
152 | if (v) | 195 | dd->last_rounded_rate *= OMAP4430_REGM4XEN_MULT; |
153 | clk->dpll_data->last_rounded_rate *= OMAP4430_REGM4XEN_MULT; | 196 | dd->last_rounded_m4xen = 1; |
197 | |||
198 | out: | ||
199 | omap4_dpll_lpmode_recalc(dd); | ||
154 | 200 | ||
155 | return clk->dpll_data->last_rounded_rate; | 201 | return dd->last_rounded_rate; |
156 | } | 202 | } |