Skip to content

Instantly share code, notes, and snippets.

@RobertCNelson
Created April 16, 2013 03:35
Show Gist options
  • Save RobertCNelson/5393160 to your computer and use it in GitHub Desktop.
Save RobertCNelson/5393160 to your computer and use it in GitHub Desktop.
diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c
index 4579c3c..d837d9f 100644
--- a/arch/arm/mach-omap2/cclock3xxx_data.c
+++ b/arch/arm/mach-omap2/cclock3xxx_data.c
@@ -250,7 +250,9 @@ static struct dpll_data dpll1_dd = {
static struct clk dpll1_ck;
-static const struct clk_ops dpll1_ck_ops = {
+static struct clk_ops dpll1_ck_ops;
+
+static struct clk_ops dpll1_ck_ops_omap34xx __initdata = {
.init = &omap2_init_clk_clkdm,
.enable = &omap3_noncore_dpll_enable,
.disable = &omap3_noncore_dpll_disable,
@@ -260,6 +262,16 @@ static const struct clk_ops dpll1_ck_ops = {
.round_rate = &omap2_dpll_round_rate,
};
+static struct clk_ops dpll5_ck_ops_omap3630 __initdata = {
+ .init = &omap2_init_clk_clkdm,
+ .enable = &omap3_noncore_dpll_enable,
+ .disable = &omap3_noncore_dpll_disable,
+ .get_parent = &omap2_init_dpll_parent,
+ .recalc_rate = &omap3_dpll_recalc,
+ .set_rate = &omap3_noncore_dpll_set_rate,
+ .round_rate = &omap2_dpll5_round_rate,
+};
+
static struct clk_hw_omap dpll1_ck_hw = {
.hw = {
.clk = &dpll1_ck,
@@ -3571,6 +3583,12 @@ int __init omap3xxx_clk_init(void)
else
dpll4_dd = dpll4_dd_34xx;
+ if (cpu_is_omap3630())
+ dpll1_ck_ops = dpll5_ck_ops_omap3630;
+ else
+ dpll1_ck_ops = dpll1_ck_ops_omap34xx;
+
+
for (c = omap3xxx_clks; c < omap3xxx_clks + ARRAY_SIZE(omap3xxx_clks);
c++)
if (c->cpu & cpu_clkflg) {
diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c
index 924c230..b40642f 100644
--- a/arch/arm/mach-omap2/clkt_dpll.c
+++ b/arch/arm/mach-omap2/clkt_dpll.c
@@ -63,6 +63,15 @@
#define DPLL_FINT_UNDERFLOW -1
#define DPLL_FINT_INVALID -2
+/* copied from clock3xxx.c */
+/*
+ * DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks
+ * that are sourced by DPLL5, and both of these require this clock
+ * to be at 120 MHz for proper operation.
+ */
+#define DPLL5_FREQ_FOR_USBHOST 120000000
+
+
/* Private functions */
/*
@@ -362,3 +371,63 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
return target_rate;
}
+struct sprz319e_2_1_values {
+ unsigned long sys_clk_rate;
+ int m, n, div120m;
+};
+
+/**
+ * omap2_dpll5_round_rate - round a target rate for OMAP DPLL5
+ * according to DM37xx sprz319e 2.1 erratum
+ *
+ * @clk: struct clk * for a DPLL (presumably DPLL5)
+ * @target_rate: desired DPLL clock rate
+ *
+ * The erratum applies only for DM37xx, desired clock rates of
+ * div120m times 120 MHz and specified sys_clks.
+ * If any of the above specified condition does not apply, this
+ * function will fall back to omap2_dpll_round_rate.
+ */
+long omap2_dpll5_round_rate(struct clk_hw *hw, unsigned long target_rate,
+ unsigned long *parent_rate)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ struct dpll_data *dd;
+ const char *clk_name;
+ int i;
+
+ /* erratum tables */
+ const struct sprz319e_2_1_values sprz319e_2_1_table[] = {
+ /* table 35 */
+ { 12000000, 80, 0, 8 },
+ { 19200000, 50, 0, 8 },
+ { 38400000, 25, 0, 8 },
+ /* table 36 */
+ { 13000000, 443, 5, 8 },
+ { 26000000, 443, 11, 8 },
+ };
+
+ if (!clk || !clk->dpll_data)
+ return ~0;
+
+ dd = clk->dpll_data;
+
+ clk_name = __clk_get_name(hw->clk);
+
+ for (i = 0; i < (sizeof(sprz319e_2_1_table)/sizeof(struct sprz319e_2_1_values)); i++) {
+ const struct sprz319e_2_1_values *v = &sprz319e_2_1_table[i];
+
+ if (*parent_rate == v->sys_clk_rate &&
+ target_rate == DPLL5_FREQ_FOR_USBHOST * v->div120m) {
+
+ printk(KERN_NOTICE "Applying SPRZ319E 2.1: %8lu, %3d, %3d, %3d\n",
+ v->sys_clk_rate, v->m, v->n, v->div120m);
+
+ dd->last_rounded_m = v->m;
+ dd->last_rounded_n = v->n + 1;
+ dd->last_rounded_rate = v->sys_clk_rate * v->m / (v->n + 1);
+
+ return dd->last_rounded_rate;
+ }
+ }
+}
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index 60ddd86..0df6eeb 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -375,6 +375,8 @@ unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw,
long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
unsigned long *parent_rate);
+long omap2_dpll5_round_rate(struct clk_hw *hw, unsigned long target_rate,
+ unsigned long *parent_rate);
unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate);
int omap3_noncore_dpll_enable(struct clk_hw *hw);
void omap3_noncore_dpll_disable(struct clk_hw *hw);
diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c
index 0b02b41..90dbc25 100644
--- a/arch/arm/mach-omap2/clock3xxx.c
+++ b/arch/arm/mach-omap2/clock3xxx.c
@@ -60,7 +60,13 @@ void __init omap3_clk_lock_dpll5(void)
struct clk *dpll5_m2_clk;
dpll5_clk = clk_get(NULL, "dpll5_ck");
- clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST);
+
+ if (cpu_is_omap3630()) {
+ clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST*8);
+ } else {
+ clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST);
+ }
+
clk_prepare_enable(dpll5_clk);
/* Program dpll5_m2_clk divider for no division */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment