diff options
Diffstat (limited to 'arch/arm/mach-tcc8k/clock.c')
-rw-r--r-- | arch/arm/mach-tcc8k/clock.c | 38 |
1 files changed, 26 insertions, 12 deletions
diff --git a/arch/arm/mach-tcc8k/clock.c b/arch/arm/mach-tcc8k/clock.c index 3970a9cdce26..e7cdae5c77a4 100644 --- a/arch/arm/mach-tcc8k/clock.c +++ b/arch/arm/mach-tcc8k/clock.c | |||
@@ -45,11 +45,12 @@ | |||
45 | #define ACLKGSB1 (CKC_BASE + ACLKGSB1_OFFS) | 45 | #define ACLKGSB1 (CKC_BASE + ACLKGSB1_OFFS) |
46 | #define ACLKGSB2 (CKC_BASE + ACLKGSB2_OFFS) | 46 | #define ACLKGSB2 (CKC_BASE + ACLKGSB2_OFFS) |
47 | #define ACLKGSB3 (CKC_BASE + ACLKGSB3_OFFS) | 47 | #define ACLKGSB3 (CKC_BASE + ACLKGSB3_OFFS) |
48 | #define ACLKUSBH (CKC_BASE + ACLKUSBH_OFFS) | ||
49 | #define ACLKTCT (CKC_BASE + ACLKTCT_OFFS) | 48 | #define ACLKTCT (CKC_BASE + ACLKTCT_OFFS) |
50 | #define ACLKTCX (CKC_BASE + ACLKTCX_OFFS) | 49 | #define ACLKTCX (CKC_BASE + ACLKTCX_OFFS) |
51 | #define ACLKTCZ (CKC_BASE + ACLKTCZ_OFFS) | 50 | #define ACLKTCZ (CKC_BASE + ACLKTCZ_OFFS) |
52 | 51 | ||
52 | #define ACLK_MAX_DIV (0xfff + 1) | ||
53 | |||
53 | /* Crystal frequencies */ | 54 | /* Crystal frequencies */ |
54 | static unsigned long xi_rate, xti_rate; | 55 | static unsigned long xi_rate, xti_rate; |
55 | 56 | ||
@@ -106,9 +107,9 @@ static int root_clk_enable(enum root_clks src) | |||
106 | return 0; | 107 | return 0; |
107 | } | 108 | } |
108 | 109 | ||
109 | static int root_clk_disable(enum root_clks root_src) | 110 | static int root_clk_disable(enum root_clks src) |
110 | { | 111 | { |
111 | switch (root_src) { | 112 | switch (src) { |
112 | case CLK_SRC_PLL0: return pll_enable(0, 0); | 113 | case CLK_SRC_PLL0: return pll_enable(0, 0); |
113 | case CLK_SRC_PLL1: return pll_enable(1, 0); | 114 | case CLK_SRC_PLL1: return pll_enable(1, 0); |
114 | case CLK_SRC_PLL2: return pll_enable(2, 0); | 115 | case CLK_SRC_PLL2: return pll_enable(2, 0); |
@@ -197,7 +198,7 @@ static unsigned long get_rate_pll_div(int pll) | |||
197 | addr = CKC_BASE + CLKDIVC1_OFFS; | 198 | addr = CKC_BASE + CLKDIVC1_OFFS; |
198 | reg = __raw_readl(addr); | 199 | reg = __raw_readl(addr); |
199 | if (reg & CLKDIVC1_P2E) | 200 | if (reg & CLKDIVC1_P2E) |
200 | div = __raw_readl(addr) & 0x3f; | 201 | div = reg & 0x3f; |
201 | break; | 202 | break; |
202 | } | 203 | } |
203 | return get_rate_pll(pll) / (div + 1); | 204 | return get_rate_pll(pll) / (div + 1); |
@@ -258,14 +259,19 @@ static unsigned long aclk_best_div(struct clk *clk, unsigned long rate) | |||
258 | { | 259 | { |
259 | unsigned long div, src, freq, r1, r2; | 260 | unsigned long div, src, freq, r1, r2; |
260 | 261 | ||
262 | if (!rate) | ||
263 | return ACLK_MAX_DIV; | ||
264 | |||
261 | src = __raw_readl(clk->aclkreg) >> ACLK_SEL_SHIFT; | 265 | src = __raw_readl(clk->aclkreg) >> ACLK_SEL_SHIFT; |
262 | src &= CLK_SRC_MASK; | 266 | src &= CLK_SRC_MASK; |
263 | freq = root_clk_get_rate(src); | 267 | freq = root_clk_get_rate(src); |
264 | div = freq / rate + 1; | 268 | div = freq / rate; |
269 | if (!div) | ||
270 | return 1; | ||
271 | if (div >= ACLK_MAX_DIV) | ||
272 | return ACLK_MAX_DIV; | ||
265 | r1 = freq / div; | 273 | r1 = freq / div; |
266 | r2 = freq / (div + 1); | 274 | r2 = freq / (div + 1); |
267 | if (r2 >= rate) | ||
268 | return div + 1; | ||
269 | if ((rate - r2) < (r1 - rate)) | 275 | if ((rate - r2) < (r1 - rate)) |
270 | return div + 1; | 276 | return div + 1; |
271 | 277 | ||
@@ -287,7 +293,8 @@ static int aclk_set_rate(struct clk *clk, unsigned long rate) | |||
287 | u32 reg; | 293 | u32 reg; |
288 | 294 | ||
289 | reg = __raw_readl(clk->aclkreg) & ~ACLK_DIV_MASK; | 295 | reg = __raw_readl(clk->aclkreg) & ~ACLK_DIV_MASK; |
290 | reg |= aclk_best_div(clk, rate); | 296 | reg |= aclk_best_div(clk, rate) - 1; |
297 | __raw_writel(reg, clk->aclkreg); | ||
291 | return 0; | 298 | return 0; |
292 | } | 299 | } |
293 | 300 | ||
@@ -296,15 +303,22 @@ static unsigned long get_rate_sys(struct clk *clk) | |||
296 | unsigned int src; | 303 | unsigned int src; |
297 | 304 | ||
298 | src = __raw_readl(CKC_BASE + CLKCTRL_OFFS) & CLK_SRC_MASK; | 305 | src = __raw_readl(CKC_BASE + CLKCTRL_OFFS) & CLK_SRC_MASK; |
299 | return root_clk_get_rate(src); | 306 | return root_clk_get_rate(src); |
300 | } | 307 | } |
301 | 308 | ||
302 | static unsigned long get_rate_bus(struct clk *clk) | 309 | static unsigned long get_rate_bus(struct clk *clk) |
303 | { | 310 | { |
304 | unsigned int div; | 311 | unsigned int reg, sdiv, bdiv, rate; |
305 | 312 | ||
306 | div = (__raw_readl(CKC_BASE + CLKCTRL_OFFS) >> 4) & 0xff; | 313 | reg = __raw_readl(CKC_BASE + CLKCTRL_OFFS); |
307 | return get_rate_sys(clk) / (div + 1); | 314 | rate = get_rate_sys(clk); |
315 | sdiv = (reg >> 20) & 3; | ||
316 | if (sdiv) | ||
317 | rate /= sdiv + 1; | ||
318 | bdiv = (reg >> 4) & 0xff; | ||
319 | if (bdiv) | ||
320 | rate /= bdiv + 1; | ||
321 | return rate; | ||
308 | } | 322 | } |
309 | 323 | ||
310 | static unsigned long get_rate_cpu(struct clk *clk) | 324 | static unsigned long get_rate_cpu(struct clk *clk) |