* Omap1 specific clock functions
*-------------------------------------------------------------------------*/
-static void omap1_watchdog_recalc(struct clk * clk)
+static void omap1_watchdog_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- clk->rate = clk->parent->rate / 14;
+ unsigned long new_rate;
+
+ new_rate = parent_rate / 14;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
}
-static void omap1_uart_recalc(struct clk * clk)
+static void omap1_uart_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
+ unsigned long new_rate;
unsigned int val = __raw_readl(clk->enable_reg);
+
if (val & clk->enable_bit)
- clk->rate = 48000000;
+ new_rate = 48000000;
else
- clk->rate = 12000000;
+ new_rate = 12000000;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
}
-static void omap1_sossi_recalc(struct clk *clk)
+static void omap1_sossi_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
+ unsigned long new_rate;
u32 div = omap_readl(MOD_CONF_CTRL_1);
div = (div >> 17) & 0x7;
div++;
- clk->rate = clk->parent->rate / div;
+ new_rate = clk->parent->rate / div;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
}
static int omap1_clk_enable_dsp_domain(struct clk *clk)
return dsor_exp;
}
-static void omap1_ckctl_recalc(struct clk * clk)
+static void omap1_ckctl_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
int dsor;
+ unsigned long new_rate;
/* Calculate divisor encoded as 2-bit exponent */
dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
- if (unlikely(clk->rate == clk->parent->rate / dsor))
+ new_rate = parent_rate / dsor;
+
+ if (unlikely(clk->rate == new_rate))
return; /* No change, quick exit */
- clk->rate = clk->parent->rate / dsor;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
}
-static void omap1_ckctl_recalc_dsp_domain(struct clk * clk)
+static void omap1_ckctl_recalc_dsp_domain(struct clk *clk,
+ unsigned long parent_rate,
+ u8 rate_storage)
{
int dsor;
+ unsigned long new_rate;
/* Calculate divisor encoded as 2-bit exponent
*
dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));
omap1_clk_disable(&api_ck.clk);
- if (unlikely(clk->rate == clk->parent->rate / dsor))
+ new_rate = parent_rate / dsor;
+
+ if (unlikely(clk->rate == new_rate))
return; /* No change, quick exit */
- clk->rate = clk->parent->rate / dsor;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_rate;
}
/* MPU virtual clock functions */
omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
ck_dpll1.rate = ptr->pll_rate;
- propagate_rate(&ck_dpll1);
+ propagate_rate(&ck_dpll1, CURRENT_RATE);
return 0;
}
}
}
}
- propagate_rate(&ck_dpll1);
+ propagate_rate(&ck_dpll1, CURRENT_RATE);
#else
/* Find the highest supported frequency and enable it */
if (omap1_select_table_rate(&virtual_ck_mpu, ~0)) {
omap_writew(0x2290, DPLL_CTL);
omap_writew(cpu_is_omap730() ? 0x3005 : 0x1005, ARM_CKCTL);
ck_dpll1.rate = 60000000;
- propagate_rate(&ck_dpll1);
+ propagate_rate(&ck_dpll1, CURRENT_RATE);
}
#endif
/* Cache rates for clocks connected to ck_ref (not dpll1) */
- propagate_rate(&ck_ref);
+ propagate_rate(&ck_ref, CURRENT_RATE);
printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): "
"%ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n",
ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
static int omap1_clk_enable_generic(struct clk * clk);
static void omap1_clk_disable_generic(struct clk * clk);
-static void omap1_ckctl_recalc(struct clk * clk);
-static void omap1_watchdog_recalc(struct clk * clk);
+static void omap1_ckctl_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap1_watchdog_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
static int omap1_set_sossi_rate(struct clk *clk, unsigned long rate);
-static void omap1_sossi_recalc(struct clk *clk);
-static void omap1_ckctl_recalc_dsp_domain(struct clk * clk);
+static void omap1_sossi_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap1_ckctl_recalc_dsp_domain(struct clk *clk,
+ unsigned long parent_rate,
+ u8 rate_storage);
static int omap1_clk_enable_dsp_domain(struct clk * clk);
static int omap1_clk_set_rate_dsp_domain(struct clk * clk, unsigned long rate);
static void omap1_clk_disable_dsp_domain(struct clk * clk);
static int omap1_set_uart_rate(struct clk * clk, unsigned long rate);
-static void omap1_uart_recalc(struct clk * clk);
+static void omap1_uart_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
static int omap1_clk_enable_uart_functional(struct clk * clk);
static void omap1_clk_disable_uart_functional(struct clk * clk);
static int omap1_set_ext_clk_rate(struct clk * clk, unsigned long rate);
/**
* omap2_get_dpll_rate - returns the current DPLL CLKOUT rate
* @clk: struct clk * of a DPLL
+ * @parent_rate: rate of the parent of the DPLL clock
*
* DPLLs can be locked or bypassed - basically, enabled or disabled.
* When locked, the DPLL output depends on the M and N values. When
* locked, or the appropriate bypass rate if the DPLL is bypassed, or 0
* if the clock @clk is not a DPLL.
*/
-u32 omap2_get_dpll_rate(struct clk *clk)
+u32 omap2_get_dpll_rate(struct clk *clk, unsigned long parent_rate)
{
long long dpll_clk;
u32 dpll_mult, dpll_div, v;
if (v == OMAP2XXX_EN_DPLL_LPBYPASS ||
v == OMAP2XXX_EN_DPLL_FRBYPASS)
- return clk->parent->rate;
+ return parent_rate;
} else if (cpu_is_omap34xx()) {
dpll_div = v & dd->div1_mask;
dpll_div >>= __ffs(dd->div1_mask);
- dpll_clk = (long long)clk->parent->rate * dpll_mult;
+ dpll_clk = (long long)parent_rate * dpll_mult;
do_div(dpll_clk, dpll_div + 1);
return dpll_clk;
* Used for clocks that have the same value as the parent clock,
* divided by some factor
*/
-void omap2_fixed_divisor_recalc(struct clk *clk)
+void omap2_fixed_divisor_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- WARN_ON(!clk->fixed_div);
+ unsigned long rate;
- clk->rate = clk->parent->rate / clk->fixed_div;
+ WARN_ON(!clk->fixed_div); /* XXX move this to init */
+
+ rate = parent_rate / clk->fixed_div;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
}
/**
* Used for clocks that are part of CLKSEL_xyz governed clocks.
* REVISIT: Maybe change to use clk->enable() functions like on omap1?
*/
-void omap2_clksel_recalc(struct clk *clk)
+void omap2_clksel_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
u32 div = 0;
+ unsigned long rate;
pr_debug("clock: recalc'ing clksel clk %s\n", clk->name);
if (div == 0)
return;
- if (clk->rate == (clk->parent->rate / div))
- return;
- clk->rate = clk->parent->rate / div;
+ rate = parent_rate / div;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
pr_debug("clock: new clock rate is %ld (div %d)\n", clk->rate, div);
}
#define omap2_clk_disable_unused NULL
#endif
-void omap2_clksel_recalc(struct clk *clk);
+void omap2_clksel_recalc(struct clk *clk, unsigned long new_parent_rate,
+ u8 rate_storage);
void omap2_init_clk_clkdm(struct clk *clk);
void omap2_init_clksel_parent(struct clk *clk);
u32 omap2_clksel_get_divisor(struct clk *clk);
u32 *new_div);
u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val);
u32 omap2_divisor_to_clksel(struct clk *clk, u32 div);
-void omap2_fixed_divisor_recalc(struct clk *clk);
+void omap2_fixed_divisor_recalc(struct clk *clk, unsigned long new_parent_rate,
+ u8 rate_storage);
long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate);
int omap2_clksel_set_rate(struct clk *clk, unsigned long rate);
-u32 omap2_get_dpll_rate(struct clk *clk);
+u32 omap2_get_dpll_rate(struct clk *clk, unsigned long parent_rate);
int omap2_wait_clock_ready(s16 prcm_mod, u16 idlest_reg, u32 cval,
const char *name);
void omap2_clk_prepare_for_reboot(void);
/**
* omap2xxx_clk_get_core_rate - return the CORE_CLK rate
* @clk: pointer to the combined dpll_ck + core_ck (currently "dpll_ck")
+ * @parent_rate: rate of the parent of the dpll_ck
*
* Returns the CORE_CLK rate. CORE_CLK can have one of three rate
* sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz
* struct clk *dpll_ck, which is a composite clock of dpll_ck and
* core_ck.
*/
-static u32 omap2xxx_clk_get_core_rate(struct clk *clk)
+static u32 omap2xxx_clk_get_core_rate(struct clk *clk,
+ unsigned long parent_rate)
{
long long core_clk;
u32 v;
- core_clk = omap2_get_dpll_rate(clk);
+ core_clk = omap2_get_dpll_rate(clk, parent_rate);
v = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
v &= OMAP24XX_CORE_CLK_SRC_MASK;
return core_clk;
}
+static unsigned long omap2xxx_clk_find_oppset_by_mpurate(unsigned long mpu_speed,
+ struct prcm_config **prcm)
+{
+ unsigned long found_speed = 0;
+ struct prcm_config *p;
+
+ p = *prcm;
+
+ for (p = rate_table; p->mpu_speed; p++) {
+ if (!(p->flags & cpu_mask))
+ continue;
+
+ if (p->xtal_speed != sys_ck.rate)
+ continue;
+
+ if (p->mpu_speed <= mpu_speed) {
+ found_speed = p->mpu_speed;
+ break;
+ }
+ }
+
+ return found_speed;
+}
+
static int omap2_enable_osc_ck(struct clk *clk)
{
prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, 0,
}
-static void omap2_dpllcore_recalc(struct clk *clk)
+static void omap2_dpllcore_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- clk->rate = omap2xxx_clk_get_core_rate(clk);
+ unsigned long rate;
+
+ rate = omap2xxx_clk_get_core_rate(clk, parent_rate);
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
}
static int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate)
int ret = -EINVAL;
local_irq_save(flags);
- cur_rate = omap2xxx_clk_get_core_rate(&dpll_ck);
+ cur_rate = omap2xxx_clk_get_core_rate(&dpll_ck, dpll_ck.parent->rate);
mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
mult &= OMAP24XX_CORE_CLK_SRC_MASK;
*
* Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set.
*/
-static void omap2_table_mpu_recalc(struct clk *clk)
+static void omap2_table_mpu_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- clk->rate = curr_prcm_set->mpu_speed;
+ struct prcm_config *prcm;
+ unsigned long mpurate;
+
+ mpurate = omap2xxx_clk_find_oppset_by_mpurate(parent_rate, &prcm);
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = mpurate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = mpurate;
}
/*
{
u32 cur_rate, done_rate, bypass = 0, tmp;
struct prcm_config *prcm;
- unsigned long found_speed = 0;
- unsigned long flags;
+ unsigned long flags, found_speed;
if (clk != &virt_prcm_set)
return -EINVAL;
- for (prcm = rate_table; prcm->mpu_speed; prcm++) {
- if (!(prcm->flags & cpu_mask))
- continue;
-
- if (prcm->xtal_speed != sys_ck.rate)
- continue;
-
- if (prcm->mpu_speed <= rate) {
- found_speed = prcm->mpu_speed;
- break;
- }
- }
-
+ found_speed = omap2xxx_clk_find_oppset_by_mpurate(rate, &prcm);
if (!found_speed) {
printk(KERN_INFO "Could not set MPU rate to %luMHz\n",
rate / 1000000);
}
curr_prcm_set = prcm;
- cur_rate = omap2xxx_clk_get_core_rate(&dpll_ck);
+ cur_rate = omap2xxx_clk_get_core_rate(&dpll_ck, dpll_ck.parent->rate);
if (prcm->dpll_speed == cur_rate / 2) {
omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
return div;
}
-static void omap2_osc_clk_recalc(struct clk *clk)
+static void omap2_osc_clk_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- clk->rate = omap2_get_apll_clkin() * omap2_get_sysclkdiv();
+ unsigned long rate;
+
+ /* XXX osc_ck on 2xxx currently is parentless */
+ rate = omap2_get_apll_clkin() * omap2_get_sysclkdiv();
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
}
-static void omap2_sys_clk_recalc(struct clk *clk)
+static void omap2_sys_clk_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- clk->rate = clk->parent->rate / omap2_get_sysclkdiv();
+ unsigned long rate;
+
+ rate = parent_rate / omap2_get_sysclkdiv();
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
}
/*
clk_init(&omap2_clk_functions);
- omap2_osc_clk_recalc(&osc_ck);
- omap2_sys_clk_recalc(&sys_ck);
+ omap2_osc_clk_recalc(&osc_ck, 0, CURRENT_RATE);
+ omap2_sys_clk_recalc(&sys_ck, sys_ck.parent->rate, CURRENT_RATE);
for (clkp = onchip_24xx_clks;
clkp < onchip_24xx_clks + ARRAY_SIZE(onchip_24xx_clks);
}
/* Check the MPU rate set by bootloader */
- clkrate = omap2xxx_clk_get_core_rate(&dpll_ck);
+ clkrate = omap2xxx_clk_get_core_rate(&dpll_ck, dpll_ck.parent->rate);
for (prcm = rate_table; prcm->mpu_speed; prcm++) {
if (!(prcm->flags & cpu_mask))
continue;
#include "cm-regbits-24xx.h"
#include "sdrc.h"
-static void omap2_table_mpu_recalc(struct clk *clk);
+static void omap2_table_mpu_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
static int omap2_select_table_rate(struct clk *clk, unsigned long rate);
static long omap2_round_to_table_rate(struct clk *clk, unsigned long rate);
-static void omap2_sys_clk_recalc(struct clk *clk);
-static void omap2_osc_clk_recalc(struct clk *clk);
-static void omap2_sys_clk_recalc(struct clk *clk);
-static void omap2_dpllcore_recalc(struct clk *clk);
+static void omap2_sys_clk_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap2_osc_clk_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap2_dpllcore_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
static int omap2_clk_fixed_enable(struct clk *clk);
static void omap2_clk_fixed_disable(struct clk *clk);
static int omap2_enable_osc_ck(struct clk *clk);
/**
* omap3_dpll_recalc - recalculate DPLL rate
* @clk: DPLL struct clk
+ * @parent_rate: rate of the DPLL's parent clock
+ * @rate_storage: flag indicating whether current or temporary rate is changing
*
* Recalculate and propagate the DPLL rate.
*/
-static void omap3_dpll_recalc(struct clk *clk)
+static void omap3_dpll_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
- clk->rate = omap2_get_dpll_rate(clk);
+ unsigned long rate;
+
+ rate = omap2_get_dpll_rate(clk, parent_rate);
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
}
/* _omap3_dpll_write_clken - write clken_bits arg to a DPLL's enable bits */
else
r = _omap3_noncore_dpll_lock(clk);
- if (!r)
- clk->rate = omap2_get_dpll_rate(clk);
-
return r;
}
if (!dd)
return -EINVAL;
- if (rate == omap2_get_dpll_rate(clk))
+ if (rate == omap2_get_dpll_rate(clk, clk->parent->rate))
return 0;
if (dd->bypass_clk->rate == rate &&
/**
* omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
* @clk: DPLL output struct clk
+ * @parent_rate: rate of the parent clock of @clk
+ * @rate_storage: flag indicating whether current or temporary rate is changing
*
* Using parent clock DPLL data, look up DPLL state. If locked, set our
* rate to the dpll_clk * 2; otherwise, just use dpll_clk.
*/
-static void omap3_clkoutx2_recalc(struct clk *clk)
+static void omap3_clkoutx2_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage)
{
const struct dpll_data *dd;
u32 v;
+ unsigned long rate;
struct clk *pclk;
/* Walk up the parents of clk, looking for a DPLL */
WARN_ON(!dd->enable_mask);
+ rate = parent_rate;
+
v = cm_read_mod_reg(pclk->prcm_mod, dd->control_reg) & dd->enable_mask;
v >>= __ffs(dd->enable_mask);
- if (v != OMAP3XXX_EN_DPLL_LOCKED)
- clk->rate = clk->parent->rate;
- else
- clk->rate = clk->parent->rate * 2;
+ if (v == OMAP3XXX_EN_DPLL_LOCKED)
+ rate *= 2;
+
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = rate;
}
/* Common clock code */
#include "prm.h"
#include "prm-regbits-34xx.h"
-static void omap3_dpll_recalc(struct clk *clk);
-static void omap3_clkoutx2_recalc(struct clk *clk);
+static void omap3_dpll_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
+static void omap3_clkoutx2_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
static void omap3_dpll_allow_idle(struct clk *clk);
static void omap3_dpll_deny_idle(struct clk *clk);
static u32 omap3_dpll_autoidle_read(struct clk *clk);
.parent = &sys_ck,
.prcm_mod = MPU_MOD,
.dpll_data = &dpll1_dd,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
+ ALWAYS_ENABLED | RECALC_ON_ENABLE,
.round_rate = &omap2_dpll_round_rate,
.set_rate = &omap3_noncore_dpll_set_rate,
.clkdm = { .name = "dpll1_clkdm" },
.parent = &sys_ck,
.prcm_mod = OMAP3430_IVA2_MOD,
.dpll_data = &dpll2_dd,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+ .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
+ RECALC_ON_ENABLE,
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
.round_rate = &omap2_dpll_round_rate,
.parent = &sys_ck,
.prcm_mod = PLL_MOD,
.dpll_data = &dpll3_dd,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+ .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
+ ALWAYS_ENABLED | RECALC_ON_ENABLE,
.round_rate = &omap2_dpll_round_rate,
.clkdm = { .name = "dpll3_clkdm" },
.recalc = &omap3_dpll_recalc,
.parent = &sys_ck,
.prcm_mod = PLL_MOD,
.dpll_data = &dpll4_dd,
- .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+ .flags = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
+ RECALC_ON_ENABLE,
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
.round_rate = &omap2_dpll_round_rate,
.parent = &sys_ck,
.prcm_mod = PLL_MOD,
.dpll_data = &dpll5_dd,
- .flags = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES,
+ .flags = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES |
+ RECALC_ON_ENABLE,
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
.round_rate = &omap2_dpll_round_rate,
return -EINVAL;
spin_lock_irqsave(&clockfw_lock, flags);
- if (arch_clock->clk_enable)
+ if (arch_clock->clk_enable) {
ret = arch_clock->clk_enable(clk);
+ if (ret == 0 && clk->flags & RECALC_ON_ENABLE) {
+ if (clk->recalc)
+ (*clk->recalc)(clk, clk->parent->rate,
+ CURRENT_RATE);
+ if (clk->flags & RATE_PROPAGATES)
+ propagate_rate(clk, CURRENT_RATE);
+ }
+ }
+
spin_unlock_irqrestore(&clockfw_lock, flags);
return ret;
goto out;
}
- if (arch_clock->clk_disable)
+ if (arch_clock->clk_disable) {
arch_clock->clk_disable(clk);
+ if (clk->flags & RECALC_ON_ENABLE) {
+ if (clk->recalc)
+ (*clk->recalc)(clk, clk->parent->rate,
+ CURRENT_RATE);
+ if (clk->flags & RATE_PROPAGATES)
+ propagate_rate(clk, CURRENT_RATE);
+ }
+ }
out:
spin_unlock_irqrestore(&clockfw_lock, flags);
ret = arch_clock->clk_set_rate(clk, rate);
if (ret == 0) {
if (clk->recalc)
- (*clk->recalc)(clk);
+ (*clk->recalc)(clk, clk->parent->rate,
+ CURRENT_RATE);
if (clk->flags & RATE_PROPAGATES)
- propagate_rate(clk);
+ propagate_rate(clk, CURRENT_RATE);
}
}
ret = arch_clock->clk_set_parent(clk, parent);
if (ret == 0) {
if (clk->recalc)
- (*clk->recalc)(clk);
+ (*clk->recalc)(clk, clk->parent->rate,
+ CURRENT_RATE);
if (clk->flags & RATE_PROPAGATES)
- propagate_rate(clk);
+ propagate_rate(clk, CURRENT_RATE);
}
}
__setup("mpurate=", omap_clk_setup);
/* Used for clocks that always have same value as the parent clock */
-void followparent_recalc(struct clk *clk)
+void followparent_recalc(struct clk *clk, unsigned long new_parent_rate,
+ u8 rate_storage)
{
- if (clk == NULL || IS_ERR(clk))
- return;
-
- clk->rate = clk->parent->rate;
+ if (rate_storage == CURRENT_RATE)
+ clk->rate = new_parent_rate;
+ else if (rate_storage == TEMP_RATE)
+ clk->temp_rate = new_parent_rate;
}
/* Propagate rate to children */
-void propagate_rate(struct clk * tclk)
+void propagate_rate(struct clk *tclk, u8 rate_storage)
{
struct clk *clkp;
+ unsigned long parent_rate = 0;
if (tclk == NULL || IS_ERR(tclk))
return;
list_for_each_entry(clkp, &clocks, node) {
if (likely(clkp->parent != tclk))
continue;
+
+ if (rate_storage == CURRENT_RATE)
+ parent_rate = tclk->rate;
+ else if (rate_storage == TEMP_RATE)
+ parent_rate = tclk->temp_rate;
+
if (clkp->recalc)
- clkp->recalc(clkp);
+ clkp->recalc(clkp, parent_rate, rate_storage);
if (clkp->flags & RATE_PROPAGATES)
- propagate_rate(clkp);
+ propagate_rate(clkp, rate_storage);
}
}
list_for_each_entry(clkp, &clocks, node) {
if (unlikely(!clkp->parent)) {
if (clkp->recalc)
- clkp->recalc(clkp);
+ clkp->recalc(clkp, 0, CURRENT_RATE);
if (clkp->flags & RATE_PROPAGATES)
- propagate_rate(clkp);
+ propagate_rate(clkp, CURRENT_RATE);
}
}
}
int id;
struct clk *parent;
unsigned long rate;
+ unsigned long temp_rate;
__u32 flags;
u32 enable_reg;
__u8 enable_bit;
__s8 usecount;
u8 idlest_bit;
- void (*recalc)(struct clk *);
+ void (*recalc)(struct clk *, unsigned long, u8);
int (*set_rate)(struct clk *, unsigned long);
long (*round_rate)(struct clk *, unsigned long);
void (*init)(struct clk *);
extern int clk_init(struct clk_functions *custom_clocks);
extern int clk_register(struct clk *clk);
extern void clk_unregister(struct clk *clk);
-extern void propagate_rate(struct clk *clk);
+extern void propagate_rate(struct clk *clk, u8 rate_storage);
extern void recalculate_root_clocks(void);
-extern void followparent_recalc(struct clk *clk);
+extern void followparent_recalc(struct clk *clk, unsigned long parent_rate,
+ u8 rate_storage);
extern void clk_allow_idle(struct clk *clk);
extern void clk_deny_idle(struct clk *clk);
extern int clk_get_usecount(struct clk *clk);
#define ENABLE_ON_INIT (1 << 11) /* Enable upon framework init */
#define INVERT_ENABLE (1 << 12) /* 0 enables, 1 disables */
#define WAIT_READY (1 << 13) /* wait for dev to leave idle */
-/* bits 14-20 are currently free */
+#define RECALC_ON_ENABLE (1 << 14) /* recalc/prop on ena/disa */
+/* bits 15-20 are currently free */
#define CLOCK_IN_OMAP310 (1 << 21)
#define CLOCK_IN_OMAP730 (1 << 22)
#define CLOCK_IN_OMAP1510 (1 << 23)
#define RATE_IN_24XX (RATE_IN_242X | RATE_IN_243X)
+/* rate_storage parameter flags */
+#define CURRENT_RATE 0
+#define TEMP_RATE 1
+
/*
* clk.prcm_mod flags (possible since only the top byte in clk.prcm_mod
* is significant)