[PATCH 1/1] clk: Add notifier support in clk_prepare/clk_unprepare

Mike Turquette mturquette at linaro.org
Tue Mar 19 13:01:40 EDT 2013


Quoting Bill Huang (2013-03-19 06:28:32)
> Add notifier calls in clk_prepare and clk_unprepare so drivers which are
> interested in knowing that clk_prepare/unprepare call can act accordingly.
> 
> The existing "clk_set_rate" notifier is not enough for normal DVFS
> inplementation since clock might be enabled/disabled at runtime. Adding
> these notifiers is useful on DVFS core which take clk_prepare as a hint
> on that the notified clock might be enabled later so it can raise voltage
> to a safe level before enabling the clock, and take clk_unprepare as a
> hint that the clock has been disabled and is safe to lower the voltage.
> 
> The added notifier events are:
> 
> PRE_CLK_PREPARE
> POST_CLK_PREPARE
> ABORT_CLK_PREPARE
> PRE_CLK_UNPREPARE
> POST_CLK_UNPREPARE
> 
> Signed-off-by: Bill Huang <bilhuang at nvidia.com>

Is this a resend or a new version?  It would be nice to put RESEND in
the patch $SUBJECT or put a changelog from previous patches under the
"---" below.

I'm still not sure about this approach.  Based on feedback I got from
Linaro Connect I am not convinced that scaling voltage through clk
rate-change notifiers is the right way to go.  As I understand it this
patch only exists for that single purpose, so if the voltage-notifier
idea gets dropped then I will not take this patch in.

Regards,
Mike

> ---
>  drivers/clk/clk.c   |   88 ++++++++++++++++++++++++++++++---------------------
>  include/linux/clk.h |    5 +++
>  2 files changed, 57 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index ed87b24..ac07c6e 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -516,6 +516,42 @@ struct clk *__clk_lookup(const char *name)
>  
>  /***        clk api        ***/
>  
> +/**
> + * __clk_notify - call clk notifier chain
> + * @clk: struct clk * that is changing rate
> + * @msg: clk notifier type (see include/linux/clk.h)
> + * @old_rate: old clk rate
> + * @new_rate: new clk rate
> + *
> + * Triggers a notifier call chain on the clk rate-change notification
> + * for 'clk'.  Passes a pointer to the struct clk and the previous
> + * and current rates to the notifier callback.  Intended to be called by
> + * internal clock code only.  Returns NOTIFY_DONE from the last driver
> + * called if all went well, or NOTIFY_STOP or NOTIFY_BAD immediately if
> + * a driver returns that.
> + */
> +static int __clk_notify(struct clk *clk, unsigned long msg,
> +               unsigned long old_rate, unsigned long new_rate)
> +{
> +       struct clk_notifier *cn;
> +       struct clk_notifier_data cnd;
> +       int ret = NOTIFY_DONE;
> +
> +       cnd.clk = clk;
> +       cnd.old_rate = old_rate;
> +       cnd.new_rate = new_rate;
> +
> +       list_for_each_entry(cn, &clk_notifier_list, node) {
> +               if (cn->clk == clk) {
> +                       ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
> +                                       &cnd);
> +                       break;
> +               }
> +       }
> +
> +       return ret;
> +}
> +
>  void __clk_unprepare(struct clk *clk)
>  {
>         if (!clk)
> @@ -549,7 +585,14 @@ void __clk_unprepare(struct clk *clk)
>  void clk_unprepare(struct clk *clk)
>  {
>         mutex_lock(&prepare_lock);
> +
> +       if (clk->notifier_count)
> +               __clk_notify(clk, PRE_CLK_UNPREPARE, clk->rate, clk->rate);
> +
>         __clk_unprepare(clk);
> +       if (clk->notifier_count)
> +               __clk_notify(clk, POST_CLK_UNPREPARE, clk->rate, clk->rate);
> +
>         mutex_unlock(&prepare_lock);
>  }
>  EXPORT_SYMBOL_GPL(clk_unprepare);
> @@ -597,7 +640,16 @@ int clk_prepare(struct clk *clk)
>         int ret;
>  
>         mutex_lock(&prepare_lock);
> +
> +       if (clk->notifier_count)
> +               __clk_notify(clk, PRE_CLK_PREPARE, clk->rate, clk->rate);
> +
>         ret = __clk_prepare(clk);
> +       if (!ret && clk->notifier_count)
> +               __clk_notify(clk, POST_CLK_PREPARE, clk->rate, clk->rate);
> +       else if (clk->notifier_count)
> +               __clk_notify(clk, ABORT_CLK_PREPARE, clk->rate, clk->rate);
> +
>         mutex_unlock(&prepare_lock);
>  
>         return ret;
> @@ -749,42 +801,6 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
>  EXPORT_SYMBOL_GPL(clk_round_rate);
>  
>  /**
> - * __clk_notify - call clk notifier chain
> - * @clk: struct clk * that is changing rate
> - * @msg: clk notifier type (see include/linux/clk.h)
> - * @old_rate: old clk rate
> - * @new_rate: new clk rate
> - *
> - * Triggers a notifier call chain on the clk rate-change notification
> - * for 'clk'.  Passes a pointer to the struct clk and the previous
> - * and current rates to the notifier callback.  Intended to be called by
> - * internal clock code only.  Returns NOTIFY_DONE from the last driver
> - * called if all went well, or NOTIFY_STOP or NOTIFY_BAD immediately if
> - * a driver returns that.
> - */
> -static int __clk_notify(struct clk *clk, unsigned long msg,
> -               unsigned long old_rate, unsigned long new_rate)
> -{
> -       struct clk_notifier *cn;
> -       struct clk_notifier_data cnd;
> -       int ret = NOTIFY_DONE;
> -
> -       cnd.clk = clk;
> -       cnd.old_rate = old_rate;
> -       cnd.new_rate = new_rate;
> -
> -       list_for_each_entry(cn, &clk_notifier_list, node) {
> -               if (cn->clk == clk) {
> -                       ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
> -                                       &cnd);
> -                       break;
> -               }
> -       }
> -
> -       return ret;
> -}
> -
> -/**
>   * __clk_recalc_rates
>   * @clk: first clk in the subtree
>   * @msg: notification type (see include/linux/clk.h)
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index b3ac22d..41d567d 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -43,6 +43,11 @@ struct clk;
>  #define PRE_RATE_CHANGE                        BIT(0)
>  #define POST_RATE_CHANGE               BIT(1)
>  #define ABORT_RATE_CHANGE              BIT(2)
> +#define PRE_CLK_PREPARE                        BIT(3)
> +#define POST_CLK_PREPARE               BIT(4)
> +#define ABORT_CLK_PREPARE              BIT(5)
> +#define PRE_CLK_UNPREPARE              BIT(6)
> +#define POST_CLK_UNPREPARE             BIT(7)
>  
>  /**
>   * struct clk_notifier - associate a clk with a notifier
> -- 
> 1.7.9.5



More information about the linux-arm-kernel mailing list