@@ -56,6 +56,10 @@ struct omap1_clk_lookup {
* struct clk_ops - some clock function pointers
* @enable: fn ptr that enables the current clock in hardware
* @disable: fn ptr that enables the current clock in hardware
+ * @recalc_rate: fn ptr that returns the clock's current rate
+ * @set_rate: fn ptr that can change the clock's current rate
+ * @round_rate: fn ptr that can round the clock's current rate
+ * @init: fn ptr to do clock-specific initialization
*
* A "companion" clk is an accompanying clock to the one being queried
* that must be enabled for the IP module connected to the clock to
@@ -66,8 +70,12 @@ struct omap1_clk_lookup {
* @find_companion must, unfortunately, remain.
*/
struct clk_ops {
- int (*enable)(struct clk_hw *);
- void (*disable)(struct clk_hw *);
+ int (*enable)(struct clk_hw *);
+ void (*disable)(struct clk_hw *);
+ unsigned long (*recalc_rate)(struct clk_hw *, unsigned long);
+ int (*set_rate)(struct clk_hw *, unsigned long, unsigned long);
+ long (*round_rate)(struct clk_hw *, unsigned long, unsigned long *);
+ void (*init)(struct clk_hw *);
};
/*
@@ -90,10 +98,6 @@ struct clk_ops {
* @sibling: list_head connecting this clk to its parent clk's @children
* @rate: current clock rate
* @enable_reg: register to write to enable the clock (see @enable_bit)
- * @recalc: fn ptr that returns the clock's current rate
- * @set_rate: fn ptr that can change the clock's current rate
- * @round_rate: fn ptr that can round the clock's current rate
- * @init: fn ptr to do clock-specific initialization
* @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg)
* @usecount: number of users that have requested this clock to be enabled
* @fixed_div: when > 0, this clock's rate is its parent's rate / @fixed_div
@@ -138,10 +142,6 @@ struct omap1_clk {
struct list_head sibling; /* node for children */
unsigned long rate;
void __iomem *enable_reg;
- unsigned long (*recalc)(struct clk_hw *);
- int (*set_rate)(struct clk_hw *, unsigned long);
- long (*round_rate)(struct clk_hw *, unsigned long);
- void (*init)(struct clk_hw *);
u8 enable_bit;
s8 usecount;
u8 fixed_div;
@@ -268,22 +268,21 @@ static DEFINE_SPINLOCK(clockfw_lock);
* Omap1 specific clock functions
*/
-static unsigned long omap1_uart_recalc(struct clk_hw *clk_hw)
+static unsigned long omap1_uart_recalc(struct clk_hw *clk_hw, unsigned long parent_rate)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
unsigned int val = __raw_readl(clk->enable_reg);
return val & clk->enable_bit ? 48000000 : 12000000;
}
-static unsigned long omap1_sossi_recalc(struct clk_hw *clk_hw)
+static unsigned long omap1_sossi_recalc(struct clk_hw *clk_hw, unsigned long parent_rate)
{
- struct omap1_clk *clk = to_omap1_clk(clk_hw);
u32 div = omap_readl(MOD_CONF_CTRL_1);
div = (div >> 17) & 0x7;
div++;
- return clk->parent->rate / div;
+ return parent_rate / div;
}
static void omap1_clk_allow_idle(struct clk_hw *clk_hw)
@@ -363,7 +362,7 @@ static __u16 verify_ckctl_value(__u16 newval)
return newval;
}
-static int calc_dsor_exp(struct omap1_clk *clk, unsigned long rate)
+static int calc_dsor_exp(struct omap1_clk *clk, unsigned long rate, unsigned long parent_rate)
{
/* Note: If target frequency is too low, this function will return 4,
* which is invalid value. Caller must check for this value and act
@@ -377,14 +376,9 @@ static int calc_dsor_exp(struct omap1_clk *clk, unsigned long rate)
* DSPMMU_CK >= TC_CK
*/
unsigned long realrate;
- struct omap1_clk * parent;
unsigned dsor_exp;
- parent = clk->parent;
- if (unlikely(parent == NULL))
- return -EIO;
-
- realrate = parent->rate;
+ realrate = parent_rate;
for (dsor_exp=0; dsor_exp<4; dsor_exp++) {
if (realrate <= rate)
break;
@@ -395,13 +389,13 @@ static int calc_dsor_exp(struct omap1_clk *clk, unsigned long rate)
return dsor_exp;
}
-static unsigned long omap1_ckctl_recalc(struct clk_hw *clk_hw)
+static unsigned long omap1_ckctl_recalc(struct clk_hw *clk_hw, unsigned long parent_rate)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
/* Calculate divisor encoded as 2-bit exponent */
int dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
- return clk->parent->rate / dsor;
+ return parent_rate / dsor;
}
/*-------------------------------------------------------------------------
@@ -453,7 +447,7 @@ static struct mpu_rate omap1_rate_table[] = {
};
/* MPU virtual clock functions */
-static int omap1_select_table_rate(struct clk_hw *clk_hw, unsigned long rate)
+static int omap1_select_table_rate(struct clk_hw *clk_hw, unsigned long rate, unsigned long parent_rate)
{
/* Find the highest supported frequency <= rate and switch to it */
struct mpu_rate * ptr;
@@ -488,13 +482,13 @@ static int omap1_select_table_rate(struct clk_hw *clk_hw, unsigned long rate)
return 0;
}
-static int omap1_clk_set_rate_dsp_domain(struct clk_hw *clk_hw, unsigned long rate)
+static int omap1_clk_set_rate_dsp_domain(struct clk_hw *clk_hw, unsigned long rate, unsigned long parent_rate)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
int dsor_exp;
u16 regval;
- dsor_exp = calc_dsor_exp(clk, rate);
+ dsor_exp = calc_dsor_exp(clk, rate, parent_rate);
if (dsor_exp > 3)
dsor_exp = -EINVAL;
if (dsor_exp < 0)
@@ -504,29 +498,29 @@ static int omap1_clk_set_rate_dsp_domain(struct clk_hw *clk_hw, unsigned long ra
regval &= ~(3 << clk->rate_offset);
regval |= dsor_exp << clk->rate_offset;
__raw_writew(regval, DSP_CKCTL);
- clk->rate = clk->parent->rate / (1 << dsor_exp);
+ clk->rate = parent_rate / (1 << dsor_exp);
return 0;
}
-static long omap1_clk_round_rate_ckctl_arm(struct clk_hw *clk_hw, unsigned long rate)
+static long omap1_clk_round_rate_ckctl_arm(struct clk_hw *clk_hw, unsigned long rate, unsigned long *parent_rate)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
- int dsor_exp = calc_dsor_exp(clk, rate);
+ int dsor_exp = calc_dsor_exp(clk, rate, *parent_rate);
if (dsor_exp < 0)
return dsor_exp;
if (dsor_exp > 3)
dsor_exp = 3;
- return clk->parent->rate / (1 << dsor_exp);
+ return *parent_rate / (1 << dsor_exp);
}
-static int omap1_clk_set_rate_ckctl_arm(struct clk_hw *clk_hw, unsigned long rate)
+static int omap1_clk_set_rate_ckctl_arm(struct clk_hw *clk_hw, unsigned long rate, unsigned long parent_rate)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
int dsor_exp;
u16 regval;
- dsor_exp = calc_dsor_exp(clk, rate);
+ dsor_exp = calc_dsor_exp(clk, rate, parent_rate);
if (dsor_exp > 3)
dsor_exp = -EINVAL;
if (dsor_exp < 0)
@@ -537,11 +531,11 @@ static int omap1_clk_set_rate_ckctl_arm(struct clk_hw *clk_hw, unsigned long rat
regval |= dsor_exp << clk->rate_offset;
regval = verify_ckctl_value(regval);
omap_writew(regval, ARM_CKCTL);
- clk->rate = clk->parent->rate / (1 << dsor_exp);
+ clk->rate = parent_rate / (1 << dsor_exp);
return 0;
}
-static long omap1_round_to_table_rate(struct clk_hw *clk_hw, unsigned long rate)
+static long omap1_round_to_table_rate(struct clk_hw *clk_hw, unsigned long rate, unsigned long *parent_rate)
{
/* Find the highest supported frequency <= rate */
struct mpu_rate * ptr;
@@ -592,7 +586,7 @@ static unsigned calc_ext_dsor(unsigned long rate)
}
/* XXX Only needed on 1510 */
-static int omap1_set_uart_rate(struct clk_hw *clk_hw, unsigned long rate)
+static int omap1_set_uart_rate(struct clk_hw *clk_hw, unsigned long rate, unsigned long parent_rate)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
unsigned int val;
@@ -611,7 +605,7 @@ static int omap1_set_uart_rate(struct clk_hw *clk_hw, unsigned long rate)
}
/* External clock (MCLK & BCLK) functions */
-static int omap1_set_ext_clk_rate(struct clk_hw *clk_hw, unsigned long rate)
+static int omap1_set_ext_clk_rate(struct clk_hw *clk_hw, unsigned long rate, unsigned long parent_rate)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
unsigned dsor;
@@ -630,16 +624,14 @@ static int omap1_set_ext_clk_rate(struct clk_hw *clk_hw, unsigned long rate)
return 0;
}
-static int omap1_set_sossi_rate(struct clk_hw *clk_hw, unsigned long rate)
+static int omap1_set_sossi_rate(struct clk_hw *clk_hw, unsigned long rate, unsigned long parent_rate)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
u32 l;
int div;
- unsigned long p_rate;
- p_rate = clk->parent->rate;
/* Round towards slower frequency */
- div = (p_rate + rate - 1) / rate;
+ div = (parent_rate + rate - 1) / rate;
div--;
if (div < 0 || div > 7)
return -EINVAL;
@@ -649,12 +641,12 @@ static int omap1_set_sossi_rate(struct clk_hw *clk_hw, unsigned long rate)
l |= div << 17;
omap_writel(l, MOD_CONF_CTRL_1);
- clk->rate = p_rate / (div + 1);
+ clk->rate = parent_rate / (div + 1);
return 0;
}
-static long omap1_round_ext_clk_rate(struct clk_hw *clk_hw, unsigned long rate)
+static long omap1_round_ext_clk_rate(struct clk_hw *clk_hw, unsigned long rate, unsigned long *parent_rate)
{
return 96000000 / calc_ext_dsor(rate);
}
@@ -678,16 +670,27 @@ static void omap1_init_ext_clk(struct clk_hw *clk_hw)
clk-> rate = 96000000 / dsor;
}
+struct clk_hw *clk_hw_get_parent(const struct clk_hw *clk_hw)
+{
+ struct omap1_clk *clk = to_omap1_clk(clk_hw);
+
+ if (!clk->parent)
+ return NULL;
+
+ return &clk->parent->clk_hw;
+}
+
static void omap1_clk_disable(struct clk_hw *clk_hw)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
+ struct clk_hw *parent = clk_hw_get_parent(clk_hw);
if (clk->usecount > 0 && !(--clk->usecount)) {
- clk->ops->disable(&clk->clk_hw);
- if (likely(clk->parent)) {
- omap1_clk_disable(&clk->parent->clk_hw);
+ clk->ops->disable(clk_hw);
+ if (likely(parent)) {
+ omap1_clk_disable(parent);
if (clk->flags & CLOCK_NO_IDLE_PARENT)
- omap1_clk_allow_idle(&clk->parent->clk_hw);
+ omap1_clk_allow_idle(parent);
}
}
}
@@ -695,22 +698,23 @@ static void omap1_clk_disable(struct clk_hw *clk_hw)
static omap1_clk_enable(struct clk_hw *clk_hw)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
+ struct clk_hw *parent = clk_hw_get_parent(clk_hw);
int ret = 0;
if (clk->usecount++ == 0) {
- if (clk->parent) {
- ret = omap1_clk_enable(&clk->parent->clk_hw);
+ if (parent) {
+ ret = omap1_clk_enable(parent);
if (ret)
goto err;
if (clk->flags & CLOCK_NO_IDLE_PARENT)
- omap1_clk_deny_idle(&clk->parent->clk_hw);
+ omap1_clk_deny_idle(parent);
}
ret = clk->ops->enable(&clk->clk_hw);
if (ret) {
- if (clk->parent)
- omap1_clk_disable(&clk->parent->clk_hw);
+ if (parent)
+ omap1_clk_disable(parent);
goto err;
}
}
@@ -771,7 +775,7 @@ static const struct clk_ops clkops_generic = {
.disable = omap1_clk_disable_generic,
};
-static unsigned long omap1_ckctl_recalc_dsp_domain(struct clk_hw *clk_hw)
+static unsigned long omap1_ckctl_recalc_dsp_domain(struct clk_hw *clk_hw, unsigned long parent_rate)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
int dsor;
@@ -787,7 +791,7 @@ static unsigned long omap1_ckctl_recalc_dsp_domain(struct clk_hw *clk_hw)
dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));
omap1_clk_disable(api_ck_p);
- return clk->parent->rate / dsor;
+ return parent_rate / dsor;
}
static int omap1_clk_enable_dsp_domain(struct clk_hw *clk_hw)
@@ -812,11 +816,6 @@ static void omap1_clk_disable_dsp_domain(struct clk_hw *clk_hw)
}
}
-static const struct clk_ops clkops_dspck = {
- .enable = omap1_clk_enable_dsp_domain,
- .disable = omap1_clk_disable_dsp_domain,
-};
-
/* XXX SYSC register handling does not belong in the clock framework */
static int omap1_clk_enable_uart_functional_16xx(struct clk_hw *clk_hw)
{
@@ -857,9 +856,20 @@ static const struct clk_ops clkops_uart_16xx = {
static long omap1_clk_round_rate(struct clk_hw *clk_hw, unsigned long rate)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
+ struct clk_hw *parent = clk_hw_get_parent(clk_hw);
+ struct omap1_clk *parent_clk;
+ unsigned long parent_rate = 0;
+
+ if (parent) {
+ parent_clk = to_omap1_clk(parent);
+ parent_rate = parent_clk->rate;
+ }
+
+ if (clk->ops->round_rate != NULL)
+ return clk->ops->round_rate(clk_hw, rate, &parent_rate);
- if (clk->round_rate != NULL)
- return clk->round_rate(clk_hw, rate);
+ if (parent)
+ parent_clk->rate = parent_rate;
return clk->rate;
}
@@ -867,10 +877,15 @@ static long omap1_clk_round_rate(struct clk_hw *clk_hw, unsigned long rate)
static int omap1_clk_set_rate(struct clk_hw *clk_hw, unsigned long rate)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
+ struct clk_hw *parent = clk_hw_get_parent(clk_hw);
+ unsigned long parent_rate = 0;
int ret = -EINVAL;
- if (clk->set_rate)
- ret = clk->set_rate(clk_hw, rate);
+ if (parent)
+ parent_rate = to_omap1_clk(parent)->rate;
+
+ if (clk->ops->set_rate)
+ ret = clk->ops->set_rate(clk_hw, rate, parent_rate);
return ret;
}
@@ -880,8 +895,8 @@ static void propagate_rate(struct omap1_clk *tclk)
struct omap1_clk *clkp;
list_for_each_entry(clkp, &tclk->children, sibling) {
- if (clkp->recalc)
- clkp->rate = clkp->recalc(&clkp->clk_hw);
+ if (clkp->ops->recalc_rate)
+ clkp->rate = clkp->ops->recalc_rate(&clkp->clk_hw, tclk->rate);
propagate_rate(clkp);
}
}
@@ -993,9 +1008,12 @@ EXPORT_SYMBOL(clk_set_parent);
struct clk *clk_get_parent(struct clk *clk)
{
- struct omap1_clk *parent = to_omap1_clk(clk->clk_hw)->parent;
+ struct clk_hw *parent = clk_hw_get_parent(clk->clk_hw);
+
+ if (!parent)
+ return NULL;
- return &parent->clk_hw.clk;
+ return &parent->clk;
}
EXPORT_SYMBOL(clk_get_parent);
@@ -1004,24 +1022,22 @@ EXPORT_SYMBOL(clk_get_parent);
*/
/* Used for clocks that always have same value as the parent clock */
-static unsigned long followparent_recalc(struct clk_hw *clk_hw)
+static unsigned long followparent_recalc(struct clk_hw *clk_hw, unsigned long parent_rate)
{
- struct omap1_clk *clk = to_omap1_clk(clk_hw);
-
- return clk->parent->rate;
+ return parent_rate;
}
/*
* Used for clocks that have the same value as the parent clock,
* divided by some factor
*/
-static unsigned long omap_fixed_divisor_recalc(struct clk_hw *clk_hw)
+static unsigned long omap_fixed_divisor_recalc(struct clk_hw *clk_hw, unsigned long parent_rate)
{
struct omap1_clk *clk = to_omap1_clk(clk_hw);
WARN_ON(!clk->fixed_div);
- return clk->parent->rate / clk->fixed_div;
+ return parent_rate / clk->fixed_div;
}
/**
@@ -1056,8 +1072,8 @@ static int clk_register(struct device *dev, struct clk_hw *clk_hw)
list_add(&clk->sibling, &clk->parent->children);
list_add(&clk->node, &clocks);
- if (clk->init)
- clk->init(&clk->clk_hw);
+ if (clk->ops->init)
+ clk->ops->init(&clk->clk_hw);
mutex_unlock(&clocks_mutex);
return 0;
@@ -1080,6 +1096,12 @@ static const struct clk_ops clkops_null = {
.disable = clkll_disable_null,
};
+static const struct clk_ops clkops_followparent = {
+ .enable = clkll_enable_null,
+ .disable = clkll_disable_null,
+ .recalc_rate = followparent_recalc,
+};
+
/*
* Dummy clock
*
@@ -1239,6 +1261,12 @@ static struct omap1_clk ck_dpll1 = {
.parent = &ck_ref,
};
+static const struct clk_ops clkops_generic_followparent = {
+ .enable = omap1_clk_enable_generic,
+ .disable = omap1_clk_disable_generic,
+ .recalc_rate = followparent_recalc,
+};
+
/*
* FIXME: This clock seems to be necessary but no-one has asked for its
* activation. [ FIX: SoSSI, SSR ]
@@ -1246,33 +1274,50 @@ static struct omap1_clk ck_dpll1 = {
static struct arm_idlect1_clk ck_dpll1out = {
.clk = {
.name = "ck_dpll1out",
- .ops = &clkops_generic,
+ .ops = &clkops_generic_followparent,
.parent = &ck_dpll1,
.flags = CLOCK_IDLE_CONTROL | ENABLE_REG_32BIT,
.enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_CKOUT_ARM,
- .recalc = &followparent_recalc,
},
.idlect_shift = IDL_CLKOUT_ARM_SHIFT,
};
+static const struct clk_ops clkops_sossi = {
+ .enable = omap1_clk_enable_generic,
+ .disable = omap1_clk_disable_generic,
+ .recalc_rate = &omap1_sossi_recalc,
+ .set_rate = &omap1_set_sossi_rate,
+};
+
static struct omap1_clk sossi_ck = {
.name = "ck_sossi",
- .ops = &clkops_generic,
+ .ops = &clkops_sossi,
.parent = &ck_dpll1out.clk,
.flags = CLOCK_NO_IDLE_PARENT | ENABLE_REG_32BIT,
.enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1),
.enable_bit = CONF_MOD_SOSSI_CLK_EN_R,
- .recalc = &omap1_sossi_recalc,
- .set_rate = &omap1_set_sossi_rate,
+};
+
+struct clk_ops clkops_null_ckctl = {
+ .enable = clkll_enable_null,
+ .disable = clkll_disable_null,
+ .recalc_rate = omap1_ckctl_recalc,
+ .round_rate = omap1_clk_round_rate_ckctl_arm,
+ .set_rate = omap1_clk_set_rate_ckctl_arm,
};
static struct omap1_clk arm_ck = {
.name = "arm_ck",
- .ops = &clkops_null,
+ .ops = &clkops_null_ckctl,
.parent = &ck_dpll1,
.rate_offset = CKCTL_ARMDIV_OFFSET,
- .recalc = &omap1_ckctl_recalc,
+};
+
+struct clk_ops clkops_generic_ckctl = {
+ .enable = omap1_clk_enable_generic,
+ .disable = omap1_clk_disable_generic,
+ .recalc_rate = omap1_ckctl_recalc,
.round_rate = omap1_clk_round_rate_ckctl_arm,
.set_rate = omap1_clk_set_rate_ckctl_arm,
};
@@ -1280,15 +1325,12 @@ static struct omap1_clk arm_ck = {
static struct arm_idlect1_clk armper_ck = {
.clk = {
.name = "armper_ck",
- .ops = &clkops_generic,
+ .ops = &clkops_generic_ckctl,
.parent = &ck_dpll1,
.flags = CLOCK_IDLE_CONTROL,
.enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_PERCK,
.rate_offset = CKCTL_PERDIV_OFFSET,
- .recalc = &omap1_ckctl_recalc,
- .round_rate = omap1_clk_round_rate_ckctl_arm,
- .set_rate = omap1_clk_set_rate_ckctl_arm,
},
.idlect_shift = IDLPER_ARM_SHIFT,
};
@@ -1299,22 +1341,20 @@ static struct arm_idlect1_clk armper_ck = {
*/
static struct omap1_clk arm_gpio_ck = {
.name = "ick",
- .ops = &clkops_generic,
+ .ops = &clkops_generic_followparent,
.parent = &ck_dpll1,
.enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_GPIOCK,
- .recalc = &followparent_recalc,
};
static struct arm_idlect1_clk armxor_ck = {
.clk = {
.name = "armxor_ck",
- .ops = &clkops_generic,
+ .ops = &clkops_generic_followparent,
.parent = &ck_ref,
.flags = CLOCK_IDLE_CONTROL,
.enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_XORPCK,
- .recalc = &followparent_recalc,
},
.idlect_shift = IDLXORP_ARM_SHIFT,
};
@@ -1322,16 +1362,21 @@ static struct arm_idlect1_clk armxor_ck = {
static struct arm_idlect1_clk armtim_ck = {
.clk = {
.name = "armtim_ck",
- .ops = &clkops_generic,
+ .ops = &clkops_generic_followparent,
.parent = &ck_ref,
.flags = CLOCK_IDLE_CONTROL,
.enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_TIMCK,
- .recalc = &followparent_recalc,
},
.idlect_shift = IDLTIM_ARM_SHIFT,
};
+static const struct clk_ops clkops_fixed_divisor = {
+ .enable = omap1_clk_enable_generic,
+ .disable = omap1_clk_disable_generic,
+ .recalc_rate = omap_fixed_divisor_recalc,
+};
+
static struct arm_idlect1_clk armwdt_ck = {
.clk = {
.name = "armwdt_ck",
@@ -1341,16 +1386,14 @@ static struct arm_idlect1_clk armwdt_ck = {
.enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_WDTCK,
.fixed_div = 14,
- .recalc = &omap_fixed_divisor_recalc,
},
.idlect_shift = IDLWDT_ARM_SHIFT,
};
static struct omap1_clk arminth_ck16xx = {
.name = "arminth_ck",
- .ops = &clkops_null,
+ .ops = &clkops_followparent,
.parent = &arm_ck,
- .recalc = &followparent_recalc,
/* Note: On 16xx the frequency can be divided by 2 by programming
* ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
*
@@ -1360,24 +1403,26 @@ static struct omap1_clk arminth_ck16xx = {
static struct omap1_clk dsp_ck = {
.name = "dsp_ck",
- .ops = &clkops_generic,
+ .ops = &clkops_generic_ckctl,
.parent = &ck_dpll1,
.enable_reg = OMAP1_IO_ADDRESS(ARM_CKCTL),
.enable_bit = EN_DSPCK,
.rate_offset = CKCTL_DSPDIV_OFFSET,
- .recalc = &omap1_ckctl_recalc,
- .round_rate = omap1_clk_round_rate_ckctl_arm,
- .set_rate = omap1_clk_set_rate_ckctl_arm,
};
static struct omap1_clk dspmmu_ck = {
.name = "dspmmu_ck",
- .ops = &clkops_null,
+ .ops = &clkops_null_ckctl,
.parent = &ck_dpll1,
.rate_offset = CKCTL_DSPMMUDIV_OFFSET,
- .recalc = &omap1_ckctl_recalc,
+};
+
+static const struct clk_ops clkops_dspck = {
+ .enable = omap1_clk_enable_dsp_domain,
+ .disable = omap1_clk_disable_dsp_domain,
+ .recalc_rate = omap1_ckctl_recalc_dsp_domain,
.round_rate = omap1_clk_round_rate_ckctl_arm,
- .set_rate = omap1_clk_set_rate_ckctl_arm,
+ .set_rate = omap1_clk_set_rate_dsp_domain,
};
static struct omap1_clk dspper_ck = {
@@ -1387,48 +1432,45 @@ static struct omap1_clk dspper_ck = {
.enable_reg = DSP_IDLECT2,
.enable_bit = EN_PERCK,
.rate_offset = CKCTL_PERDIV_OFFSET,
- .recalc = &omap1_ckctl_recalc_dsp_domain,
- .round_rate = omap1_clk_round_rate_ckctl_arm,
- .set_rate = &omap1_clk_set_rate_dsp_domain,
+};
+
+static const struct clk_ops clkops_dspck_followparent = {
+ .enable = omap1_clk_enable_dsp_domain,
+ .disable = omap1_clk_disable_dsp_domain,
+ .recalc_rate = followparent_recalc,
};
static struct omap1_clk dspxor_ck = {
.name = "dspxor_ck",
- .ops = &clkops_dspck,
+ .ops = &clkops_dspck_followparent,
.parent = &ck_ref,
.enable_reg = DSP_IDLECT2,
.enable_bit = EN_XORPCK,
- .recalc = &followparent_recalc,
};
static struct omap1_clk dsptim_ck = {
.name = "dsptim_ck",
- .ops = &clkops_dspck,
+ .ops = &clkops_dspck_followparent,
.parent = &ck_ref,
.enable_reg = DSP_IDLECT2,
.enable_bit = EN_DSPTIMCK,
- .recalc = &followparent_recalc,
};
static struct arm_idlect1_clk tc_ck = {
.clk = {
.name = "tc_ck",
- .ops = &clkops_null,
+ .ops = &clkops_null_ckctl,
.parent = &ck_dpll1,
.flags = CLOCK_IDLE_CONTROL,
.rate_offset = CKCTL_TCDIV_OFFSET,
- .recalc = &omap1_ckctl_recalc,
- .round_rate = omap1_clk_round_rate_ckctl_arm,
- .set_rate = omap1_clk_set_rate_ckctl_arm,
},
.idlect_shift = IDLIF_ARM_SHIFT,
};
static struct omap1_clk arminth_ck1510 = {
.name = "arminth_ck",
- .ops = &clkops_null,
+ .ops = &clkops_followparent,
.parent = &tc_ck.clk,
- .recalc = &followparent_recalc,
/* Note: On 1510 the frequency follows TC_CK
*
* 16xx version is in MPU clocks.
@@ -1438,28 +1480,25 @@ static struct omap1_clk arminth_ck1510 = {
static struct omap1_clk tipb_ck = {
/* No-idle controlled by "tc_ck" */
.name = "tipb_ck",
- .ops = &clkops_null,
+ .ops = &clkops_followparent,
.parent = &tc_ck.clk,
- .recalc = &followparent_recalc,
};
static struct omap1_clk l3_ocpi_ck = {
/* No-idle controlled by "tc_ck" */
.name = "l3_ocpi_ck",
- .ops = &clkops_generic,
+ .ops = &clkops_generic_followparent,
.parent = &tc_ck.clk,
.enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT3),
.enable_bit = EN_OCPI_CK,
- .recalc = &followparent_recalc,
};
static struct omap1_clk tc1_ck = {
.name = "tc1_ck",
- .ops = &clkops_generic,
+ .ops = &clkops_generic_followparent,
.parent = &tc_ck.clk,
.enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT3),
.enable_bit = EN_TC1_CK,
- .recalc = &followparent_recalc,
};
/*
@@ -1468,37 +1507,33 @@ static struct omap1_clk tc1_ck = {
*/
static struct omap1_clk tc2_ck = {
.name = "tc2_ck",
- .ops = &clkops_generic,
+ .ops = &clkops_generic_followparent,
.parent = &tc_ck.clk,
.enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT3),
.enable_bit = EN_TC2_CK,
- .recalc = &followparent_recalc,
};
static struct omap1_clk dma_ck = {
/* No-idle controlled by "tc_ck" */
.name = "dma_ck",
- .ops = &clkops_null,
+ .ops = &clkops_followparent,
.parent = &tc_ck.clk,
- .recalc = &followparent_recalc,
};
static struct omap1_clk dma_lcdfree_ck = {
.name = "dma_lcdfree_ck",
- .ops = &clkops_null,
+ .ops = &clkops_followparent,
.parent = &tc_ck.clk,
- .recalc = &followparent_recalc,
};
static struct arm_idlect1_clk api_ck = {
.clk = {
.name = "api_ck",
- .ops = &clkops_generic,
+ .ops = &clkops_generic_followparent,
.parent = &tc_ck.clk,
.flags = CLOCK_IDLE_CONTROL,
.enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_APICK,
- .recalc = &followparent_recalc,
},
.idlect_shift = IDLAPI_ARM_SHIFT,
};
@@ -1506,58 +1541,56 @@ static struct arm_idlect1_clk api_ck = {
static struct arm_idlect1_clk lb_ck = {
.clk = {
.name = "lb_ck",
- .ops = &clkops_generic,
+ .ops = &clkops_generic_followparent,
.parent = &tc_ck.clk,
.flags = CLOCK_IDLE_CONTROL,
.enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_LBCK,
- .recalc = &followparent_recalc,
},
.idlect_shift = IDLLB_ARM_SHIFT,
};
static struct omap1_clk rhea1_ck = {
.name = "rhea1_ck",
- .ops = &clkops_null,
+ .ops = &clkops_followparent,
.parent = &tc_ck.clk,
- .recalc = &followparent_recalc,
};
static struct omap1_clk rhea2_ck = {
.name = "rhea2_ck",
- .ops = &clkops_null,
+ .ops = &clkops_followparent,
.parent = &tc_ck.clk,
- .recalc = &followparent_recalc,
};
static struct omap1_clk lcd_ck_16xx = {
.name = "lcd_ck",
- .ops = &clkops_generic,
+ .ops = &clkops_generic_ckctl,
.parent = &ck_dpll1,
.enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_LCDCK,
.rate_offset = CKCTL_LCDDIV_OFFSET,
- .recalc = &omap1_ckctl_recalc,
- .round_rate = omap1_clk_round_rate_ckctl_arm,
- .set_rate = omap1_clk_set_rate_ckctl_arm,
};
static struct arm_idlect1_clk lcd_ck_1510 = {
.clk = {
.name = "lcd_ck",
- .ops = &clkops_generic,
+ .ops = &clkops_generic_ckctl,
.parent = &ck_dpll1,
.flags = CLOCK_IDLE_CONTROL,
.enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
.enable_bit = EN_LCDCK,
.rate_offset = CKCTL_LCDDIV_OFFSET,
- .recalc = &omap1_ckctl_recalc,
- .round_rate = omap1_clk_round_rate_ckctl_arm,
- .set_rate = omap1_clk_set_rate_ckctl_arm,
},
.idlect_shift = OMAP1510_IDLLCD_ARM_SHIFT,
};
+static const struct clk_ops clkops_uart = {
+ .enable = clkll_enable_null,
+ .disable = clkll_disable_null,
+ .set_rate = omap1_set_uart_rate,
+ .recalc_rate = omap1_uart_recalc,
+};
+
/*
* XXX The enable_bit here is misused - it simply switches between 12MHz
* and 48MHz. Reimplement with clksel.
@@ -1566,15 +1599,13 @@ static struct arm_idlect1_clk lcd_ck_1510 = {
*/
static struct omap1_clk uart1_1510 = {
.name = "uart1_ck",
- .ops = &clkops_null,
+ .ops = &clkops_uart,
/* Direct from ULPD, no real parent */
.parent = &armper_ck.clk,
.rate = 12000000,
.flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
.enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
.enable_bit = CONF_MOD_UART1_CLK_MODE_R,
- .set_rate = &omap1_set_uart_rate,
- .recalc = &omap1_uart_recalc,
};
/*
@@ -1605,15 +1636,13 @@ static struct uart_clk uart1_16xx = {
*/
static struct omap1_clk uart2_ck = {
.name = "uart2_ck",
- .ops = &clkops_null,
+ .ops = &clkops_uart,
/* Direct from ULPD, no real parent */
.parent = &armper_ck.clk,
.rate = 12000000,
.flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
.enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
.enable_bit = CONF_MOD_UART2_CLK_MODE_R,
- .set_rate = &omap1_set_uart_rate,
- .recalc = &omap1_uart_recalc,
};
/*
@@ -1624,15 +1653,13 @@ static struct omap1_clk uart2_ck = {
*/
static struct omap1_clk uart3_1510 = {
.name = "uart3_ck",
- .ops = &clkops_null,
+ .ops = &clkops_uart,
/* Direct from ULPD, no real parent */
.parent = &armper_ck.clk,
.rate = 12000000,
.flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
.enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
.enable_bit = CONF_MOD_UART3_CLK_MODE_R,
- .set_rate = &omap1_set_uart_rate,
- .recalc = &omap1_uart_recalc,
};
/*
@@ -1722,15 +1749,20 @@ static struct omap1_clk mclk_1510 = {
.enable_bit = SOFT_COM_MCKO_REQ_SHIFT,
};
+static const struct clk_ops clkops_ext_clk = {
+ .enable = omap1_clk_enable_generic,
+ .disable = omap1_clk_disable_generic,
+ .set_rate = omap1_set_ext_clk_rate,
+ .round_rate = omap1_round_ext_clk_rate,
+ .init = omap1_init_ext_clk,
+};
+
static struct omap1_clk mclk_16xx = {
.name = "mclk",
- .ops = &clkops_generic,
+ .ops = &clkops_ext_clk,
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
.enable_reg = OMAP1_IO_ADDRESS(COM_CLK_DIV_CTRL_SEL),
.enable_bit = COM_ULPD_PLL_CLK_REQ,
- .set_rate = &omap1_set_ext_clk_rate,
- .round_rate = &omap1_round_ext_clk_rate,
- .init = &omap1_init_ext_clk,
};
static struct omap1_clk bclk_1510 = {
@@ -1742,13 +1774,10 @@ static struct omap1_clk bclk_1510 = {
static struct omap1_clk bclk_16xx = {
.name = "bclk",
- .ops = &clkops_generic,
+ .ops = &clkops_ext_clk,
/* Direct from ULPD, no parent. May be enabled by ext hardware. */
.enable_reg = OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL),
.enable_bit = SWD_ULPD_PLL_CLK_REQ,
- .set_rate = &omap1_set_ext_clk_rate,
- .round_rate = &omap1_round_ext_clk_rate,
- .init = &omap1_init_ext_clk,
};
static struct omap1_clk mmc1_ck = {
@@ -1788,31 +1817,34 @@ static struct omap1_clk mmc3_ck = {
.enable_bit = SOFT_MMC_DPLL_REQ_SHIFT,
};
+static const struct clk_ops clkops_mpu = {
+ .enable = clkll_enable_null,
+ .disable = clkll_disable_null,
+ .recalc_rate = followparent_recalc,
+ .set_rate = omap1_select_table_rate,
+ .round_rate = omap1_round_to_table_rate,
+};
+
static struct omap1_clk virtual_ck_mpu = {
.name = "mpu",
- .ops = &clkops_null,
+ .ops = &clkops_mpu,
.parent = &arm_ck, /* Is smarter alias for */
- .recalc = &followparent_recalc,
- .set_rate = &omap1_select_table_rate,
- .round_rate = &omap1_round_to_table_rate,
};
/* virtual functional clock domain for I2C. Just for making sure that ARMXOR_CK
remains active during MPU idle whenever this is enabled */
static struct omap1_clk i2c_fck = {
.name = "i2c_fck",
- .ops = &clkops_null,
+ .ops = &clkops_followparent,
.flags = CLOCK_NO_IDLE_PARENT,
.parent = &armxor_ck.clk,
- .recalc = &followparent_recalc,
};
static struct omap1_clk i2c_ick = {
.name = "i2c_ick",
- .ops = &clkops_null,
+ .ops = &clkops_followparent,
.flags = CLOCK_NO_IDLE_PARENT,
.parent = &armper_ck.clk,
- .recalc = &followparent_recalc,
};
/*
@@ -2057,7 +2089,7 @@ void __init omap1_clk_late_init(void)
unsigned long rate = ck_dpll1.rate;
/* Find the highest supported frequency and enable it */
- if (omap1_select_table_rate(&virtual_ck_mpu.clk_hw, ~0)) {
+ if (omap1_select_table_rate(&virtual_ck_mpu.clk_hw, ~0, 0)) {
pr_err("System frequencies not set, using default. Check your config.\n");
/*
* Reprogramming the DPLL is tricky, it must be done from SRAM.
The callbacks for clocks are almost the same as those used on common_clk, now reduce the number of remaining differences: - make .recalc_rate and .round_rate take a parent_rate argument - move .recalc_rate/.set_rate/.round_rate/.init from 'struct clk_hw' into 'struct clk_ops'. Signed-off-by: Arnd Bergmann <arnd@arndb.de> --- arch/arm/mach-omap1/clock.c | 368 ++++++++++++++++++++---------------- 1 file changed, 200 insertions(+), 168 deletions(-)