diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c
index e25364d..a40860f 100644
--- a/arch/arm/mach-omap2/clkt_clksel.c
+++ b/arch/arm/mach-omap2/clkt_clksel.c
@@ -445,21 +445,48 @@ int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
 
 	validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
 	if (validrate != rate)
-		return -EINVAL;
+        {
+            pr_notice("%s: validrate = %lu, rate = %lu \n", 
+                      __func__, (unsigned long)validrate, rate);
+            return -EINVAL;
+        }
 
 	field_val = _divisor_to_clksel(clk, new_div);
 	if (field_val == ~0)
-		return -EINVAL;
+	{
+            pr_notice("%s: field_val == %d \n", __func__, field_val);
+            return -EINVAL;
+        }
 
 	_write_clksel_reg(clk, field_val);
 
 	clk->rate = clk->parent->rate / new_div;
 
-	pr_debug("clock: %s: set rate to %ld\n", clk->name, clk->rate);
-
+	pr_notice("clock: %s: set rate to %ld (divider = %d)\n", clk->name, clk->rate, new_div);
+        
 	return 0;
 }
 
+int omap2_clksel_force_divisor(struct clk *clk, int new_div)
+{
+    u32 field_val;
+    
+    field_val = _divisor_to_clksel(clk, new_div);
+    if (field_val == ~0)
+    {
+        pr_notice("%s: field_val == %d \n", __func__, field_val);
+        return -EINVAL;
+    }
+    
+    _write_clksel_reg(clk, field_val);
+    
+    clk->rate = clk->parent->rate / new_div;
+    
+    pr_notice("clock: %s: force rate to %ld (divider = %d)\n", clk->name, clk->rate, new_div);
+    
+	return 0;    
+}
+
 /*
  * Clksel parent setting function - not passed in struct clk function
  * pointer - instead, the OMAP clock code currently assumes that any
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index e5abd35..ec7f3ff 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -61,6 +61,11 @@ void omap3_dpll_allow_idle(struct clk *clk);
 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);
@@ -86,6 +91,7 @@ unsigned long omap2_clksel_recalc(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);
diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c
index 62cf7bb..fbd30be 100644
--- a/arch/arm/mach-omap2/clock3xxx.c
+++ b/arch/arm/mach-omap2/clock3xxx.c
@@ -40,6 +40,51 @@
 /* needed by omap3_core_dpll_m2_set_rate() */
 struct clk *sdrc_ick_p, *arm_fck_p;
 
+struct dpll_settings
+{
+    int rate, m, n, f;
+};
+int omap3_dpll5_set_rate(struct clk *clk, unsigned long rate)
+{
+    if (cpu_is_omap3630() && rate == DPLL5_FREQ_FOR_USBHOST)
+    {
+        struct clk *sys_clk, *dpll5_m2;
+        int i, rv;
+        const static struct dpll_settings precomputed[] = 
+            {
+                /* From DM3730 errata, 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 }
+            };
+        
+        /* Erratum 2.1 applies: try to make the PHY at least vaguely
+         *  happy
+         */
+        sys_clk = clk_get(NULL, "sys_ck");
+        dpll5_m2 = clk_get(NULL, "dpll5_m2_ck");
+        pr_notice("RRW: Setting DPLL5 - erratum 2.1 applies sys_clk = %lu.\n", sys_clk->rate);
+        for (i=0 ;i < (sizeof(precomputed)/sizeof(struct dpll_settings)); ++i)
+        {
+            const struct dpll_settings *d = &precomputed[i];
+
+            if (sys_clk->rate == d->rate)
+            {
+                pr_notice("RRW: Program DPLL5 with m = %d, n = %d, f = %d \n", 
+                          d->m, d->n, d->f);
+                rv =  omap3_noncore_dpll_program(clk, d->m ,d->n, 0);
+                if (rv) { return rv; }
+                return omap2_clksel_force_divisor(dpll5_m2, d->f);
+            }
+        }
+        pr_notice("RRW: No precomputed settings... \n");
+    }
+    return omap3_noncore_dpll_set_rate(clk, rate);
+    
+}
+
 int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate)
 {
 	/*
@@ -61,16 +106,19 @@ void __init omap3_clk_lock_dpll5(void)
 	struct clk *dpll5_clk;
 	struct clk *dpll5_m2_clk;
 
+        pr_notice("rrw: Using hard-wired DPLL5 settings. \n");
 	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);
-
-	clk_disable(dpll5_m2_clk);
+        if (!cpu_is_omap3630())
+        {
+            dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck");
+            clk_enable(dpll5_m2_clk);
+            clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST);
+            clk_disable(dpll5_m2_clk);
+        }
+        
 	clk_disable(dpll5_clk);
 	return;
 }
diff --git a/arch/arm/mach-omap2/clock3xxx.h b/arch/arm/mach-omap2/clock3xxx.h
index 8bbeeaf..0ede513 100644
--- a/arch/arm/mach-omap2/clock3xxx.h
+++ b/arch/arm/mach-omap2/clock3xxx.h
@@ -10,6 +10,7 @@
 
 int omap3xxx_clk_init(void);
 int omap3_dpll4_set_rate(struct clk *clk, unsigned long rate);
+int omap3_dpll5_set_rate(struct clk *clk, unsigned long rate);
 int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate);
 void omap3_clk_lock_dpll5(void);
 
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index 3ba11f2..b6e3466 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -942,7 +942,7 @@ static struct clk dpll5_ck = {
 	.parent		= &sys_ck,
 	.dpll_data	= &dpll5_dd,
 	.round_rate	= &omap2_dpll_round_rate,
-	.set_rate	= &omap3_noncore_dpll_set_rate,
+	.set_rate	= &omap3_dpll5_set_rate, 
 	.clkdm_name	= "dpll5_clkdm",
 	.recalc		= &omap3_dpll_recalc,
 };
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index fc56745..9c83a40 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -291,7 +291,7 @@ static void _lookup_sddiv(struct clk *clk, u8 *sd_div, u16 m, u8 n)
  * 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;
@@ -398,7 +398,7 @@ int omap3_noncore_dpll_enable(struct clk *clk)
 
 /**
  * omap3_noncore_dpll_disable - instruct a DPLL to enter low-power stop
- * @clk: pointer to a DPLL struct clk
+ * @clk#: pointer to a DPLL struct clk
  *
  * Instructs a non-CORE DPLL to enter low-power stop.  This function is
  * intended for use in struct clkops.  No return value.
