|
@@ -312,3 +312,61 @@ u8 omap2_clksel_find_parent_index(struct clk_hw *hw)
|
|
|
struct clk *parent;
|
|
|
const char *clk_name;
|
|
|
int ret = 0, f = 0;
|
|
|
+
|
|
|
+ parent = __clk_get_parent(hw->clk);
|
|
|
+ clk_name = __clk_get_name(hw->clk);
|
|
|
+
|
|
|
+ /* XXX should be able to return an error */
|
|
|
+ WARN((!clk->clksel || !clk->clksel_mask),
|
|
|
+ "clock: %s: attempt to call on a non-clksel clock", clk_name);
|
|
|
+
|
|
|
+ r = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
|
|
|
+ r >>= __ffs(clk->clksel_mask);
|
|
|
+
|
|
|
+ for (clks = clk->clksel; clks->parent && !found; clks++) {
|
|
|
+ for (clkr = clks->rates; clkr->div && !found; clkr++) {
|
|
|
+ if (!(clkr->flags & cpu_mask))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (clkr->val == r) {
|
|
|
+ found = 1;
|
|
|
+ ret = f;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ f++;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* This indicates a data error */
|
|
|
+ WARN(!found, "clock: %s: init parent: could not find regval %0x\n",
|
|
|
+ clk_name, r);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap2_clksel_recalc() - function ptr to pass via struct clk .recalc field
|
|
|
+ * @clk: struct clk *
|
|
|
+ *
|
|
|
+ * This function is intended to be called only by the clock framework.
|
|
|
+ * Each clksel clock should have its struct clk .recalc field set to this
|
|
|
+ * function. Returns the clock's current rate, based on its parent's rate
|
|
|
+ * and its current divisor setting in the hardware.
|
|
|
+ */
|
|
|
+unsigned long omap2_clksel_recalc(struct clk_hw *hw, unsigned long parent_rate)
|
|
|
+{
|
|
|
+ unsigned long rate;
|
|
|
+ u32 div = 0;
|
|
|
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
|
|
+
|
|
|
+ if (!parent_rate)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ div = _read_divisor(clk);
|
|
|
+ if (!div)
|
|
|
+ rate = parent_rate;
|
|
|
+ else
|
|
|
+ rate = parent_rate / div;
|
|
|
+
|
|
|
+ pr_debug("%s: recalc'd %s's rate to %lu (div %d)\n", __func__,
|
|
|
+ __clk_get_name(hw->clk), rate, div);
|