[U-Boot] [PATCH 3/8 V2] EXYNOS: Add clock for SPI.
Simon Glass
sjg at google.com
Tue Oct 2 08:04:47 CEST 2012
Hi,
On Tue, Jul 31, 2012 at 4:00 AM, Rajeshwari Shinde
<rajeshwari.s at samsung.com> wrote:
> This patch adds api to calculate and set the clock for SPI channels
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> Signed-off-by: Rajeshwari Shinde <rajeshwari.s at samsung.com>
I believe this should also have a sign-off from
jamesmiller at 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
>
More information about the U-Boot
mailing list