Example #1
0
int __init omap2_clk_init(void)
{
	struct prcm_config *prcm;
	struct omap_clk *c;
	u32 clkrate;

	if (cpu_is_omap242x())
		cpu_mask = RATE_IN_242X;
	else if (cpu_is_omap2430())
		cpu_mask = RATE_IN_243X;

	clk_init(&omap2_clk_functions);

	for (c = omap24xx_clks; c < omap24xx_clks + ARRAY_SIZE(omap24xx_clks); c++)
		clk_init_one(c->lk.clk);

	osc_ck.rate = omap2_osc_clk_recalc(&osc_ck);
	propagate_rate(&osc_ck);
	sys_ck.rate = omap2_sys_clk_recalc(&sys_ck);
	propagate_rate(&sys_ck);

	for (c = omap24xx_clks; c < omap24xx_clks + ARRAY_SIZE(omap24xx_clks); c++)
		if (c->cpu & cpu_mask) {
			clkdev_add(&c->lk);
			clk_register(c->lk.clk);
		}

	/* Check the MPU rate set by bootloader */
	clkrate = omap2xxx_clk_get_core_rate(&dpll_ck);
	for (prcm = rate_table; prcm->mpu_speed; prcm++) {
		if (!(prcm->flags & cpu_mask))
			continue;
		if (prcm->xtal_speed != sys_ck.rate)
			continue;
		if (prcm->dpll_speed <= clkrate)
			 break;
	}
	curr_prcm_set = prcm;

	recalculate_root_clocks();

	printk(KERN_INFO "Clocking rate (Crystal/DPLL/MPU): "
	       "%ld.%01ld/%ld/%ld MHz\n",
	       (sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10,
	       (dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ;

	/*
	 * Only enable those clocks we will need, let the drivers
	 * enable other clocks as necessary
	 */
	clk_enable_init_clocks();

	/* Avoid sleeping sleeping during omap2_clk_prepare_for_reboot() */
	vclk = clk_get(NULL, "virt_prcm_set");
	sclk = clk_get(NULL, "sys_ck");

	return 0;
}
Example #2
0
File: clock.c Project: mozyg/kernel
/* Arch specific init */
static int __init omap3_clk_arch_init(void)
{
	struct vdd_prcm_config *vdd1_prcm;
	struct vdd_prcm_config *vdd2_prcm;
	u32 sys_clk_speed, mpu_speed, core_speed, l3_speed = 0;
	int div;

	printk("OMAP Clock subsystem initializing.\n");

	/* Lock DPLL5 */
	if (prcm_configure_dpll(DPLL5_PER2, -1, -1, -1))
		panic("FATAL ERROR: Unable to Configure DPLL5\n");
	if (prcm_enable_dpll(DPLL5_PER2))
		panic("FATAL ERROR: Unable to Lock DPLL5\n");
	omap3_get_crystal_rate(&osc_sys_ck);
	omap3_update_sources();

	sys_clk_speed = prcm_get_system_clock_speed() * 1000;
	prcm_get_processor_speed(DOM_MPU, &mpu_speed);
	mpu_speed = mpu_speed * 1000;
	prcm_get_dpll_rate((&core_ck)->prcmid, &core_speed);
	core_speed = core_speed * 1000;
	prcm_clksel_get_divider((&l3_ck)->prcmid, &div);
	if (div != 0)
		l3_speed = core_speed / div;
	else
		printk(KERN_ERR"Error: Divider for L3 returned 0 in omap3_clk"
					"_arch_init\n");

	pr_debug("System clock speed: %u, mpu speed : %u, l3_speed : %u"
				"\n", sys_clk_speed, mpu_speed, l3_speed);

	for (vdd1_prcm = vdd1_rate_table+MAX_VDD1_OPP; vdd1_prcm->speed;
	vdd1_prcm--) {
		pr_debug("%lu\n", vdd1_prcm->speed);
		if (vdd1_prcm->speed <= mpu_speed)
			break;
	}
	curr_vdd1_prcm_set = vdd1_prcm;

	for (vdd2_prcm = vdd2_rate_table+MAX_VDD2_OPP; vdd2_prcm->speed;
		vdd2_prcm++) {
		pr_debug("%lu\n", vdd2_prcm->speed);
		if (vdd2_prcm->speed <= l3_speed)
			break;
	}
	curr_vdd2_prcm_set = vdd2_prcm;

	propagate_rate(&osc_sys_ck);	/* update main root fast */
	propagate_rate(&omap_32k_fck);	/* update main root slow */
	propagate_rate(&sysaltck);	/* update alt ck tree */

	pr_debug("Rate propagation done for all clocks\n");
	return 0;
}
Example #3
0
/**
 * omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
 * @clk: DPLL output struct clk
 *
 * 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)
{
    const struct dpll_data *dd;
    u32 v;
    struct clk *pclk;

    /* Walk up the parents of clk, looking for a DPLL */
    pclk = clk->parent;
    while (pclk && !pclk->dpll_data)
        pclk = pclk->parent;

    /* clk does not have a DPLL as a parent? */
    WARN_ON(!pclk);

    dd = pclk->dpll_data;

    WARN_ON(!dd->control_reg || !dd->enable_mask);

    v = __raw_readl(dd->control_reg) & dd->enable_mask;
    v >>= __ffs(dd->enable_mask);
    if (v != DPLL_LOCKED)
        clk->rate = clk->parent->rate;
    else
        clk->rate = clk->parent->rate * 2;

    if (clk->flags & RATE_PROPAGATES)
        propagate_rate(clk);
}
Example #4
0
/*
 * _ti814x_adpll_check_and_set_rate - check if given clock's parent is an ADPLL
 *  and check if it is allowed to change the rate of the ADPLL based on id,
 *  Set rate if it is a clock not an ADPLL and propagate rate down tree
 * @clk - pointer to struct clk
 * @dpll_setrate - output variable indicating whether rate can be set
 * @rate - rate to be set
 */
static int _ti814x_adpll_check_and_set_rate(struct clk *clk,
					int *dpll_setrate,
					unsigned long rate)
{
	struct dpll_data *dd;
	struct clk *dclk = clk->parent;
	int ret = 0;

	*dpll_setrate = 0;

	if (dclk->dpll_data) {
		dd = dclk->dpll_data;
		if (((dd->dpll_id == TI814X_ARM_DPLL_ID) ||
				(dd->dpll_id == TI814X_DDR_DPLL_ID)))
			return -EINVAL;
		*dpll_setrate = 1;
	} else if (dclk->set_rate) {
		if (dclk->usecount > 1) {
			pr_warn("clock: %s,\'s parent %s is already in use, can't"
				" change rate\n", clk->name, dclk->name);
			return -EBUSY; //?EWB
		}
		ret = dclk->set_rate(dclk, rate);
		if (!ret) {
			/* re-set divider based on parent rate */
			ret = omap2_clksel_set_rate(clk, dclk->rate);
			if (ret) {
				pr_err("clock: failed to reset the divider\n");
				return ret;
			}
			propagate_rate(dclk);
		}
	}
	return ret;
}
Example #5
0
/* Recalculate SYST_CLK */
static void omap2_sys_clk_recalc(struct clk * clk)
{
    u32 div = PRCM_CLKSRC_CTRL;
    div &= (1 << 7) | (1 << 6);    /* Test if ext clk divided by 1 or 2 */
    div >>= clk->rate_offset;
    clk->rate = (clk->parent->rate / div);
    propagate_rate(clk);
}
Example #6
0
File: clock.c Project: 274914765/C
/*
 * Used for clocks that have the same value as the parent clock,
 * divided by some factor
 */
void omap2_fixed_divisor_recalc(struct clk *clk)
{
    WARN_ON(!clk->fixed_div);

    clk->rate = clk->parent->rate / clk->fixed_div;

    if (clk->flags & RATE_PROPAGATES)
        propagate_rate(clk);
}
Example #7
0
File: clock.c Project: 274914765/C
int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
{
    void __iomem *src_addr;
    u32 field_val, field_mask, reg_val, parent_div;

    if (unlikely(clk->flags & CONFIG_PARTICIPANT))
        return -EINVAL;

    if (!clk->clksel)
        return -EINVAL;

    field_val = omap2_clksel_get_src_field(&src_addr, new_parent,
                           &field_mask, clk, &parent_div);
    if (src_addr == 0)
        return -EINVAL;

    if (clk->usecount > 0)
        _omap2_clk_disable(clk);

    /* Set new source value (previous dividers if any in effect) */
    reg_val = __raw_readl(src_addr) & ~field_mask;
    reg_val |= (field_val << __ffs(field_mask));
    __raw_writel(reg_val, src_addr);
    wmb();

    if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) {
        __raw_writel(OMAP24XX_VALID_CONFIG, OMAP24XX_PRCM_CLKCFG_CTRL);
        wmb();
    }

    if (clk->usecount > 0)
        _omap2_clk_enable(clk);

    clk->parent = new_parent;

    /* CLKSEL clocks follow their parents' rates, divided by a divisor */
    clk->rate = new_parent->rate;

    if (parent_div > 0)
        clk->rate /= parent_div;

    pr_debug("clock: set parent of %s to %s (new rate %ld)\n",
         clk->name, clk->parent->name, clk->rate);

    if (unlikely(clk->flags & RATE_PROPAGATES))
        propagate_rate(clk);

    return 0;
}
Example #8
0
File: clock.c Project: mozyg/kernel
/* Calls appropriate PRCM API to calculate rate of clock */
static void omap3_clk_recalc(struct clk *clk)
{
	u32 parent_rate, divider, ret, rate;
	parent_rate = clk->parent->rate;
	ret = PRCM_PASS;

	pr_debug("Clock name: %s\n", clk->name);

	if (clk == &sys_ck) {
		clk->rate = prcm_get_system_clock_speed() * 1000;
		ret = PRCM_PASS;
	}

	if (clk == &mpu_ck) {
		ret = prcm_get_processor_speed(clk->prcmid, &rate);
		clk->rate = rate * 1000;
	}

	if (clk == &iva2_ck) {
		ret = prcm_get_processor_speed(clk->prcmid, &rate);
		clk->rate = rate * 1000;
	}

	if (clk->flags & DPLL_OUTPUT) {
		ret = prcm_get_dpll_rate(clk->prcmid, &rate);
		if (ret == PRCM_PASS)
			clk->rate = rate * 1000;
	}

	if (clk->flags & RATE_CKCTL) {
		ret = prcm_clksel_get_divider(clk->prcmid, &divider);
		pr_debug("Divider: %d\n", divider);
		if (ret == PRCM_PASS)
			clk->rate = clk->parent->rate / divider;
	}

	if (ret != PRCM_PASS)
		printk(KERN_ERR "Error in clk_recalc: %d,%s\n", ret, clk->name);

	pr_debug("Rate: %lu\n", clk->rate);

	if (clk->flags & RATE_PROPAGATES)
		propagate_rate(clk);
}
Example #9
0
File: clock.c Project: 274914765/C
/*
 * 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)
{
    u32 div = 0;

    pr_debug("clock: recalc'ing clksel clk %s\n", clk->name);

    div = omap2_clksel_get_divisor(clk);
    if (div == 0)
        return;

    if (unlikely(clk->rate == clk->parent->rate / div))
        return;
    clk->rate = clk->parent->rate / div;

    pr_debug("clock: new clock rate is %ld (div %d)\n", clk->rate, div);

    if (unlikely(clk->flags & RATE_PROPAGATES))
        propagate_rate(clk);
}
Example #10
0
File: clock.c Project: 274914765/C
/* Set the clock rate for a clock source */
int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
{
    int ret = -EINVAL;

    pr_debug("clock: set_rate for clock %s to rate %ld\n", clk->name, rate);

    /* CONFIG_PARTICIPANT clocks are changed only in sets via the
       rate table mechanism, driven by mpu_speed  */
    if (clk->flags & CONFIG_PARTICIPANT)
        return -EINVAL;

    /* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */
    if (clk->set_rate != 0)
        ret = clk->set_rate(clk, rate);

    if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
        propagate_rate(clk);

    return ret;
}
Example #11
0
static int pll160_set_rate(struct clk *clk, u32 rate)
{
	u32 tmp_reg, tmp_m, tmp_2p, i;
	u32 parent_rate;
	int ret = -EINVAL;

	parent_rate = clk->parent->rate;

	if (!parent_rate)
		goto out;

	/* set direct run for ARM or disable output for others  */
	clk_reg_disable(clk);

	/* disable source input as well (ignored for ARM) */
	clk_reg_disable1(clk);

	tmp_reg = __raw_readl(clk->scale_reg);
	tmp_reg &= ~0x1ffff;	/*clear all settings, power down */
	__raw_writel(tmp_reg, clk->scale_reg);

	rate -= rate % parent_rate;	/*round down the input */

	if (rate > PLL160_MAX_FCCO)
		rate = PLL160_MAX_FCCO;

	if (!rate) {
		clk->rate = 0;
		ret = 0;
		goto out;
	}

	clk_reg_enable1(clk);
	tmp_reg = __raw_readl(clk->scale_reg);

	if (rate == parent_rate) {
		/*enter direct bypass mode */
		tmp_reg |= ((1 << 14) | (1 << 15));
		__raw_writel(tmp_reg, clk->scale_reg);
		clk->rate = parent_rate;
		clk_reg_enable(clk);
		ret = 0;
		goto out;
	}

	i = 0;
	for (tmp_2p = 1; tmp_2p < 16; tmp_2p <<= 1) {
		if (rate * tmp_2p >= PLL160_MIN_FCCO)
			break;
		i++;
	}

	if (tmp_2p > 1)
		tmp_reg |= ((i - 1) << 11);
	else
		tmp_reg |= (1 << 14);	/*direct mode, no divide */

	tmp_m = rate * tmp_2p;
	tmp_m /= parent_rate;

	tmp_reg |= (tmp_m - 1) << 1;	/*calculate M */
	tmp_reg |= (1 << 16);	/*power up PLL */
	__raw_writel(tmp_reg, clk->scale_reg);

	if (clk_wait_for_pll_lock(clk) < 0) {
		clk_reg_disable(clk);
		clk_reg_disable1(clk);

		tmp_reg = __raw_readl(clk->scale_reg);
		tmp_reg &= ~0x1ffff;	/*clear all settings, power down */
		__raw_writel(tmp_reg, clk->scale_reg);
		clk->rate = 0;
		ret = -EFAULT;
		goto out;
	}

	clk->rate = (tmp_m * parent_rate) / tmp_2p;

	if (clk->flags & RATE_PROPAGATES)
		propagate_rate(clk);

	clk_reg_enable(clk);
	ret = 0;

out:
	return ret;
}
Example #12
0
/**
 * ti814x_clksel_set_rate() - program clock rate in hardware
 * @clk: struct clk * to program rate
 * @rate: target rate to program
 *
 * This function is intended to be called by the audio and some
 * of the coprocessors. Program @clk's rate to @rate in the hardware.
 * The clock must be enabled, or -EPERM is returned
 * If multiple drivers are using the clock, returns -EBUSY with error message.
 * Returns -EINVAL upon error, or 0 upon success.
 */
int ti814x_clksel_set_rate(struct clk *clk, unsigned long rate)
{
	struct clk *pclk;
	struct clk *dclk;
	int ret, dpll_setrate = 0;

	if (clk->usecount == 0) {
		pr_err("clock: Enable %s before setting rate\n",
			clk->name);
		return -EPERM;
	}
	if (clk->usecount > 1) {
		pr_warn("clock: %s usecount(%d) > 1 - can't change the rate\n",
			clk->name, clk->usecount);
		return -EBUSY; //?EWB
	}

	pclk = clk->parent;
	if (pclk->usecount > 1) {
		pr_warn("clock: %s's parent %s usecount(%d) > 1 -"
			"can't change the rate\n", clk->name,
			pclk->name, pclk->usecount);
		return -EBUSY; //?EWB
	}

	dclk = pclk->parent;
	/* check the dividers in parent clock */
	ret = pclk->set_rate(pclk, rate);
	if (!ret) {
		propagate_rate(pclk);
	} else {

		ret = _ti814x_adpll_check_and_set_rate(pclk,
						&dpll_setrate,
						rate);

		if (ret && dpll_setrate)
			goto failed_set_divider;
		else if (ret) {
			pclk = dclk;
			dclk = dclk->parent;
			ret = _ti814x_adpll_check_and_set_rate(pclk,
							&dpll_setrate,
							rate);
			if (ret && dpll_setrate)
				goto failed_set_divider;
		}
	}
	if (dpll_setrate) {
		if (dclk->usecount > 1) {
			pr_warn("clock: %s's parent %s usecount(%d) > 1"
				" - can't change the rate\n", pclk->name,
				dclk->name, dclk->usecount);
			return -EBUSY; //?EWB
		}

		/* Changing the DPLL rate */
		ret = dclk->set_rate(dclk, rate);
		if (ret) {
			pr_err("clock: failed to set dpll rate\n");
			return -EINVAL;
		}

		/* reset divider */
		ret = omap2_clksel_set_rate(pclk, dclk->rate);
		if (ret) {
			pr_err("clock: failed to reset the divider\n");
			return -EINVAL;
		}
		propagate_rate(dclk);
	}
	return 0;

failed_set_divider:
	pr_err("clock: failed to set divider\n");
	return ret;
}
Example #13
0
static void omap2_sys_clk_recalc(struct clk *clk)
{
    clk->rate = clk->parent->rate / omap2_get_sysclkdiv();
    propagate_rate(clk);
}
Example #14
0
static void omap2_osc_clk_recalc(struct clk *clk)
{
    clk->rate = omap2_get_apll_clkin() * omap2_get_sysclkdiv();
    propagate_rate(clk);
}
Example #15
0
static void omap2_dpll_recalc(struct clk *clk)
{
    clk->rate = omap2_get_dpll_rate_24xx(clk);

    propagate_rate(clk);
}
Example #16
0
File: clock.c Project: mozyg/kernel
/* Make the rate same as that of the parent.
 If the rate propagates, call propagate_rate*/
static void omap3_followparent_recalc(struct clk *clk)
{
	followparent_recalc(clk);
	if (clk->flags & RATE_PROPAGATES)
		propagate_rate(clk);
}
Example #17
0
File: clock.c Project: mozyg/kernel
static void omap3_propagate_rate(struct clk *clk)
{
	propagate_rate(clk);
}
Example #18
0
/**
 * ti816x_clksel_set_rate() - program clock rate in hardware
 * @clk: struct clk * to program rate
 * @rate: target rate to program
 *
 * This function is intended to be called by the audio and some
 * of the coprocessors. Program @clk's rate to @rate in the hardware.
 * The clock should be disabled when this happens, otherwise setrate
 * will fail, because this is treated as clock being used. If multiple
 * drivers are using the clock, even though it is trying to change
 * then this return -EINVAL with error message. Returns -EINVAL upon
 * error, or 0 upon success.
 */
int ti816x_clksel_set_rate(struct clk *clk, unsigned long rate)
{
	struct clk *pclk;
	struct clk *fclk;
	struct fapll_data *fd;
	int ret, fapll_sr = 0;

	if (clk->usecount == 0) {
		pr_err("clock: Enable the clock '%s' before setting rate\n",
			clk->name);
		return -EINVAL;
	}
	if (clk->usecount > 1) {
		pr_err("clock: '%s' clock is in use can't change the rate "
			"usecount = '%d'", clk->name, clk->usecount);
		return -EBUSY;
	}

	pclk = clk->parent;
	if (pclk->usecount > 1) {
		pr_err("clock: '%s' clock's parent '%s' is in use can't"
			" change the rate usecount = %d", clk->name,
			pclk->name, pclk->usecount);
		return -EBUSY;
	}

	fclk = pclk->parent;
	/* check the dividers in parent clock */
	ret = pclk->set_rate(pclk, rate);
	if (!ret)
		propagate_rate(pclk);
	else {
		if (!fclk->fapll_data)
			goto failed_set_divider;

		fd = fclk->fapll_data;
		if (!((fd->fapll_id == 1) || (fd->fapll_id == 4)))
			goto failed_set_divider;

		if ((fd->fapll_id == 1) && (fclk->synthesizer_id == 2))
			goto failed_set_divider;

		fapll_sr = 1;
	}

	if (fapll_sr) {
		if (fclk->usecount > 1) {
			pr_err("clock: %s, parent %s is already in use, change"
				" parent\n", pclk->name, pclk->parent->name);
			return -EINVAL;
		}

		/* Changing the FAPLL synthesizer rate */
		ret = fclk->set_rate(fclk, rate);
		if (ret) {
			pr_err("clock: failed to set fapll rate\n");
			return -EINVAL;
		}

		/* reset divider */
		ret = omap2_clksel_set_rate(pclk, fclk->rate);
		if (ret) {
			pr_err("clock: failed to reset the divider\n");
			return -EINVAL;
		}
		propagate_rate(fclk);
	}
	return 0;

failed_set_divider:
	pr_err("clock: failed to set divider\n");
	return -EINVAL;
}
Example #19
0
static int set_cpu_freq(int wp)
{
	int arm_podf;
	int podf;
	int vinc = 0;
	int ret = 0;
	int org_cpu_rate;
	unsigned long rate = 0;
	int gp_volt = 0;
	u32 reg;
	u32 reg1;
	unsigned long flags;

	if (cpu_wp_tbl[wp].pll_rate != cpu_wp_tbl[old_wp].pll_rate) {
		org_cpu_rate = clk_get_rate(cpu_clk);
		rate = cpu_wp_tbl[wp].cpu_rate;

		if (org_cpu_rate == rate)
			return ret;

		gp_volt = cpu_wp_tbl[wp].cpu_voltage;
		if (gp_volt == 0)
			return ret;

		/*Set the voltage for the GP domain. */
		if (rate > org_cpu_rate) {
			ret = regulator_set_voltage(core_regulator, gp_volt,
						    gp_volt);
			if (ret < 0) {
				printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE\n");
				return ret;
			}
			udelay(dvfs_data->delay_time);
		}
		atomic_spin_lock_irqsave(&mxc_dvfs_core_lock, flags);
		/* PLL_RELOCK, set ARM_FREQ_SHIFT_DIVIDER */
		reg = __raw_readl(ccm_base + dvfs_data->ccm_cdcr_offset);
		reg &= 0xFFFFFFFB;
		__raw_writel(reg, ccm_base + dvfs_data->ccm_cdcr_offset);

		setup_pll();
		/* START the GPC main control FSM */
		/* set VINC */
		reg = __raw_readl(gpc_base + dvfs_data->gpc_vcr_offset);
		reg &= ~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK |
			 MXC_GPCVCR_VCNT_MASK);

		if (rate > org_cpu_rate)
			reg |= 1 << MXC_GPCVCR_VINC_OFFSET;

		reg |= (1 << MXC_GPCVCR_VCNTU_OFFSET) |
		       (1 << MXC_GPCVCR_VCNT_OFFSET);
		__raw_writel(reg, gpc_base + dvfs_data->gpc_vcr_offset);

		reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset);
		reg &= ~(MXC_GPCCNTR_ADU_MASK | MXC_GPCCNTR_FUPD_MASK);
		reg |= MXC_GPCCNTR_FUPD;
		reg |= MXC_GPCCNTR_ADU;
		__raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset);

		reg |= MXC_GPCCNTR_STRT;
		__raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset);
		while (__raw_readl(gpc_base + dvfs_data->gpc_cntr_offset)
				& 0x4000)
			udelay(10);
		atomic_spin_unlock_irqrestore(&mxc_dvfs_core_lock, flags);

		if (rate < org_cpu_rate) {
			ret = regulator_set_voltage(core_regulator,
						    gp_volt, gp_volt);
			if (ret < 0) {
				printk(KERN_DEBUG
				       "COULD NOT SET GP VOLTAGE!!!!\n");
				return ret;
			}
			udelay(dvfs_data->delay_time);
		}
		clk_set_rate(cpu_clk, rate);
	} else {
		podf = cpu_wp_tbl[wp].cpu_podf;
		gp_volt = cpu_wp_tbl[wp].cpu_voltage;

		/* Change arm_podf only */
		/* set ARM_FREQ_SHIFT_DIVIDER */
		reg = __raw_readl(ccm_base + dvfs_data->ccm_cdcr_offset);
		reg &= 0xFFFFFFFB;
		reg |= 1 << 2;
		__raw_writel(reg, ccm_base + dvfs_data->ccm_cdcr_offset);

		/* Get ARM_PODF */
		reg = __raw_readl(ccm_base + dvfs_data->ccm_cacrr_offset);
		arm_podf = reg & 0x07;
		if (podf == arm_podf) {
			printk(KERN_DEBUG
			       "No need to change freq and voltage!!!!\n");
			return 0;
		}

		/* Check if FSVAI indicate freq up */
		if (podf < arm_podf) {
			ret = regulator_set_voltage(core_regulator,
						    gp_volt, gp_volt);
			if (ret < 0) {
				printk(KERN_DEBUG
				       "COULD NOT SET GP VOLTAGE!!!!\n");
				return 0;
			}
			udelay(dvfs_data->delay_time);
			vinc = 1;
		} else {
			vinc = 0;
		}

		arm_podf = podf;
		/* Set ARM_PODF */
		reg &= 0xFFFFFFF8;
		reg |= arm_podf;

		reg1 = __raw_readl(ccm_base + dvfs_data->ccm_cdhipr_offset);
		if ((reg1 & 0x00010000) == 0)
			__raw_writel(reg,
				ccm_base + dvfs_data->ccm_cacrr_offset);
		else {
			printk(KERN_DEBUG "ARM_PODF still in busy!!!!\n");
			return 0;
		}

		/* START the GPC main control FSM */
		reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset);
		reg |= MXC_GPCCNTR_FUPD;
		/* ADU=1, select ARM domain */
		reg |= MXC_GPCCNTR_ADU;
		__raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset);
		/* set VINC */
		reg = __raw_readl(gpc_base + dvfs_data->gpc_vcr_offset);
		reg &=
		    ~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK |
		      MXC_GPCVCR_VCNT_MASK);
		reg |= (1 << MXC_GPCVCR_VCNTU_OFFSET) |
		    (100 << MXC_GPCVCR_VCNT_OFFSET) |
		    (vinc << MXC_GPCVCR_VINC_OFFSET);
		__raw_writel(reg, gpc_base + dvfs_data->gpc_vcr_offset);

		reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset);
		reg &= (~(MXC_GPCCNTR_ADU | MXC_GPCCNTR_FUPD));
		reg |= MXC_GPCCNTR_ADU | MXC_GPCCNTR_FUPD | MXC_GPCCNTR_STRT;
		__raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset);

		/* Wait for arm podf Enable */
		while ((__raw_readl(gpc_base + dvfs_data->gpc_cntr_offset) &
			MXC_GPCCNTR_STRT) == MXC_GPCCNTR_STRT) {
			printk(KERN_DEBUG "Waiting arm_podf enabled!\n");
			udelay(10);
		}

		if (vinc == 0) {
			ret = regulator_set_voltage(core_regulator,
						    gp_volt, gp_volt);
			if (ret < 0) {
				printk(KERN_DEBUG
				       "COULD NOT SET GP VOLTAGE!!!!\n");
				return ret;
			}
			udelay(dvfs_data->delay_time);
		}

		propagate_rate(pll1_sw_clk);
		/* Clear the ARM_FREQ_SHIFT_DIVIDER */
		reg = __raw_readl(ccm_base + dvfs_data->ccm_cdcr_offset);
		reg &= 0xFFFFFFFB;
		__raw_writel(reg, ccm_base + dvfs_data->ccm_cdcr_offset);
	}
#if defined(CONFIG_CPU_FREQ)
		cpufreq_trig_needed = 1;
#endif
	old_wp = wp;

	return ret;
}