/** * omap3_noncore_dpll_enable - instruct a DPLL to enter bypass or lock mode * @clk: pointer to a DPLL struct clk * * Instructs a non-CORE DPLL to enable, e.g., to enter bypass or lock. * The choice of modes depends on the DPLL's programmed rate: if it is * the same as the DPLL's parent clock, it will enter bypass; * otherwise, it will enter lock. This code will wait for the DPLL to * indicate readiness before returning, unless the DPLL takes too long * to enter the target state. Intended to be used as the struct clk's * enable function. If DPLL3 was passed in, or the DPLL does not * support low-power stop, or if the DPLL took too long to enter * bypass or lock, return -EINVAL; otherwise, return 0. */ static int omap3_noncore_dpll_enable(struct clk *clk) { int r; struct dpll_data *dd; if (clk == &dpll3_ck) return -EINVAL; dd = clk->dpll_data; if (!dd) return -EINVAL; if (clk->rate == dd->bypass_clk->rate) r = _omap3_noncore_dpll_bypass(clk); else r = _omap3_noncore_dpll_lock(clk); return r; }
/* * omap3_noncore_dpll_program - set non-core DPLL M,N values directly * @clk: struct clk * of DPLL to set * @m: DPLL multiplier to set * @n: DPLL divider to set * @freqsel: FREQSEL value to set * * Program the DPLL with the supplied M, N values, and wait for the DPLL to * lock.. Returns -EINVAL upon error, or 0 upon success. */ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel) { struct dpll_data *dd = clk->dpll_data; u32 v; /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ _omap3_noncore_dpll_bypass(clk); /* Set jitter correction */ v = __raw_readl(dd->control_reg); v &= ~dd->freqsel_mask; v |= freqsel << __ffs(dd->freqsel_mask); __raw_writel(v, dd->control_reg); /* Set DPLL multiplier, divider */ v = __raw_readl(dd->mult_div1_reg); v &= ~(dd->mult_mask | dd->div1_mask); v |= m << __ffs(dd->mult_mask); v |= (n - 1) << __ffs(dd->div1_mask); if (dd->jtype) { u8 dco, sd_div; lookup_dco_sddiv(clk, &dco, &sd_div, m, n); v &= ~(dd->dco_sel_mask | dd->sd_div_mask); v |= dco << __ffs(dd->dco_sel_mask); v |= sd_div << __ffs(dd->sd_div_mask); } __raw_writel(v, dd->mult_div1_reg); /* We let the clock framework set the other output dividers later */ /* REVISIT: Set ramp-up delay? */ _omap3_noncore_dpll_lock(clk); return 0; }
/** * omap3_noncore_dpll_set_rate - set non-core DPLL rate * @clk: struct clk * of DPLL to set * @rate: rounded target rate * * Set the DPLL CLKOUT to the target rate. If the DPLL can enter * low-power bypass, and the target rate is the bypass source clock * rate, then configure the DPLL for bypass. Otherwise, round the * target rate if it hasn't been done already, then program and lock * the DPLL. Returns -EINVAL upon error, or 0 upon success. */ int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) { struct clk *new_parent = NULL; u16 freqsel = 0; struct dpll_data *dd; int ret; unsigned long orig_rate = 0; if (!clk || !rate) return -EINVAL; dd = clk->dpll_data; if (!dd) return -EINVAL; if (rate == omap2_get_dpll_rate(clk)) return 0; /* * Ensure both the bypass and ref clocks are enabled prior to * doing anything; we need the bypass clock running to reprogram * the DPLL. */ omap2_clk_enable(dd->clk_bypass); omap2_clk_enable(dd->clk_ref); if (dd->clk_bypass->rate == rate && (clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS))) { pr_debug("clock: %s: set rate: entering bypass.\n", clk->name); ret = _omap3_noncore_dpll_bypass(clk); if (!ret) new_parent = dd->clk_bypass; } else { /* * On 4460, the MPU clk for frequencies higher than 1Ghz * is sourced from CLKOUTX2_M3, instead of CLKOUT_M2, while * value of M3 is fixed to 1. Hence for frequencies higher * than 1 Ghz, lock the DPLL at half the rate so the * CLKOUTX2_M3 then matches the requested rate. */ if (cpu_is_omap4460() && !strcmp(clk->name, "dpll_mpu_ck") && (rate > 1000000000)) { orig_rate = rate; rate = rate/2; } if (dd->last_rounded_rate != rate) rate = clk->round_rate(clk, rate); if (dd->last_rounded_rate == 0) return -EINVAL; /* No freqsel on OMAP4 and OMAP3630 */ if (!cpu_is_omap44xx() && !cpu_is_omap3630()) { freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); if (!freqsel) WARN_ON(1); } /* Set the rate back to original for book keeping*/ if (orig_rate) rate = orig_rate; pr_debug("clock: %s: set rate: locking rate to %lu.\n", clk->name, rate); ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m, dd->last_rounded_n, freqsel, orig_rate); if (!ret) new_parent = dd->clk_ref; } if (!ret) { /* * Switch the parent clock in the heirarchy, and make sure * that the new parent's usecount is correct. Note: we * enable the new parent before disabling the old to avoid * any unnecessary hardware disable->enable transitions. */ if (clk->usecount) { omap2_clk_enable(new_parent); omap2_clk_disable(clk->parent); } clk_reparent(clk, new_parent); clk->rate = rate; } omap2_clk_disable(dd->clk_ref); omap2_clk_disable(dd->clk_bypass); return 0; }
/* * _omap3_noncore_dpll_program - set non-core DPLL M,N values directly * @clk: struct clk * of DPLL to set * @m: DPLL multiplier to set * @n: DPLL divider to set * @freqsel: FREQSEL value to set * * Program the DPLL with the supplied M, N values, and wait for the DPLL to * lock.. Returns -EINVAL upon error, or 0 upon success. */ static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel, unsigned long orig_rate) { struct dpll_data *dd = clk->dpll_data; u8 dco, sd_div; u32 v; /* * On OMAP4460, to obtain MPU DPLL frequency higher * than 1GHz, DCC (Duty Cycle Correction) needs to * be enabled. * Also the interconnect frequency to EMIF should * be switched between MPU clk divide by 4 (for * frequencies higher than 920Mhz) and MPU clk divide * by 2 (for frequencies lower than or equal to 920Mhz) * Lastly the async bridge to ABE must be MPU clk divide * by 8 for MPU clk > 748Mhz and MPU clk divide by 4 * for lower frequencies. * TODO: For now use a strcmp, but need to find a * better way to identify the MPU dpll. */ if (cpu_is_omap4460() && !strcmp(clk->name, "dpll_mpu_ck")) { /* DCC control */ v = __raw_readl(dd->mult_div1_reg); if ((orig_rate <= 1000000000) && (v & OMAP4460_DCC_EN_MASK)) { v &= ~OMAP4460_DCC_EN_MASK; /* Disable DCC */ __raw_writel(v, dd->mult_div1_reg); } } /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ _omap3_noncore_dpll_bypass(clk); /* * Set jitter correction. No jitter correction for OMAP4 and 3630 * since freqsel field is no longer present */ if (!cpu_is_omap44xx() && !cpu_is_omap3630()) { v = __raw_readl(dd->control_reg); v &= ~dd->freqsel_mask; v |= freqsel << __ffs(dd->freqsel_mask); __raw_writel(v, dd->control_reg); } /* Set DPLL multiplier, divider */ v = __raw_readl(dd->mult_div1_reg); v &= ~(dd->mult_mask | dd->div1_mask); v |= m << __ffs(dd->mult_mask); v |= (n - 1) << __ffs(dd->div1_mask); /* Configure dco and sd_div for dplls that have these fields */ if (dd->dco_mask) { _lookup_dco(clk, &dco, m, n); v &= ~(dd->dco_mask); v |= dco << __ffs(dd->dco_mask); } if (dd->sddiv_mask) { _lookup_sddiv(clk, &sd_div, m, n); v &= ~(dd->sddiv_mask); v |= sd_div << __ffs(dd->sddiv_mask); } __raw_writel(v, dd->mult_div1_reg); /* We let the clock framework set the other output dividers later */ /* REVISIT: Set ramp-up delay? */ _omap3_noncore_dpll_lock(clk); if (cpu_is_omap4460() && !strcmp(clk->name, "dpll_mpu_ck")) { /* DCC control */ if (orig_rate > 1000000000) { v &= ~OMAP4460_DCC_COUNT_MAX_MASK; v |= (5 << OMAP4460_DCC_COUNT_MAX_SHIFT); __raw_writel(v, dd->mult_div1_reg); v |= OMAP4460_DCC_EN_MASK; /* Enable DCC */ __raw_writel(v, dd->mult_div1_reg); } /* EMIF/ABE clock rate control */ v = __raw_readl(OMAP4430_CM_MPU_MPU_CLKCTRL); if (orig_rate > 920000000) v |= OMAP4460_CLKSEL_EMIF_DIV_MODE_MASK; else v &= ~OMAP4460_CLKSEL_EMIF_DIV_MODE_MASK; if (orig_rate > 748000000) v |= OMAP4460_CLKSEL_ABE_DIV_MODE_MASK; else v &= ~OMAP4460_CLKSEL_ABE_DIV_MODE_MASK; __raw_writel(v, OMAP4430_CM_MPU_MPU_CLKCTRL); } return 0; }
/** * omap3_noncore_dpll_set_rate - set non-core DPLL rate * @clk: struct clk * of DPLL to set * @rate: rounded target rate * * Set the DPLL CLKOUT to the target rate. If the DPLL can enter * low-power bypass, and the target rate is the bypass source clock * rate, then configure the DPLL for bypass. Otherwise, round the * target rate if it hasn't been done already, then program and lock * the DPLL. Returns -EINVAL upon error, or 0 upon success. */ int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) { struct clk *new_parent = NULL; u16 freqsel = 0; struct dpll_data *dd; int ret; if (!clk || !rate) return -EINVAL; dd = clk->dpll_data; if (!dd) return -EINVAL; if (rate == omap2_get_dpll_rate(clk)) return 0; /* * Ensure both the bypass and ref clocks are enabled prior to * doing anything; we need the bypass clock running to reprogram * the DPLL. */ omap2_clk_enable(dd->clk_bypass); omap2_clk_enable(dd->clk_ref); if (dd->clk_bypass->rate == rate && (clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS))) { pr_debug("clock: %s: set rate: entering bypass.\n", clk->name); ret = _omap3_noncore_dpll_bypass(clk); if (!ret) new_parent = dd->clk_bypass; } else { if (dd->last_rounded_rate != rate) rate = clk->round_rate(clk, rate); if (dd->last_rounded_rate == 0) return -EINVAL; /* No freqsel on OMAP4 and OMAP3630 */ if (!cpu_is_omap44xx() && !cpu_is_omap3630()) { freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); if (!freqsel) WARN_ON(1); } pr_debug("clock: %s: set rate: locking rate to %lu.\n", clk->name, rate); ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m, dd->last_rounded_n, freqsel); if (!ret) new_parent = dd->clk_ref; } if (!ret) { /* * Switch the parent clock in the hierarchy, and make sure * that the new parent's usecount is correct. Note: we * enable the new parent before disabling the old to avoid * any unnecessary hardware disable->enable transitions. */ if (clk->usecount) { omap2_clk_enable(new_parent); omap2_clk_disable(clk->parent); } clk_reparent(clk, new_parent); clk->rate = rate; } omap2_clk_disable(dd->clk_ref); omap2_clk_disable(dd->clk_bypass); return 0; }
/** * omap3_noncore_dpll_set_rate - set non-core DPLL rate * @clk: struct clk * of DPLL to set * @rate: rounded target rate * * Set the DPLL CLKOUT to the target rate. If the DPLL can enter * low-power bypass, and the target rate is the bypass source clock * rate, then configure the DPLL for bypass. Otherwise, round the * target rate if it hasn't been done already, then program and lock * the DPLL. Returns -EINVAL upon error, or 0 upon success. */ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); struct clk *new_parent = NULL; unsigned long rrate; u16 freqsel = 0; struct dpll_data *dd; int ret; if (!hw || !rate) return -EINVAL; dd = clk->dpll_data; if (!dd) return -EINVAL; if (__clk_get_rate(dd->clk_bypass) == rate && (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { pr_debug("%s: %s: set rate: entering bypass.\n", __func__, __clk_get_name(hw->clk)); __clk_prepare(dd->clk_bypass); clk_enable(dd->clk_bypass); ret = _omap3_noncore_dpll_bypass(clk); if (!ret) new_parent = dd->clk_bypass; clk_disable(dd->clk_bypass); __clk_unprepare(dd->clk_bypass); } else { __clk_prepare(dd->clk_ref); clk_enable(dd->clk_ref); if (dd->last_rounded_rate != rate) { rrate = __clk_round_rate(hw->clk, rate); if (rrate != rate) { pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n", __func__, __clk_get_name(hw->clk), rrate, rate); rate = rrate; } } if (dd->last_rounded_rate == 0) return -EINVAL; /* Freqsel is available only on OMAP343X devices */ if (cpu_is_omap343x()) { freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); WARN_ON(!freqsel); } pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__, __clk_get_name(hw->clk), rate); ret = omap3_noncore_dpll_program(clk, freqsel); if (!ret) new_parent = dd->clk_ref; clk_disable(dd->clk_ref); __clk_unprepare(dd->clk_ref); } /* * FIXME - this is all wrong. common code handles reparenting and * migrating prepare/enable counts. dplls should be a multiplexer * clock and this should be a set_parent operation so that all of that * stuff is inherited for free */ if (!ret && clk_get_parent(hw->clk) != new_parent) __clk_reparent(hw->clk, new_parent); return 0; }
/* * _omap3_noncore_dpll_program - set non-core DPLL M,N values directly * @clk: struct clk * of DPLL to set * @freqsel: FREQSEL value to set * * Program the DPLL with the last M, N values calculated, and wait for * the DPLL to lock. Returns -EINVAL upon error, or 0 upon success. */ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) { struct dpll_data *dd = clk->dpll_data; u8 dco, sd_div; u32 v; /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ _omap3_noncore_dpll_bypass(clk); if (dd->sink_clkdm) clkdm_clk_enable(dd->sink_clkdm, clk->hw.clk); /* * Set jitter correction. Jitter correction applicable for OMAP343X * only since freqsel field is no longer present on other devices. */ if (cpu_is_omap343x()) { v = omap2_clk_readl(clk, dd->control_reg); v &= ~dd->freqsel_mask; v |= freqsel << __ffs(dd->freqsel_mask); omap2_clk_writel(v, clk, dd->control_reg); } /* Set DPLL multiplier, divider */ v = omap2_clk_readl(clk, dd->mult_div1_reg); /* Handle Duty Cycle Correction */ if (dd->dcc_mask) { if (dd->last_rounded_rate >= dd->dcc_rate) v |= dd->dcc_mask; /* Enable DCC */ else v &= ~dd->dcc_mask; /* Disable DCC */ } v &= ~(dd->mult_mask | dd->div1_mask); v |= dd->last_rounded_m << __ffs(dd->mult_mask); v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask); /* Configure dco and sd_div for dplls that have these fields */ if (dd->dco_mask) { _lookup_dco(clk, &dco, dd->last_rounded_m, dd->last_rounded_n); v &= ~(dd->dco_mask); v |= dco << __ffs(dd->dco_mask); } if (dd->sddiv_mask) { _lookup_sddiv(clk, &sd_div, dd->last_rounded_m, dd->last_rounded_n); v &= ~(dd->sddiv_mask); v |= sd_div << __ffs(dd->sddiv_mask); } omap2_clk_writel(v, clk, dd->mult_div1_reg); /* Set 4X multiplier and low-power mode */ if (dd->m4xen_mask || dd->lpmode_mask) { v = omap2_clk_readl(clk, dd->control_reg); if (dd->m4xen_mask) { if (dd->last_rounded_m4xen) v |= dd->m4xen_mask; else v &= ~dd->m4xen_mask; } if (dd->lpmode_mask) { if (dd->last_rounded_lpmode) v |= dd->lpmode_mask; else v &= ~dd->lpmode_mask; } omap2_clk_writel(v, clk, dd->control_reg); } /* We let the clock framework set the other output dividers later */ /* REVISIT: Set ramp-up delay? */ _omap3_noncore_dpll_lock(clk); if (dd->sink_clkdm) clkdm_clk_disable(dd->sink_clkdm, clk->hw.clk); return 0; }
/* * _omap3_noncore_dpll_program - set non-core DPLL M,N values directly * @clk: struct clk * of DPLL to set * @freqsel: FREQSEL value to set * * Program the DPLL with the last M, N values calculated, and wait for * the DPLL to lock. Returns -EINVAL upon error, or 0 upon success. */ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) { struct dpll_data *dd = clk->dpll_data; u8 dco, sd_div, ai = 0; u32 v; bool errata_i810; /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ _omap3_noncore_dpll_bypass(clk); /* * Set jitter correction. Jitter correction applicable for OMAP343X * only since freqsel field is no longer present on other devices. */ if (ti_clk_get_features()->flags & TI_CLK_DPLL_HAS_FREQSEL) { v = ti_clk_ll_ops->clk_readl(&dd->control_reg); v &= ~dd->freqsel_mask; v |= freqsel << __ffs(dd->freqsel_mask); ti_clk_ll_ops->clk_writel(v, &dd->control_reg); } /* Set DPLL multiplier, divider */ v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg); /* Handle Duty Cycle Correction */ if (dd->dcc_mask) { if (dd->last_rounded_rate >= dd->dcc_rate) v |= dd->dcc_mask; /* Enable DCC */ else v &= ~dd->dcc_mask; /* Disable DCC */ } v &= ~(dd->mult_mask | dd->div1_mask); v |= dd->last_rounded_m << __ffs(dd->mult_mask); v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask); /* Configure dco and sd_div for dplls that have these fields */ if (dd->dco_mask) { _lookup_dco(clk, &dco, dd->last_rounded_m, dd->last_rounded_n); v &= ~(dd->dco_mask); v |= dco << __ffs(dd->dco_mask); } if (dd->sddiv_mask) { _lookup_sddiv(clk, &sd_div, dd->last_rounded_m, dd->last_rounded_n); v &= ~(dd->sddiv_mask); v |= sd_div << __ffs(dd->sddiv_mask); } /* * Errata i810 - DPLL controller can get stuck while transitioning * to a power saving state. Software must ensure the DPLL can not * transition to a low power state while changing M/N values. * Easiest way to accomplish this is to prevent DPLL autoidle * before doing the M/N re-program. */ errata_i810 = ti_clk_get_features()->flags & TI_CLK_ERRATA_I810; if (errata_i810) { ai = omap3_dpll_autoidle_read(clk); if (ai) { omap3_dpll_deny_idle(clk); /* OCP barrier */ omap3_dpll_autoidle_read(clk); } } ti_clk_ll_ops->clk_writel(v, &dd->mult_div1_reg); /* Set 4X multiplier and low-power mode */ if (dd->m4xen_mask || dd->lpmode_mask) { v = ti_clk_ll_ops->clk_readl(&dd->control_reg); if (dd->m4xen_mask) { if (dd->last_rounded_m4xen) v |= dd->m4xen_mask; else v &= ~dd->m4xen_mask; } if (dd->lpmode_mask) { if (dd->last_rounded_lpmode) v |= dd->lpmode_mask; else v &= ~dd->lpmode_mask; } ti_clk_ll_ops->clk_writel(v, &dd->control_reg); } /* We let the clock framework set the other output dividers later */ /* REVISIT: Set ramp-up delay? */ _omap3_noncore_dpll_lock(clk); if (errata_i810 && ai) omap3_dpll_allow_idle(clk); return 0; }
static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate) { struct clk *new_parent = NULL; u16 freqsel; struct dpll_data *dd; int ret; if (!clk || !rate) return -EINVAL; dd = clk->dpll_data; if (!dd) return -EINVAL; if (rate == omap2_get_dpll_rate(clk)) return 0; omap2_clk_enable(dd->clk_bypass); omap2_clk_enable(dd->clk_ref); if (dd->clk_bypass->rate == rate && (clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS))) { pr_debug("clock: %s: set rate: entering bypass.\n", clk->name); ret = _omap3_noncore_dpll_bypass(clk); if (!ret) new_parent = dd->clk_bypass; } else { if (dd->last_rounded_rate != rate) omap2_dpll_round_rate(clk, rate); if (dd->last_rounded_rate == 0) return -EINVAL; freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); if (!freqsel) WARN_ON(1); pr_debug("clock: %s: set rate: locking rate to %lu.\n", clk->name, rate); ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m, dd->last_rounded_n, freqsel); if (!ret) new_parent = dd->clk_ref; } if (!ret) { if (clk->usecount) { omap2_clk_enable(new_parent); omap2_clk_disable(clk->parent); } clk_reparent(clk, new_parent); clk->rate = rate; } omap2_clk_disable(dd->clk_ref); omap2_clk_disable(dd->clk_bypass); return 0; }
/** * omap3_noncore_dpll_set_rate - set non-core DPLL rate * @clk: struct clk * of DPLL to set * @rate: rounded target rate * * Set the DPLL CLKOUT to the target rate. If the DPLL can enter * low-power bypass, and the target rate is the bypass source clock * rate, then configure the DPLL for bypass. Otherwise, round the * target rate if it hasn't been done already, then program and lock * the DPLL. Returns -EINVAL upon error, or 0 upon success. */ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); struct clk *new_parent = NULL; u16 freqsel = 0; struct dpll_data *dd; int ret; if (!hw || !rate) return -EINVAL; dd = clk->dpll_data; if (!dd) return -EINVAL; __clk_prepare(dd->clk_bypass); clk_enable(dd->clk_bypass); __clk_prepare(dd->clk_ref); clk_enable(dd->clk_ref); if (__clk_get_rate(dd->clk_bypass) == rate && (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { pr_debug("%s: %s: set rate: entering bypass.\n", __func__, __clk_get_name(hw->clk)); ret = _omap3_noncore_dpll_bypass(clk); if (!ret) new_parent = dd->clk_bypass; } else { if (dd->last_rounded_rate != rate) rate = __clk_round_rate(hw->clk, rate); if (dd->last_rounded_rate == 0) return -EINVAL; /* No freqsel on OMAP4 and OMAP3630 */ if (!cpu_is_omap44xx() && !cpu_is_omap3630()) { freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); if (!freqsel) WARN_ON(1); } pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__, __clk_get_name(hw->clk), rate); ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m, dd->last_rounded_n, freqsel); if (!ret) new_parent = dd->clk_ref; } /* * FIXME - this is all wrong. common code handles reparenting and * migrating prepare/enable counts. dplls should be a multiplexer * clock and this should be a set_parent operation so that all of that * stuff is inherited for free */ if (!ret) __clk_reparent(hw->clk, new_parent); clk_disable(dd->clk_ref); __clk_unprepare(dd->clk_ref); clk_disable(dd->clk_bypass); __clk_unprepare(dd->clk_bypass); return 0; }