diff options
Diffstat (limited to 'arch/arm/plat-spear')
-rw-r--r-- | arch/arm/plat-spear/clock.c | 59 | ||||
-rw-r--r-- | arch/arm/plat-spear/include/plat/clock.h | 68 |
2 files changed, 97 insertions, 30 deletions
diff --git a/arch/arm/plat-spear/clock.c b/arch/arm/plat-spear/clock.c index ee4f90e534d..f1cf832e4e3 100644 --- a/arch/arm/plat-spear/clock.c +++ b/arch/arm/plat-spear/clock.c @@ -17,7 +17,6 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/spinlock.h> -#include <mach/misc_regs.h> #include <plat/clock.h> static DEFINE_SPINLOCK(clocks_lock); @@ -187,6 +186,20 @@ int clk_set_parent(struct clk *clk, struct clk *parent) } EXPORT_SYMBOL(clk_set_parent); +/** + * clk_set_rate - set the clock rate for a clock source + * @clk: clock source + * @rate: desired clock rate in Hz + * + * Returns success (0) or negative errno. + */ +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + /* TODO */ + return -EINVAL; +} +EXPORT_SYMBOL(clk_set_rate); + /* registers clock in platform clock framework */ void clk_register(struct clk_lookup *cl) { @@ -212,6 +225,7 @@ void clk_register(struct clk_lookup *cl) list_add(&clk->sibling, &clk->pclk->children); } else { /* add clocks with > 1 parent to 1st parent's children list */ + clk->pclk = clk->pclk_sel->pclk_info[0].pclk; list_add(&clk->sibling, &clk->pclk_sel->pclk_info[0].pclk->children); } @@ -283,29 +297,31 @@ static void change_parent(struct clk *cclk, struct clk *pclk) * In Dithered mode * rate = (2 * M[15:0] * Fin)/(256 * N * 2^P) */ -void pll1_clk_recalc(struct clk *clk) +void pll_clk_recalc(struct clk *clk) { struct pll_clk_config *config = clk->private_data; unsigned int num = 2, den = 0, val, mode = 0; unsigned long flags; spin_lock_irqsave(&clocks_lock, flags); - mode = (readl(config->mode_reg) >> PLL_MODE_SHIFT) & - PLL_MODE_MASK; + mode = (readl(config->mode_reg) >> config->masks->mode_shift) & + config->masks->mode_mask; val = readl(config->cfg_reg); /* calculate denominator */ - den = (val >> PLL_DIV_P_SHIFT) & PLL_DIV_P_MASK; + den = (val >> config->masks->div_p_shift) & config->masks->div_p_mask; den = 1 << den; - den *= (val >> PLL_DIV_N_SHIFT) & PLL_DIV_N_MASK; + den *= (val >> config->masks->div_n_shift) & config->masks->div_n_mask; /* calculate numerator & denominator */ if (!mode) { /* Normal mode */ - num *= (val >> PLL_NORM_FDBK_M_SHIFT) & PLL_NORM_FDBK_M_MASK; + num *= (val >> config->masks->norm_fdbk_m_shift) & + config->masks->norm_fdbk_m_mask; } else { /* Dithered mode */ - num *= (val >> PLL_DITH_FDBK_M_SHIFT) & PLL_DITH_FDBK_M_MASK; + num *= (val >> config->masks->dith_fdbk_m_shift) & + config->masks->dith_fdbk_m_mask; den *= 256; } @@ -321,7 +337,8 @@ void bus_clk_recalc(struct clk *clk) unsigned long flags; spin_lock_irqsave(&clocks_lock, flags); - div = ((readl(config->reg) >> config->shift) & config->mask) + 1; + div = ((readl(config->reg) >> config->masks->shift) & + config->masks->mask) + 1; clk->rate = (unsigned long)clk->pclk->rate / div; spin_unlock_irqrestore(&clocks_lock, flags); } @@ -359,15 +376,18 @@ void aux_clk_recalc(struct clk *clk) if (pclk_info->scalable) { val = readl(config->synth_reg); - eqn = (val >> AUX_EQ_SEL_SHIFT) & AUX_EQ_SEL_MASK; - if (eqn == AUX_EQ1_SEL) + eqn = (val >> config->masks->eq_sel_shift) & + config->masks->eq_sel_mask; + if (eqn == config->masks->eq1_mask) den *= 2; /* calculate numerator */ - num = (val >> AUX_XSCALE_SHIFT) & AUX_XSCALE_MASK; + num = (val >> config->masks->xscale_sel_shift) & + config->masks->xscale_sel_mask; /* calculate denominator */ - den *= (val >> AUX_YSCALE_SHIFT) & AUX_YSCALE_MASK; + den *= (val >> config->masks->yscale_sel_shift) & + config->masks->yscale_sel_mask; val = (((clk->pclk->rate/10000) * num) / den) * 10000; } else val = clk->pclk->rate; @@ -383,7 +403,7 @@ void aux_clk_recalc(struct clk *clk) */ void gpt_clk_recalc(struct clk *clk) { - struct aux_clk_config *config = clk->private_data; + struct gpt_clk_config *config = clk->private_data; struct pclk_info *pclk_info = NULL; unsigned int div = 1, val; unsigned long flags; @@ -402,8 +422,10 @@ void gpt_clk_recalc(struct clk *clk) spin_lock_irqsave(&clocks_lock, flags); if (pclk_info->scalable) { val = readl(config->synth_reg); - div += (val >> GPT_MSCALE_SHIFT) & GPT_MSCALE_MASK; - div *= 1 << (((val >> GPT_NSCALE_SHIFT) & GPT_NSCALE_MASK) + 1); + div += (val >> config->masks->mscale_sel_shift) & + config->masks->mscale_sel_mask; + div *= 1 << (((val >> config->masks->nscale_sel_shift) & + config->masks->nscale_sel_mask) + 1); } clk->rate = (unsigned long)clk->pclk->rate / div; @@ -411,15 +433,16 @@ void gpt_clk_recalc(struct clk *clk) } /* - * Used for clocks that always have same value as the parent clock divided by a + * Used for clocks that always have value as the parent clock divided by a * fixed divisor */ void follow_parent(struct clk *clk) { unsigned long flags; + unsigned int div_factor = (clk->div_factor < 1) ? 1 : clk->div_factor; spin_lock_irqsave(&clocks_lock, flags); - clk->rate = clk->pclk->rate; + clk->rate = clk->pclk->rate/div_factor; spin_unlock_irqrestore(&clocks_lock, flags); } diff --git a/arch/arm/plat-spear/include/plat/clock.h b/arch/arm/plat-spear/include/plat/clock.h index 2572260f990..863d9e98392 100644 --- a/arch/arm/plat-spear/include/plat/clock.h +++ b/arch/arm/plat-spear/include/plat/clock.h @@ -54,7 +54,7 @@ struct pclk_info { struct pclk_sel { struct pclk_info *pclk_info; u8 pclk_count; - unsigned int *pclk_sel_reg; + void __iomem *pclk_sel_reg; unsigned int pclk_sel_mask; }; @@ -67,6 +67,7 @@ struct pclk_sel { * @en_reg_bit: clk enable/disable bit * @ops: clk enable/disable ops - generic_clkops selected if NULL * @recalc: pointer to clock rate recalculate function + * @div_factor: division factor to parent clock. Only for recalc = follow_parent * @pclk: current parent clk * @pclk_sel: pointer to parent selection structure * @pclk_sel_shift: register shift for selecting parent of this clock @@ -78,10 +79,11 @@ struct clk { unsigned int usage_count; unsigned int flags; unsigned long rate; - unsigned int *en_reg; + void __iomem *en_reg; u8 en_reg_bit; const struct clkops *ops; void (*recalc) (struct clk *); + unsigned int div_factor; struct clk *pclk; struct pclk_sel *pclk_sel; @@ -93,23 +95,65 @@ struct clk { }; /* pll configuration structure */ +struct pll_clk_masks { + u32 mode_mask; + u32 mode_shift; + + u32 norm_fdbk_m_mask; + u32 norm_fdbk_m_shift; + u32 dith_fdbk_m_mask; + u32 dith_fdbk_m_shift; + u32 div_p_mask; + u32 div_p_shift; + u32 div_n_mask; + u32 div_n_shift; +}; + struct pll_clk_config { - unsigned int *mode_reg; - unsigned int *cfg_reg; + void __iomem *mode_reg; + void __iomem *cfg_reg; + struct pll_clk_masks *masks; }; /* ahb and apb bus configuration structure */ +struct bus_clk_masks { + u32 mask; + u32 shift; +}; + struct bus_clk_config { - unsigned int *reg; - unsigned int mask; - unsigned int shift; + void __iomem *reg; + struct bus_clk_masks *masks; +}; + +/* Aux clk configuration structure: applicable to UART and FIRDA */ +struct aux_clk_masks { + u32 eq_sel_mask; + u32 eq_sel_shift; + u32 eq1_mask; + u32 eq2_mask; + u32 xscale_sel_mask; + u32 xscale_sel_shift; + u32 yscale_sel_mask; + u32 yscale_sel_shift; }; -/* - * Aux clk configuration structure: applicable to GPT, UART and FIRDA - */ struct aux_clk_config { - unsigned int *synth_reg; + void __iomem *synth_reg; + struct aux_clk_masks *masks; +}; + +/* GPT clk configuration structure */ +struct gpt_clk_masks { + u32 mscale_sel_mask; + u32 mscale_sel_shift; + u32 nscale_sel_mask; + u32 nscale_sel_shift; +}; + +struct gpt_clk_config { + void __iomem *synth_reg; + struct gpt_clk_masks *masks; }; /* platform specific clock functions */ @@ -118,7 +162,7 @@ void recalc_root_clocks(void); /* clock recalc functions */ void follow_parent(struct clk *clk); -void pll1_clk_recalc(struct clk *clk); +void pll_clk_recalc(struct clk *clk); void bus_clk_recalc(struct clk *clk); void gpt_clk_recalc(struct clk *clk); void aux_clk_recalc(struct clk *clk); |