|
@@ -254,3 +254,137 @@ static long pll1_set_rate(struct clk *clk, unsigned long rate, int apply)
|
|
|
if (apply) {
|
|
|
if (actual_rate != rate)
|
|
|
return -EINVAL;
|
|
|
+ if (clk->users > 0)
|
|
|
+ return -EBUSY;
|
|
|
+ pr_debug(KERN_INFO "clk %s: new rate %lu (actual rate %lu)\n",
|
|
|
+ clk->name, rate, actual_rate);
|
|
|
+ pm_writel(PLL1, ctrl);
|
|
|
+ }
|
|
|
+
|
|
|
+ return actual_rate;
|
|
|
+}
|
|
|
+
|
|
|
+static int pll1_set_parent(struct clk *clk, struct clk *parent)
|
|
|
+{
|
|
|
+ u32 ctrl;
|
|
|
+
|
|
|
+ if (clk->users > 0)
|
|
|
+ return -EBUSY;
|
|
|
+
|
|
|
+ ctrl = pm_readl(PLL1);
|
|
|
+ WARN_ON(ctrl & PM_BIT(PLLEN));
|
|
|
+
|
|
|
+ if (parent == &osc0)
|
|
|
+ ctrl &= ~PM_BIT(PLLOSC);
|
|
|
+ else if (parent == &osc1)
|
|
|
+ ctrl |= PM_BIT(PLLOSC);
|
|
|
+ else
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ pm_writel(PLL1, ctrl);
|
|
|
+ clk->parent = parent;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * The AT32AP7000 has five primary clock sources: One 32kHz
|
|
|
+ * oscillator, two crystal oscillators and two PLLs.
|
|
|
+ */
|
|
|
+static struct clk osc32k = {
|
|
|
+ .name = "osc32k",
|
|
|
+ .get_rate = osc_get_rate,
|
|
|
+ .users = 1,
|
|
|
+ .index = 0,
|
|
|
+};
|
|
|
+static struct clk osc0 = {
|
|
|
+ .name = "osc0",
|
|
|
+ .get_rate = osc_get_rate,
|
|
|
+ .users = 1,
|
|
|
+ .index = 1,
|
|
|
+};
|
|
|
+static struct clk osc1 = {
|
|
|
+ .name = "osc1",
|
|
|
+ .get_rate = osc_get_rate,
|
|
|
+ .index = 2,
|
|
|
+};
|
|
|
+static struct clk pll0 = {
|
|
|
+ .name = "pll0",
|
|
|
+ .get_rate = pll0_get_rate,
|
|
|
+ .parent = &osc0,
|
|
|
+};
|
|
|
+static struct clk pll1 = {
|
|
|
+ .name = "pll1",
|
|
|
+ .mode = pll1_mode,
|
|
|
+ .get_rate = pll1_get_rate,
|
|
|
+ .set_rate = pll1_set_rate,
|
|
|
+ .set_parent = pll1_set_parent,
|
|
|
+ .parent = &osc0,
|
|
|
+};
|
|
|
+
|
|
|
+/*
|
|
|
+ * The main clock can be either osc0 or pll0. The boot loader may
|
|
|
+ * have chosen one for us, so we don't really know which one until we
|
|
|
+ * have a look at the SM.
|
|
|
+ */
|
|
|
+static struct clk *main_clock;
|
|
|
+
|
|
|
+/*
|
|
|
+ * Synchronous clocks are generated from the main clock. The clocks
|
|
|
+ * must satisfy the constraint
|
|
|
+ * fCPU >= fHSB >= fPB
|
|
|
+ * i.e. each clock must not be faster than its parent.
|
|
|
+ */
|
|
|
+static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
|
|
|
+{
|
|
|
+ return main_clock->get_rate(main_clock) >> shift;
|
|
|
+};
|
|
|
+
|
|
|
+static void cpu_clk_mode(struct clk *clk, int enabled)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ u32 mask;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&pm_lock, flags);
|
|
|
+ mask = pm_readl(CPU_MASK);
|
|
|
+ if (enabled)
|
|
|
+ mask |= 1 << clk->index;
|
|
|
+ else
|
|
|
+ mask &= ~(1 << clk->index);
|
|
|
+ pm_writel(CPU_MASK, mask);
|
|
|
+ spin_unlock_irqrestore(&pm_lock, flags);
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned long cpu_clk_get_rate(struct clk *clk)
|
|
|
+{
|
|
|
+ unsigned long cksel, shift = 0;
|
|
|
+
|
|
|
+ cksel = pm_readl(CKSEL);
|
|
|
+ if (cksel & PM_BIT(CPUDIV))
|
|
|
+ shift = PM_BFEXT(CPUSEL, cksel) + 1;
|
|
|
+
|
|
|
+ return bus_clk_get_rate(clk, shift);
|
|
|
+}
|
|
|
+
|
|
|
+static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
|
|
|
+{
|
|
|
+ u32 control;
|
|
|
+ unsigned long parent_rate, child_div, actual_rate, div;
|
|
|
+
|
|
|
+ parent_rate = clk->parent->get_rate(clk->parent);
|
|
|
+ control = pm_readl(CKSEL);
|
|
|
+
|
|
|
+ if (control & PM_BIT(HSBDIV))
|
|
|
+ child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
|
|
|
+ else
|
|
|
+ child_div = 1;
|
|
|
+
|
|
|
+ if (rate > 3 * (parent_rate / 4) || child_div == 1) {
|
|
|
+ actual_rate = parent_rate;
|
|
|
+ control &= ~PM_BIT(CPUDIV);
|
|
|
+ } else {
|
|
|
+ unsigned int cpusel;
|
|
|
+ div = (parent_rate + rate / 2) / rate;
|
|
|
+ if (div > child_div)
|
|
|
+ div = child_div;
|
|
|
+ cpusel = (div > 1) ? (fls(div) - 2) : 0;
|