See my comments below
2010/6/7 Raffaele Recalcati <[email protected]>:
> From: Davide Bonfanti <[email protected]>
> Date: Thu, 3 Jun 2010 14:26:26 +0200
> Subject: [PATCH 10/12] DaVinci: dm365: Added clokout2 management
>
> Signed-off-by: Raffaele Recalcati <[email protected]>
> ---
> arch/arm/mach-davinci/clock.c | 62
> ++++++++++++++++++++++++++++
> arch/arm/mach-davinci/clock.h | 6 +++
> arch/arm/mach-davinci/dm365.c | 58 ++++++++++++++++++++++++-
> arch/arm/mach-davinci/include/mach/clock.h | 3 +
> 4 files changed, 126 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
> index 054c303..f561b73 100644
> --- a/arch/arm/mach-davinci/clock.c
> +++ b/arch/arm/mach-davinci/clock.c
> @@ -144,6 +144,68 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
> }
> EXPORT_SYMBOL(clk_set_rate);
>
> +
> +int clkout_set_rate(struct clk *clk, unsigned long rate)
> +{
> + unsigned long flags;
> + int ret = -EINVAL;
> + int i, err, min_err, i_min_err;
> + u32 regval;
> + struct pll_data *pll;
> +
> +
> + if (clk == NULL || IS_ERR(clk))
> + return ret;
> + pll = clk->parent->pll_data;
> + regval = __raw_readl(IO_ADDRESS(clk->sec_div_reg));
> +
> + if (clk->sec_div_reg)
> + {
> + i_min_err = min_err = INT_MAX;
> + for (i=clk->sec_div_reg_max; i>0; i--)
> + {
> + if (clk->set_rate)
> + {
> + ret = clk_set_rate(clk, rate * i) ;
> + err = clk_get_rate(clk) - rate * i;
> + if (abs(min_err) > abs(err))
> + {
> + min_err = err;
> + i_min_err = i;
> + }
> + }
> + }
> + i = i_min_err;
> + ret = clk->set_rate(clk, rate * i) ;
> +
> + regval &= ~(clk->sec_div_reg_max << clk->sec_div_reg_shift);
> + regval |= (i-1) << clk->sec_div_reg_shift;
> + __raw_writel(regval, IO_ADDRESS(clk->sec_div_reg));
> + regval = __raw_readl( IO_ADDRESS(clk->out_enable_reg));
> + regval |= 1 << clk->out_enable_bit;
> + __raw_writel(regval, IO_ADDRESS(clk->out_enable_reg));
> + rate *= i;
> + }
> + else
> + {
> + if (clk->set_rate)
> + ret = clk->set_rate(clk, rate);
> + }
> +
> + spin_lock_irqsave(&clockfw_lock, flags);
> + if (ret == 0) {
> + if (clk->recalc)
> + clk->rate = clk->recalc(clk);
You end up with the syclk9 rate, since clk->recalc is clk_syclk_recalc.
> + propagate_rate(clk);
> + regval &= ~(1 << clk->out_enable_bit);
> + __raw_writel(regval, IO_ADDRESS(clk->out_enable_reg));
> + }
> + spin_unlock_irqrestore(&clockfw_lock, flags);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL(clkout_set_rate);
> +
> int clk_set_parent(struct clk *clk, struct clk *parent)
> {
> unsigned long flags;
> diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
> index 01e3648..1ca14e7 100644
> --- a/arch/arm/mach-davinci/clock.h
> +++ b/arch/arm/mach-davinci/clock.h
> @@ -95,6 +95,12 @@ struct clk {
> struct list_head childnode; /* parent's child list node */
> struct pll_data *pll_data;
> u32 div_reg;
> + u32 sec_div_reg;
> + u32 sec_div_reg_max;
> + u32 sec_div_reg_shift;
> + u32 out_enable_reg;
> + u32 out_enable_bit;
> +
div reg is an offset with respect to pll base,
and sec_div_reg is not. is adding five u32 for all clock really a good
idea, when
only one clock actually uses them ?
> unsigned long (*recalc) (struct clk *);
> int (*set_rate) (struct clk *clk, unsigned long rate);
> int (*round_rate) (struct clk *clk, unsigned long rate);
> diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
> index e4ead0a..9968c37 100644
> --- a/arch/arm/mach-davinci/dm365.c
> +++ b/arch/arm/mach-davinci/dm365.c
> @@ -40,6 +40,21 @@
> #include "mux.h"
>
> #define DM365_REF_FREQ 24000000 /* 24 MHz on the DM365 EVM */
> +#define PINMUX0 0x00
> +#define PINMUX1 0x04
> +#define PINMUX2 0x08
> +#define PINMUX3 0x0c
> +#define PINMUX4 0x10
> +#define INTMUX 0x18
> +#define EVTMUX 0x1c
> +#define PERI_CLKCTL 0x48
> +#define CLOCKOUT2EN 2
> +#define CLOCKOUT1EN 1
> +#define CLOCKOUT0EN 0
> +
> +
> +int dm365_set_pll1_rate(struct clk *clk, unsigned long rate);
> +
>
> static struct pll_data pll1_data = {
> .num = 1,
> @@ -147,6 +162,20 @@ static struct clk pll1_sysclk9 = {
> .div_reg = PLLDIV9,
> };
>
> +static struct clk clkout2_clk = {
> + .name = "clkout2",
> + .parent = &pll1_clk,
> + .flags = CLK_PLL,
> + .div_reg = PLLDIV9,
> + .sec_div_reg = DAVINCI_SYSTEM_MODULE_BASE + PERI_CLKCTL,
> + .sec_div_reg_max = 0x0F,
> + .sec_div_reg_shift = 3,
> + .out_enable_reg = DAVINCI_SYSTEM_MODULE_BASE + PERI_CLKCTL,
> + .out_enable_bit = CLOCKOUT2EN,
> + .set_rate = dm365_set_pll1_rate,
> +};
> +
> +
> static struct clk pll2_clk = {
> .name = "pll2",
> .parent = &ref_clk,
> @@ -421,6 +450,7 @@ static struct clk_lookup dm365_clks[] = {
> CLK(NULL, "pll1_sysclk7", &pll1_sysclk7),
> CLK(NULL, "pll1_sysclk8", &pll1_sysclk8),
> CLK(NULL, "pll1_sysclk9", &pll1_sysclk9),
> + CLK(NULL, "clkout2", &clkout2_clk),
pll1_sysclk9 and clkout2 are the same clock, so pll1_sysclk9
shoud be removed, or clkout2 should have pll1_sysclk9 has parent.
I think clkout2 should be a child of pll1_syclk9.
> CLK(NULL, "pll2", &pll2_clk),
> CLK(NULL, "pll2_aux", &pll2_aux_clk),
> CLK(NULL, "clkout1", &clkout1_clk),
> @@ -467,9 +497,6 @@ static struct clk_lookup dm365_clks[] = {
>
> /*----------------------------------------------------------------------*/
>
> -#define INTMUX 0x18
> -#define EVTMUX 0x1c
> -
>
> static const struct mux_config dm365_pins[] = {
> #ifdef CONFIG_DAVINCI_MUX
> @@ -657,6 +684,31 @@ static struct resource dm365_spi0_resources[] = {
> },
> };
>
> +int dm365_set_pll1_rate(struct clk *clk, unsigned long rate)
> +{
> + unsigned int prediv, mult, postdiv;
> + u32 clk_freq_min, clk_freq_max, plldiv;
> +
> + prediv = ioread32(IO_ADDRESS(DAVINCI_PLL1_BASE + PREDIV)) & 0x1F;
> + mult = ioread32(IO_ADDRESS(DAVINCI_PLL1_BASE + PLLM)) & 0x3FF;
> + postdiv = ioread32(IO_ADDRESS(DAVINCI_PLL1_BASE + POSTDIV)) & 0x1F;
> +
> + clk_freq_max = DM365_REF_FREQ * 2 * mult / ( (prediv + 1) * (postdiv +
> 1) );
> + clk_freq_min = clk_freq_max / 0x20;
> +
> + if ( (rate < clk_freq_min) || (rate > clk_freq_max) )
> + return -EINVAL;
> +
> + plldiv = clk_freq_max / rate ;
> + if ( (clk_freq_max % rate) < (rate/2))
> + plldiv--;
> + iowrite32(plldiv & 0x1F, IO_ADDRESS(DAVINCI_PLL1_BASE + clk->div_reg));
> + iowrite32(plldiv | 0x8000, IO_ADDRESS(DAVINCI_PLL1_BASE +
> clk->div_reg));
> + clk->rate = rate;
> +
> + return 0;
> +}
This could be more generic, because this is true for all sysclk.
Moreover, this pll rate calculation is already done in
clk_pllclk_recalc in clock.c
You could use this data by accessing the parent clock.
sysclk clocks have the CLK_PLL flag set have and have a pll for
parent, and this parent has a
pll_data field from which you can infer the pll base and the pll rate :
struct pll_data *pll;
if(!clk->parent->pll_data)
return ???;
pll = clk->parent->pll_data;
clk_freq_max = clk->parent->rate;
clk_freq_min = ...
And at the end :
raw_writel(div_value, pll->base + clk->div_reg)
So in the end , I think the following step would lead to something
more consistent :
- make a set_rate functions for all syclk like clock.
- make clkout2 a child of syclk9
- provide a set_rate function for clkout2 where you use the secdiv etc register,
but without adding field to the clock struct, since this fields are
currently used in a single place.
_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source