+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
+ * N+1 is because the values in the table are register values;
+ * dpll_program() will subtract one from the N we give it,
+ * so ...
+ */
+ { 13000000, 443, 5+1, 8 },
+ { 26000000, 443, 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;
+}
+