|
@@ -370,3 +370,97 @@ unsigned long omap2_clksel_recalc(struct clk_hw *hw, unsigned long parent_rate)
|
|
|
|
|
|
pr_debug("%s: recalc'd %s's rate to %lu (div %d)\n", __func__,
|
|
pr_debug("%s: recalc'd %s's rate to %lu (div %d)\n", __func__,
|
|
__clk_get_name(hw->clk), rate, div);
|
|
__clk_get_name(hw->clk), rate, div);
|
|
|
|
+
|
|
|
|
+ return rate;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap2_clksel_round_rate() - find rounded rate for the given clock and rate
|
|
|
|
+ * @clk: OMAP struct clk to use
|
|
|
|
+ * @target_rate: desired clock rate
|
|
|
|
+ *
|
|
|
|
+ * This function is intended to be called only by the clock framework.
|
|
|
|
+ * Finds best target rate based on the source clock and possible dividers.
|
|
|
|
+ * rates. The divider array must be sorted with smallest divider first.
|
|
|
|
+ *
|
|
|
|
+ * Returns the rounded clock rate or returns 0xffffffff on error.
|
|
|
|
+ */
|
|
|
|
+long omap2_clksel_round_rate(struct clk_hw *hw, unsigned long target_rate,
|
|
|
|
+ unsigned long *parent_rate)
|
|
|
|
+{
|
|
|
|
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
|
|
|
+ u32 new_div;
|
|
|
|
+
|
|
|
|
+ return omap2_clksel_round_rate_div(clk, target_rate, &new_div);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap2_clksel_set_rate() - program clock rate in hardware
|
|
|
|
+ * @clk: struct clk * to program rate
|
|
|
|
+ * @rate: target rate to program
|
|
|
|
+ *
|
|
|
|
+ * This function is intended to be called only by the clock framework.
|
|
|
|
+ * Program @clk's rate to @rate in the hardware. The clock can be
|
|
|
|
+ * either enabled or disabled when this happens, although if the clock
|
|
|
|
+ * is enabled, some downstream devices may glitch or behave
|
|
|
|
+ * unpredictably when the clock rate is changed - this depends on the
|
|
|
|
+ * hardware. This function does not currently check the usecount of
|
|
|
|
+ * the clock, so if multiple drivers are using the clock, and the rate
|
|
|
|
+ * is changed, they will all be affected without any notification.
|
|
|
|
+ * Returns -EINVAL upon error, or 0 upon success.
|
|
|
|
+ */
|
|
|
|
+int omap2_clksel_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
|
|
+ unsigned long parent_rate)
|
|
|
|
+{
|
|
|
|
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
|
|
|
+ u32 field_val, validrate, new_div = 0;
|
|
|
|
+
|
|
|
|
+ if (!clk->clksel || !clk->clksel_mask)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
|
|
|
|
+ if (validrate != rate)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ field_val = _divisor_to_clksel(clk, new_div);
|
|
|
|
+ if (field_val == ~0)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ _write_clksel_reg(clk, field_val);
|
|
|
|
+
|
|
|
|
+ pr_debug("clock: %s: set rate to %ld\n", __clk_get_name(hw->clk),
|
|
|
|
+ __clk_get_rate(hw->clk));
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Clksel parent setting function - not passed in struct clk function
|
|
|
|
+ * pointer - instead, the OMAP clock code currently assumes that any
|
|
|
|
+ * parent-setting clock is a clksel clock, and calls
|
|
|
|
+ * omap2_clksel_set_parent() by default
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap2_clksel_set_parent() - change a clock's parent clock
|
|
|
|
+ * @clk: struct clk * of the child clock
|
|
|
|
+ * @new_parent: struct clk * of the new parent clock
|
|
|
|
+ *
|
|
|
|
+ * This function is intended to be called only by the clock framework.
|
|
|
|
+ * Change the parent clock of clock @clk to @new_parent. This is
|
|
|
|
+ * intended to be used while @clk is disabled. This function does not
|
|
|
|
+ * currently check the usecount of the clock, so if multiple drivers
|
|
|
|
+ * are using the clock, and the parent is changed, they will all be
|
|
|
|
+ * affected without any notification. Returns -EINVAL upon error, or
|
|
|
|
+ * 0 upon success.
|
|
|
|
+ */
|
|
|
|
+int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val)
|
|
|
|
+{
|
|
|
|
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
|
|
|
+
|
|
|
|
+ if (!clk->clksel || !clk->clksel_mask)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ _write_clksel_reg(clk, field_val);
|
|
|
|
+ return 0;
|
|
|
|
+}
|