|
@@ -307,3 +307,148 @@ long omap1_round_to_table_rate(struct clk *clk, unsigned long rate)
|
|
|
static unsigned calc_ext_dsor(unsigned long rate)
|
|
|
{
|
|
|
unsigned dsor;
|
|
|
+
|
|
|
+ /* MCLK and BCLK divisor selection is not linear:
|
|
|
+ * freq = 96MHz / dsor
|
|
|
+ *
|
|
|
+ * RATIO_SEL range: dsor <-> RATIO_SEL
|
|
|
+ * 0..6: (RATIO_SEL+2) <-> (dsor-2)
|
|
|
+ * 6..48: (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6)
|
|
|
+ * Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9
|
|
|
+ * can not be used.
|
|
|
+ */
|
|
|
+ for (dsor = 2; dsor < 96; ++dsor) {
|
|
|
+ if ((dsor & 1) && dsor > 8)
|
|
|
+ continue;
|
|
|
+ if (rate >= 96000000 / dsor)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return dsor;
|
|
|
+}
|
|
|
+
|
|
|
+/* XXX Only needed on 1510 */
|
|
|
+int omap1_set_uart_rate(struct clk *clk, unsigned long rate)
|
|
|
+{
|
|
|
+ unsigned int val;
|
|
|
+
|
|
|
+ val = __raw_readl(clk->enable_reg);
|
|
|
+ if (rate == 12000000)
|
|
|
+ val &= ~(1 << clk->enable_bit);
|
|
|
+ else if (rate == 48000000)
|
|
|
+ val |= (1 << clk->enable_bit);
|
|
|
+ else
|
|
|
+ return -EINVAL;
|
|
|
+ __raw_writel(val, clk->enable_reg);
|
|
|
+ clk->rate = rate;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* External clock (MCLK & BCLK) functions */
|
|
|
+int omap1_set_ext_clk_rate(struct clk *clk, unsigned long rate)
|
|
|
+{
|
|
|
+ unsigned dsor;
|
|
|
+ __u16 ratio_bits;
|
|
|
+
|
|
|
+ dsor = calc_ext_dsor(rate);
|
|
|
+ clk->rate = 96000000 / dsor;
|
|
|
+ if (dsor > 8)
|
|
|
+ ratio_bits = ((dsor - 8) / 2 + 6) << 2;
|
|
|
+ else
|
|
|
+ ratio_bits = (dsor - 2) << 2;
|
|
|
+
|
|
|
+ ratio_bits |= __raw_readw(clk->enable_reg) & ~0xfd;
|
|
|
+ __raw_writew(ratio_bits, clk->enable_reg);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int omap1_set_sossi_rate(struct clk *clk, unsigned long rate)
|
|
|
+{
|
|
|
+ u32 l;
|
|
|
+ int div;
|
|
|
+ unsigned long p_rate;
|
|
|
+
|
|
|
+ p_rate = clk->parent->rate;
|
|
|
+ /* Round towards slower frequency */
|
|
|
+ div = (p_rate + rate - 1) / rate;
|
|
|
+ div--;
|
|
|
+ if (div < 0 || div > 7)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ l = omap_readl(MOD_CONF_CTRL_1);
|
|
|
+ l &= ~(7 << 17);
|
|
|
+ l |= div << 17;
|
|
|
+ omap_writel(l, MOD_CONF_CTRL_1);
|
|
|
+
|
|
|
+ clk->rate = p_rate / (div + 1);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+long omap1_round_ext_clk_rate(struct clk *clk, unsigned long rate)
|
|
|
+{
|
|
|
+ return 96000000 / calc_ext_dsor(rate);
|
|
|
+}
|
|
|
+
|
|
|
+void omap1_init_ext_clk(struct clk *clk)
|
|
|
+{
|
|
|
+ unsigned dsor;
|
|
|
+ __u16 ratio_bits;
|
|
|
+
|
|
|
+ /* Determine current rate and ensure clock is based on 96MHz APLL */
|
|
|
+ ratio_bits = __raw_readw(clk->enable_reg) & ~1;
|
|
|
+ __raw_writew(ratio_bits, clk->enable_reg);
|
|
|
+
|
|
|
+ ratio_bits = (ratio_bits & 0xfc) >> 2;
|
|
|
+ if (ratio_bits > 6)
|
|
|
+ dsor = (ratio_bits - 6) * 2 + 8;
|
|
|
+ else
|
|
|
+ dsor = ratio_bits + 2;
|
|
|
+
|
|
|
+ clk-> rate = 96000000 / dsor;
|
|
|
+}
|
|
|
+
|
|
|
+int omap1_clk_enable(struct clk *clk)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (clk->usecount++ == 0) {
|
|
|
+ if (clk->parent) {
|
|
|
+ ret = omap1_clk_enable(clk->parent);
|
|
|
+ if (ret)
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ if (clk->flags & CLOCK_NO_IDLE_PARENT)
|
|
|
+ omap1_clk_deny_idle(clk->parent);
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = clk->ops->enable(clk);
|
|
|
+ if (ret) {
|
|
|
+ if (clk->parent)
|
|
|
+ omap1_clk_disable(clk->parent);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+
|
|
|
+err:
|
|
|
+ clk->usecount--;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+void omap1_clk_disable(struct clk *clk)
|
|
|
+{
|
|
|
+ if (clk->usecount > 0 && !(--clk->usecount)) {
|
|
|
+ clk->ops->disable(clk);
|
|
|
+ if (likely(clk->parent)) {
|
|
|
+ omap1_clk_disable(clk->parent);
|
|
|
+ if (clk->flags & CLOCK_NO_IDLE_PARENT)
|
|
|
+ omap1_clk_allow_idle(clk->parent);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int omap1_clk_enable_generic(struct clk *clk)
|
|
|
+{
|
|
|
+ __u16 regval16;
|