void omap3_dpll_deny_idle(struct clk *clk);
u32 omap3_dpll_autoidle_read(struct clk *clk);
int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate);
+#if CONFIG_ARCH_OMAP3
+int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel);
+/* If you are using this function and not on OMAP3, you are
+ * Doing It Wrong(tm), so there is no stub.
+ */
+#endif
int omap3_noncore_dpll_enable(struct clk *clk);
void omap3_noncore_dpll_disable(struct clk *clk);
int omap4_dpllmx_gatectrl_read(struct clk *clk);
long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate);
int omap2_clksel_set_rate(struct clk *clk, unsigned long rate);
int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent);
+int omap2_clksel_force_divisor(struct clk *clk, int new_div);
/* clkt_iclk.c public functions */
extern void omap2_clkt_iclk_allow_idle(struct clk *clk);
/* needed by omap3_core_dpll_m2_set_rate() */
struct clk *sdrc_ick_p, *arm_fck_p;
+struct dpll_settings {
+ int rate, m, n, f;
+};
+
+
+static int omap3_dpll5_apply_erratum21(struct clk *clk, struct clk *dpll5_m2)
+{
+ struct clk *sys_clk;
+ int i, rv;
+ static const struct dpll_settings precomputed[] = {
+ /* From DM3730 errata (sprz319e), table 36
+ * +1 is because the values in the table are register values;
+ * dpll_program() will subtract one from what we give it,
+ * so ...
+ */
+ { 13000000, 443+1, 5+1, 8 },
+ { 26000000, 443+1, 11+1, 8 }
+ };
+
+ sys_clk = clk_get(NULL, "sys_ck");
+
+ for (i = 0 ; i < (sizeof(precomputed)/sizeof(struct dpll_settings)) ;
+ ++i) {
+ const struct dpll_settings *d = &precomputed[i];
+ if (sys_clk->rate == d->rate) {
+ rv = omap3_noncore_dpll_program(clk, d->m , d->n, 0);
+ if (rv)
+ return 1;
+ rv = omap2_clksel_force_divisor(dpll5_m2 , d->f);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int omap3_dpll5_set_rate(struct clk *clk, unsigned long rate)
+{
+ struct clk *dpll5_m2;
+ int rv;
+ dpll5_m2 = clk_get(NULL, "dpll5_m2_ck");
+
+ if (cpu_is_omap3630() && rate == DPLL5_FREQ_FOR_USBHOST &&
+ omap3_dpll5_apply_erratum21(clk, dpll5_m2)) {
+ return 1;
+ }
+ rv = omap3_noncore_dpll_set_rate(clk, rate);
+ if (rv)
+ goto out;
+ rv = clk_set_rate(dpll5_m2, rate);
+
+out:
+ return rv;
+}
+
int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate)
{
/*
void __init omap3_clk_lock_dpll5(void)
{
struct clk *dpll5_clk;
- struct clk *dpll5_m2_clk;
dpll5_clk = clk_get(NULL, "dpll5_ck");
clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST);
- clk_enable(dpll5_clk);
- /* Program dpll5_m2_clk divider for no division */
- dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck");
- clk_enable(dpll5_m2_clk);
- clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST);
+ /* dpll5_m2_ck is now (grottily!) handled by dpll5_clk's set routine,
+ * to cope with an erratum on DM3730
+ */
- clk_disable(dpll5_m2_clk);
- clk_disable(dpll5_clk);
return;
}
* 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)
+int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
{
struct dpll_data *dd = clk->dpll_data;
u8 dco, sd_div;