
Hi,
On Tue, Jul 31, 2012 at 4:00 AM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch adds api to calculate and set the clock for SPI channels
Signed-off-by: Simon Glass sjg@chromium.org Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
I believe this should also have a sign-off from jamesmiller@chromium.org, since he wrote much of the code.
Regards, Simon
Changes in V2: - None arch/arm/cpu/armv7/exynos/clock.c | 122 ++++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-exynos/clk.h | 4 +- 2 files changed, 125 insertions(+), 1 deletions(-)
diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index de3db8e..ea5c305 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -628,6 +628,122 @@ static unsigned long exynos5_get_i2c_clk(void) return aclk_66; }
+/**
- Linearly searches for the most accurate main and fine stage clock scalars
- (divisors) for a specified target frequency and scalar bit sizes by checking
- all multiples of main_scalar_bits values. Will always return scalars up to or
- slower than target.
- @param main_scalar_bits Number of main scalar bits, must be > 0 and < 32
- @param fine_scalar_bits Number of fine scalar bits, must be > 0 and < 32
- @param input_freq Clock frequency to be scaled in Hz
- @param target_freq Desired clock frequency in Hz
- @param best_fine_scalar Pointer to store the fine stage divisor
- @return best_main_scalar Main scalar for desired frequency or -1 if none
- found
- */
+static int clock_calc_best_scalar(unsigned int main_scaler_bits,
unsigned int fine_scalar_bits, unsigned int input_rate,
unsigned int target_rate, unsigned int *best_fine_scalar)
+{
int i;
int best_main_scalar = -1;
unsigned int best_error = target_rate;
const unsigned int cap = (1 << fine_scalar_bits) - 1;
const unsigned int loops = 1 << main_scaler_bits;
debug("Input Rate is %u, Target is %u, Cap is %u\n", input_rate,
target_rate, cap);
assert(best_fine_scalar != NULL);
assert(main_scaler_bits <= fine_scalar_bits);
*best_fine_scalar = 1;
if (input_rate == 0 || target_rate == 0)
return -1;
if (target_rate >= input_rate)
return 1;
for (i = 1; i <= loops; i++) {
const unsigned int effective_div = max(min(input_rate / i /
target_rate, cap), 1);
const unsigned int effective_rate = input_rate / i /
effective_div;
const int error = target_rate - effective_rate;
debug("%d|effdiv:%u, effrate:%u, error:%d\n", i, effective_div,
effective_rate, error);
if (error >= 0 && error <= best_error) {
best_error = error;
best_main_scalar = i;
*best_fine_scalar = effective_div;
}
}
return best_main_scalar;
+}
+static int exynos5_spi_set_clock_rate(enum periph_id periph_id,
unsigned int rate)
+{
struct exynos5_clock *clk =
(struct exynos5_clock *)samsung_get_base_clock();
int main;
unsigned int fine;
unsigned shift, pre_shift;
unsigned mask = 0xff;
u32 *reg;
main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine);
if (main < 0) {
debug("%s: Cannot set clock rate for periph %d",
__func__, periph_id);
return -1;
}
main = main - 1;
fine = fine - 1;
switch (periph_id) {
case PERIPH_ID_SPI0:
reg = &clk->div_peric1;
shift = 0;
pre_shift = 8;
break;
case PERIPH_ID_SPI1:
reg = &clk->div_peric1;
shift = 16;
pre_shift = 24;
break;
case PERIPH_ID_SPI2:
reg = &clk->div_peric2;
shift = 0;
pre_shift = 8;
break;
case PERIPH_ID_SPI3:
reg = &clk->sclk_div_isp;
shift = 0;
pre_shift = 4;
break;
case PERIPH_ID_SPI4:
reg = &clk->sclk_div_isp;
shift = 12;
pre_shift = 16;
break;
default:
debug("%s: Unsupported peripheral ID %d\n", __func__,
periph_id);
return -1;
}
clrsetbits_le32(reg, mask << shift, (main & mask) << shift);
clrsetbits_le32(reg, mask << pre_shift, (fine & mask) << pre_shift);
return 0;
+}
unsigned long get_pll_clk(int pllreg) { if (cpu_is_exynos5()) @@ -697,3 +813,9 @@ void set_mipi_clk(void) if (cpu_is_exynos4()) exynos4_set_mipi_clk(); }
+int spi_set_clock_rate(enum periph_id periph_id, unsigned int rate) +{
if (cpu_is_exynos5())
exynos5_spi_set_clock_rate(periph_id, rate);
+} diff --git a/arch/arm/include/asm/arch-exynos/clk.h b/arch/arm/include/asm/arch-exynos/clk.h index 5529025..4e51402 100644 --- a/arch/arm/include/asm/arch-exynos/clk.h +++ b/arch/arm/include/asm/arch-exynos/clk.h @@ -22,6 +22,8 @@ #ifndef __ASM_ARM_ARCH_CLK_H_ #define __ASM_ARM_ARCH_CLK_H_
+#include <asm/arch/pinmux.h>
#define APLL 0 #define MPLL 1 #define EPLL 2 @@ -38,5 +40,5 @@ void set_mmc_clk(int dev_index, unsigned int div); unsigned long get_lcd_clk(void); void set_lcd_clk(void); void set_mipi_clk(void);
+int spi_set_clock_rate(enum periph_id periph_id, unsigned int rate);
#endif
1.7.4.4