|
@@ -346,3 +346,196 @@ void omap2_dflt_clk_disable(struct clk_hw *hw)
|
|
if (!clk->enable_reg) {
|
|
if (!clk->enable_reg) {
|
|
/*
|
|
/*
|
|
* 'independent' here refers to a clock which is not
|
|
* 'independent' here refers to a clock which is not
|
|
|
|
+ * controlled by its parent.
|
|
|
|
+ */
|
|
|
|
+ pr_err("%s: independent clock %s has no enable_reg\n",
|
|
|
|
+ __func__, __clk_get_name(hw->clk));
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ v = __raw_readl(clk->enable_reg);
|
|
|
|
+ if (clk->flags & INVERT_ENABLE)
|
|
|
|
+ v |= (1 << clk->enable_bit);
|
|
|
|
+ else
|
|
|
|
+ v &= ~(1 << clk->enable_bit);
|
|
|
|
+ __raw_writel(v, clk->enable_reg);
|
|
|
|
+ /* No OCP barrier needed here since it is a disable operation */
|
|
|
|
+
|
|
|
|
+ if (clkdm_control && clk->clkdm)
|
|
|
|
+ clkdm_clk_disable(clk->clkdm, hw->clk);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw
|
|
|
|
+ * @hw: struct clk_hw * of the clock being enabled
|
|
|
|
+ *
|
|
|
|
+ * Increment the usecount of the clockdomain of the clock pointed to
|
|
|
|
+ * by @hw; if the usecount is 1, the clockdomain will be "enabled."
|
|
|
|
+ * Only needed for clocks that don't use omap2_dflt_clk_enable() as
|
|
|
|
+ * their enable function pointer. Passes along the return value of
|
|
|
|
+ * clkdm_clk_enable(), -EINVAL if @hw is not associated with a
|
|
|
|
+ * clockdomain, or 0 if clock framework-based clockdomain control is
|
|
|
|
+ * not implemented.
|
|
|
|
+ */
|
|
|
|
+int omap2_clkops_enable_clkdm(struct clk_hw *hw)
|
|
|
|
+{
|
|
|
|
+ struct clk_hw_omap *clk;
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ clk = to_clk_hw_omap(hw);
|
|
|
|
+
|
|
|
|
+ if (unlikely(!clk->clkdm)) {
|
|
|
|
+ pr_err("%s: %s: no clkdm set ?!\n", __func__,
|
|
|
|
+ __clk_get_name(hw->clk));
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (unlikely(clk->enable_reg))
|
|
|
|
+ pr_err("%s: %s: should use dflt_clk_enable ?!\n", __func__,
|
|
|
|
+ __clk_get_name(hw->clk));
|
|
|
|
+
|
|
|
|
+ if (!clkdm_control) {
|
|
|
|
+ pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
|
|
|
|
+ __func__, __clk_get_name(hw->clk));
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = clkdm_clk_enable(clk->clkdm, hw->clk);
|
|
|
|
+ WARN(ret, "%s: could not enable %s's clockdomain %s: %d\n",
|
|
|
|
+ __func__, __clk_get_name(hw->clk), clk->clkdm->name, ret);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap2_clkops_disable_clkdm - decrement usecount on clkdm of @hw
|
|
|
|
+ * @hw: struct clk_hw * of the clock being disabled
|
|
|
|
+ *
|
|
|
|
+ * Decrement the usecount of the clockdomain of the clock pointed to
|
|
|
|
+ * by @hw; if the usecount is 0, the clockdomain will be "disabled."
|
|
|
|
+ * Only needed for clocks that don't use omap2_dflt_clk_disable() as their
|
|
|
|
+ * disable function pointer. No return value.
|
|
|
|
+ */
|
|
|
|
+void omap2_clkops_disable_clkdm(struct clk_hw *hw)
|
|
|
|
+{
|
|
|
|
+ struct clk_hw_omap *clk;
|
|
|
|
+
|
|
|
|
+ clk = to_clk_hw_omap(hw);
|
|
|
|
+
|
|
|
|
+ if (unlikely(!clk->clkdm)) {
|
|
|
|
+ pr_err("%s: %s: no clkdm set ?!\n", __func__,
|
|
|
|
+ __clk_get_name(hw->clk));
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (unlikely(clk->enable_reg))
|
|
|
|
+ pr_err("%s: %s: should use dflt_clk_disable ?!\n", __func__,
|
|
|
|
+ __clk_get_name(hw->clk));
|
|
|
|
+
|
|
|
|
+ if (!clkdm_control) {
|
|
|
|
+ pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
|
|
|
|
+ __func__, __clk_get_name(hw->clk));
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ clkdm_clk_disable(clk->clkdm, hw->clk);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap2_dflt_clk_is_enabled - is clock enabled in the hardware?
|
|
|
|
+ * @hw: struct clk_hw * to check
|
|
|
|
+ *
|
|
|
|
+ * Return 1 if the clock represented by @hw is enabled in the
|
|
|
|
+ * hardware, or 0 otherwise. Intended for use in the struct
|
|
|
|
+ * clk_ops.is_enabled function pointer.
|
|
|
|
+ */
|
|
|
|
+int omap2_dflt_clk_is_enabled(struct clk_hw *hw)
|
|
|
|
+{
|
|
|
|
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
|
|
|
+ u32 v;
|
|
|
|
+
|
|
|
|
+ v = __raw_readl(clk->enable_reg);
|
|
|
|
+
|
|
|
|
+ if (clk->flags & INVERT_ENABLE)
|
|
|
|
+ v ^= BIT(clk->enable_bit);
|
|
|
|
+
|
|
|
|
+ v &= BIT(clk->enable_bit);
|
|
|
|
+
|
|
|
|
+ return v ? 1 : 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int __initdata mpurate;
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * By default we use the rate set by the bootloader.
|
|
|
|
+ * You can override this with mpurate= cmdline option.
|
|
|
|
+ */
|
|
|
|
+static int __init omap_clk_setup(char *str)
|
|
|
|
+{
|
|
|
|
+ get_option(&str, &mpurate);
|
|
|
|
+
|
|
|
|
+ if (!mpurate)
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ if (mpurate < 1000)
|
|
|
|
+ mpurate *= 1000000;
|
|
|
|
+
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+__setup("mpurate=", omap_clk_setup);
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap2_init_clk_hw_omap_clocks - initialize an OMAP clock
|
|
|
|
+ * @clk: struct clk * to initialize
|
|
|
|
+ *
|
|
|
|
+ * Add an OMAP clock @clk to the internal list of OMAP clocks. Used
|
|
|
|
+ * temporarily for autoidle handling, until this support can be
|
|
|
|
+ * integrated into the common clock framework code in some way. No
|
|
|
|
+ * return value.
|
|
|
|
+ */
|
|
|
|
+void omap2_init_clk_hw_omap_clocks(struct clk *clk)
|
|
|
|
+{
|
|
|
|
+ struct clk_hw_omap *c;
|
|
|
|
+
|
|
|
|
+ if (__clk_get_flags(clk) & CLK_IS_BASIC)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ c = to_clk_hw_omap(__clk_get_hw(clk));
|
|
|
|
+ list_add(&c->node, &clk_hw_omap_clocks);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap2_clk_enable_autoidle_all - enable autoidle on all OMAP clocks that
|
|
|
|
+ * support it
|
|
|
|
+ *
|
|
|
|
+ * Enable clock autoidle on all OMAP clocks that have allow_idle
|
|
|
|
+ * function pointers associated with them. This function is intended
|
|
|
|
+ * to be temporary until support for this is added to the common clock
|
|
|
|
+ * code. Returns 0.
|
|
|
|
+ */
|
|
|
|
+int omap2_clk_enable_autoidle_all(void)
|
|
|
|
+{
|
|
|
|
+ struct clk_hw_omap *c;
|
|
|
|
+
|
|
|
|
+ list_for_each_entry(c, &clk_hw_omap_clocks, node)
|
|
|
|
+ if (c->ops && c->ops->allow_idle)
|
|
|
|
+ c->ops->allow_idle(c);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * omap2_clk_disable_autoidle_all - disable autoidle on all OMAP clocks that
|
|
|
|
+ * support it
|
|
|
|
+ *
|
|
|
|
+ * Disable clock autoidle on all OMAP clocks that have allow_idle
|
|
|
|
+ * function pointers associated with them. This function is intended
|
|
|
|
+ * to be temporary until support for this is added to the common clock
|
|
|
|
+ * code. Returns 0.
|
|
|
|
+ */
|
|
|
|
+int omap2_clk_disable_autoidle_all(void)
|
|
|
|
+{
|
|
|
|
+ struct clk_hw_omap *c;
|
|
|
|
+
|
|
|
|
+ list_for_each_entry(c, &clk_hw_omap_clocks, node)
|
|
|
|
+ if (c->ops && c->ops->deny_idle)
|
|
|
|
+ c->ops->deny_idle(c);
|