From fe03a9f7bb89e920e60fd1bb074adab2eed2bf48 Mon Sep 17 00:00:00 2001 From: "Hans J. Koch" Date: Thu, 17 Feb 2011 16:42:59 +0100 Subject: [PATCH] arm: tcc8k: Fix clock rate calculation The calculation of the best divider value for a requested clock rate always returned a value that was slightly too large. It was also not protected against possible divisions by zero. Request for very low, but non zero rates would cause the ACLK divisor field to overflow. Catch this situation by using the maximum value. The internal function aclk_set_rate() calculates the correct divider value, but doesn't write it back to the register. Add the write back. Signed-off-by: Hans J. Koch Signed-off-by: Oskar Schirmer Cc: bigeasy@linutronix.de Signed-off-by: Thomas Gleixner --- arch/arm/mach-tcc8k/clock.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-tcc8k/clock.c b/arch/arm/mach-tcc8k/clock.c index 3970a9cdce26..7ebcbff4652a 100644 --- a/arch/arm/mach-tcc8k/clock.c +++ b/arch/arm/mach-tcc8k/clock.c @@ -50,6 +50,8 @@ #define ACLKTCX (CKC_BASE + ACLKTCX_OFFS) #define ACLKTCZ (CKC_BASE + ACLKTCZ_OFFS) +#define ACLK_MAX_DIV (0xfff + 1) + /* Crystal frequencies */ static unsigned long xi_rate, xti_rate; @@ -258,14 +260,19 @@ static unsigned long aclk_best_div(struct clk *clk, unsigned long rate) { unsigned long div, src, freq, r1, r2; + if (!rate) + return ACLK_MAX_DIV; + src = __raw_readl(clk->aclkreg) >> ACLK_SEL_SHIFT; src &= CLK_SRC_MASK; freq = root_clk_get_rate(src); - div = freq / rate + 1; + div = freq / rate; + if (!div) + return 1; + if (div >= ACLK_MAX_DIV) + return ACLK_MAX_DIV; r1 = freq / div; r2 = freq / (div + 1); - if (r2 >= rate) - return div + 1; if ((rate - r2) < (r1 - rate)) return div + 1; @@ -287,7 +294,8 @@ static int aclk_set_rate(struct clk *clk, unsigned long rate) u32 reg; reg = __raw_readl(clk->aclkreg) & ~ACLK_DIV_MASK; - reg |= aclk_best_div(clk, rate); + reg |= aclk_best_div(clk, rate) - 1; + __raw_writel(reg, clk->aclkreg); return 0; } -- 2.39.5