Loading drivers/clk/clk.c +72 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,8 @@ struct clk_core { unsigned int enable_count; unsigned int prepare_count; unsigned int protect_count; bool need_handoff_enable; bool need_handoff_prepare; unsigned long min_rate; unsigned long max_rate; unsigned long accuracy; Loading Loading @@ -1078,6 +1080,19 @@ int clk_prepare(struct clk *clk) if (!clk) return 0; /* * setting CLK_ENABLE_HAND_OFF flag triggers this conditional * * need_handoff_prepare implies this clk was already prepared by * __clk_init. now we have a proper user, so unset the flag in our * internal bookkeeping. See CLK_ENABLE_HAND_OFF flag in clk-provider.h * for details. */ if (clk->core->need_handoff_prepare) { clk->core->need_handoff_prepare = false; return 0; } return clk_core_prepare_lock(clk->core); } EXPORT_SYMBOL_GPL(clk_prepare); Loading Loading @@ -1205,6 +1220,19 @@ int clk_enable(struct clk *clk) if (!clk) return 0; /* * setting CLK_ENABLE_HAND_OFF flag triggers this conditional * * need_handoff_enable implies this clk was already enabled by * __clk_init. now we have a proper user, so unset the flag in our * internal bookkeeping. See CLK_ENABLE_HAND_OFF flag in clk-provider.h * for details. */ if (clk->core->need_handoff_enable) { clk->core->need_handoff_enable = false; return 0; } return clk_core_enable_lock(clk->core); } EXPORT_SYMBOL_GPL(clk_enable); Loading Loading @@ -3423,6 +3451,50 @@ static int __clk_core_init(struct clk_core *core) } } /* * optional platform-specific magic * * The .init callback is not used by any of the basic clock types, but * exists for weird hardware that must perform initialization magic. * Please consider other ways of solving initialization problems before * using this callback, as its use is discouraged. */ if (core->ops->init) core->ops->init(core->hw); if (core->flags & CLK_IS_CRITICAL) { unsigned long flags; clk_core_prepare(core); flags = clk_enable_lock(); clk_core_enable(core); clk_enable_unlock(flags); } /* * enable clocks with the CLK_ENABLE_HAND_OFF flag set * * This flag causes the framework to enable the clock at registration * time, which is sometimes necessary for clocks that would cause a * system crash when gated (e.g. cpu, memory, etc). The prepare_count * is migrated over to the first clk consumer to call clk_prepare(). * Similarly the clk's enable_count is migrated to the first consumer * to call clk_enable(). */ if (core->flags & CLK_ENABLE_HAND_OFF) { unsigned long flags; core->need_handoff_prepare = true; core->need_handoff_enable = true; ret = clk_core_prepare(core); if (ret) goto out; flags = clk_enable_lock(); clk_core_enable(core); clk_enable_unlock(flags); } kref_init(&core->ref); out: clk_pm_runtime_put(core); Loading include/linux/clk-provider.h +5 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,11 @@ #define CLK_OPS_PARENT_ENABLE BIT(12) /* duty cycle call may be forwarded to the parent clock */ #define CLK_DUTY_CYCLE_PARENT BIT(13) #define CLK_ENABLE_HAND_OFF BIT(14) /* enable clock when registered. */ /* * hand-off enable_count & prepare_count * to first consumer that enables clk */ struct clk; struct clk_hw; Loading Loading
drivers/clk/clk.c +72 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,8 @@ struct clk_core { unsigned int enable_count; unsigned int prepare_count; unsigned int protect_count; bool need_handoff_enable; bool need_handoff_prepare; unsigned long min_rate; unsigned long max_rate; unsigned long accuracy; Loading Loading @@ -1078,6 +1080,19 @@ int clk_prepare(struct clk *clk) if (!clk) return 0; /* * setting CLK_ENABLE_HAND_OFF flag triggers this conditional * * need_handoff_prepare implies this clk was already prepared by * __clk_init. now we have a proper user, so unset the flag in our * internal bookkeeping. See CLK_ENABLE_HAND_OFF flag in clk-provider.h * for details. */ if (clk->core->need_handoff_prepare) { clk->core->need_handoff_prepare = false; return 0; } return clk_core_prepare_lock(clk->core); } EXPORT_SYMBOL_GPL(clk_prepare); Loading Loading @@ -1205,6 +1220,19 @@ int clk_enable(struct clk *clk) if (!clk) return 0; /* * setting CLK_ENABLE_HAND_OFF flag triggers this conditional * * need_handoff_enable implies this clk was already enabled by * __clk_init. now we have a proper user, so unset the flag in our * internal bookkeeping. See CLK_ENABLE_HAND_OFF flag in clk-provider.h * for details. */ if (clk->core->need_handoff_enable) { clk->core->need_handoff_enable = false; return 0; } return clk_core_enable_lock(clk->core); } EXPORT_SYMBOL_GPL(clk_enable); Loading Loading @@ -3423,6 +3451,50 @@ static int __clk_core_init(struct clk_core *core) } } /* * optional platform-specific magic * * The .init callback is not used by any of the basic clock types, but * exists for weird hardware that must perform initialization magic. * Please consider other ways of solving initialization problems before * using this callback, as its use is discouraged. */ if (core->ops->init) core->ops->init(core->hw); if (core->flags & CLK_IS_CRITICAL) { unsigned long flags; clk_core_prepare(core); flags = clk_enable_lock(); clk_core_enable(core); clk_enable_unlock(flags); } /* * enable clocks with the CLK_ENABLE_HAND_OFF flag set * * This flag causes the framework to enable the clock at registration * time, which is sometimes necessary for clocks that would cause a * system crash when gated (e.g. cpu, memory, etc). The prepare_count * is migrated over to the first clk consumer to call clk_prepare(). * Similarly the clk's enable_count is migrated to the first consumer * to call clk_enable(). */ if (core->flags & CLK_ENABLE_HAND_OFF) { unsigned long flags; core->need_handoff_prepare = true; core->need_handoff_enable = true; ret = clk_core_prepare(core); if (ret) goto out; flags = clk_enable_lock(); clk_core_enable(core); clk_enable_unlock(flags); } kref_init(&core->ref); out: clk_pm_runtime_put(core); Loading
include/linux/clk-provider.h +5 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,11 @@ #define CLK_OPS_PARENT_ENABLE BIT(12) /* duty cycle call may be forwarded to the parent clock */ #define CLK_DUTY_CYCLE_PARENT BIT(13) #define CLK_ENABLE_HAND_OFF BIT(14) /* enable clock when registered. */ /* * hand-off enable_count & prepare_count * to first consumer that enables clk */ struct clk; struct clk_hw; Loading