summaryrefslogtreecommitdiff
path: root/arch/arm/plat-spear
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-spear')
-rw-r--r--arch/arm/plat-spear/clock.c59
-rw-r--r--arch/arm/plat-spear/include/plat/clock.h68
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);