|
@@ -121,3 +121,136 @@ static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
|
|
|
|
|
|
rate = clk->parent->get_rate(clk->parent);
|
|
|
rate = (rate + div / 2) / div;
|
|
|
+ rate *= mul;
|
|
|
+
|
|
|
+ return rate;
|
|
|
+}
|
|
|
+
|
|
|
+static long pll_set_rate(struct clk *clk, unsigned long rate,
|
|
|
+ u32 *pll_ctrl)
|
|
|
+{
|
|
|
+ unsigned long mul;
|
|
|
+ unsigned long mul_best_fit = 0;
|
|
|
+ unsigned long div;
|
|
|
+ unsigned long div_min;
|
|
|
+ unsigned long div_max;
|
|
|
+ unsigned long div_best_fit = 0;
|
|
|
+ unsigned long base;
|
|
|
+ unsigned long pll_in;
|
|
|
+ unsigned long actual = 0;
|
|
|
+ unsigned long rate_error;
|
|
|
+ unsigned long rate_error_prev = ~0UL;
|
|
|
+ u32 ctrl;
|
|
|
+
|
|
|
+ /* Rate must be between 80 MHz and 200 Mhz. */
|
|
|
+ if (rate < 80000000UL || rate > 200000000UL)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ ctrl = PM_BF(PLLOPT, 4);
|
|
|
+ base = clk->parent->get_rate(clk->parent);
|
|
|
+
|
|
|
+ /* PLL input frequency must be between 6 MHz and 32 MHz. */
|
|
|
+ div_min = DIV_ROUND_UP(base, 32000000UL);
|
|
|
+ div_max = base / 6000000UL;
|
|
|
+
|
|
|
+ if (div_max < div_min)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ for (div = div_min; div <= div_max; div++) {
|
|
|
+ pll_in = (base + div / 2) / div;
|
|
|
+ mul = (rate + pll_in / 2) / pll_in;
|
|
|
+
|
|
|
+ if (mul == 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ actual = pll_in * mul;
|
|
|
+ rate_error = abs(actual - rate);
|
|
|
+
|
|
|
+ if (rate_error < rate_error_prev) {
|
|
|
+ mul_best_fit = mul;
|
|
|
+ div_best_fit = div;
|
|
|
+ rate_error_prev = rate_error;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (rate_error == 0)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (div_best_fit == 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ ctrl |= PM_BF(PLLMUL, mul_best_fit - 1);
|
|
|
+ ctrl |= PM_BF(PLLDIV, div_best_fit - 1);
|
|
|
+ ctrl |= PM_BF(PLLCOUNT, 16);
|
|
|
+
|
|
|
+ if (clk->parent == &osc1)
|
|
|
+ ctrl |= PM_BIT(PLLOSC);
|
|
|
+
|
|
|
+ *pll_ctrl = ctrl;
|
|
|
+
|
|
|
+ return actual;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned long pll0_get_rate(struct clk *clk)
|
|
|
+{
|
|
|
+ u32 control;
|
|
|
+
|
|
|
+ control = pm_readl(PLL0);
|
|
|
+
|
|
|
+ return pll_get_rate(clk, control);
|
|
|
+}
|
|
|
+
|
|
|
+static void pll1_mode(struct clk *clk, int enabled)
|
|
|
+{
|
|
|
+ unsigned long timeout;
|
|
|
+ u32 status;
|
|
|
+ u32 ctrl;
|
|
|
+
|
|
|
+ ctrl = pm_readl(PLL1);
|
|
|
+
|
|
|
+ if (enabled) {
|
|
|
+ if (!PM_BFEXT(PLLMUL, ctrl) && !PM_BFEXT(PLLDIV, ctrl)) {
|
|
|
+ pr_debug("clk %s: failed to enable, rate not set\n",
|
|
|
+ clk->name);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ctrl |= PM_BIT(PLLEN);
|
|
|
+ pm_writel(PLL1, ctrl);
|
|
|
+
|
|
|
+ /* Wait for PLL lock. */
|
|
|
+ for (timeout = 10000; timeout; timeout--) {
|
|
|
+ status = pm_readl(ISR);
|
|
|
+ if (status & PM_BIT(LOCK1))
|
|
|
+ break;
|
|
|
+ udelay(10);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!(status & PM_BIT(LOCK1)))
|
|
|
+ printk(KERN_ERR "clk %s: timeout waiting for lock\n",
|
|
|
+ clk->name);
|
|
|
+ } else {
|
|
|
+ ctrl &= ~PM_BIT(PLLEN);
|
|
|
+ pm_writel(PLL1, ctrl);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned long pll1_get_rate(struct clk *clk)
|
|
|
+{
|
|
|
+ u32 control;
|
|
|
+
|
|
|
+ control = pm_readl(PLL1);
|
|
|
+
|
|
|
+ return pll_get_rate(clk, control);
|
|
|
+}
|
|
|
+
|
|
|
+static long pll1_set_rate(struct clk *clk, unsigned long rate, int apply)
|
|
|
+{
|
|
|
+ u32 ctrl = 0;
|
|
|
+ unsigned long actual_rate;
|
|
|
+
|
|
|
+ actual_rate = pll_set_rate(clk, rate, &ctrl);
|
|
|
+
|
|
|
+ if (apply) {
|
|
|
+ if (actual_rate != rate)
|
|
|
+ return -EINVAL;
|