Message ID | 20230918-imx8mp-dtsi-v1-3-1d008b3237c0@skidata.com (mailing list archive) |
---|---|
State | Changes Requested, archived |
Headers | show |
Series | imx8mp: first clock propagation attempt (for LVDS) | expand |
Hi, On Mon, Sep 18, 2023 at 12:39:59AM +0200, Benjamin Bara wrote: > From: Benjamin Bara <benjamin.bara@skidata.com> > > This function can be used to set the rate of a clock hardware from a > driver, e.g. to adapt the rate to a clock change coming from the parent. > > Signed-off-by: Benjamin Bara <benjamin.bara@skidata.com> > --- > drivers/clk/clk.c | 15 +++++++++++++++ > include/linux/clk-provider.h | 1 + > 2 files changed, 16 insertions(+) > > diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c > index c249f9791ae8..3e222802b712 100644 > --- a/drivers/clk/clk.c > +++ b/drivers/clk/clk.c > @@ -2462,6 +2462,21 @@ static int clk_core_set_rate_nolock(struct clk_core *core, > return ret; > } > > +int clk_hw_set_rate(struct clk_hw *hw, unsigned long req_rate) > +{ > + /* A rate change is ongoing, so just target the required rate. > + * Note: this does not work if one clock along the line has > + * CLK_RECALC_NEW_RATES active, as this overwrites the new_rate again. > + */ > + if (hw->core->new_rate != hw->core->rate) { > + hw->core->new_rate = req_rate; > + return 0; > + } > + > + return clk_core_set_rate_nolock(hw->core, req_rate); > +} > +EXPORT_SYMBOL_GPL(clk_hw_set_rate); So, we discussed it recently, and it's non-obvious to see how it would work if you're in a set_rate change that modifies the tree and the new call to clk_hw_set_rate modifies the tree too. Some explanation on how it's handled, and some unit tests are required here imo. Maxime
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index c249f9791ae8..3e222802b712 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2462,6 +2462,21 @@ static int clk_core_set_rate_nolock(struct clk_core *core, return ret; } +int clk_hw_set_rate(struct clk_hw *hw, unsigned long req_rate) +{ + /* A rate change is ongoing, so just target the required rate. + * Note: this does not work if one clock along the line has + * CLK_RECALC_NEW_RATES active, as this overwrites the new_rate again. + */ + if (hw->core->new_rate != hw->core->rate) { + hw->core->new_rate = req_rate; + return 0; + } + + return clk_core_set_rate_nolock(hw->core, req_rate); +} +EXPORT_SYMBOL_GPL(clk_hw_set_rate); + /** * clk_set_rate - specify a new rate for clk * @clk: the clk whose rate is being changed diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index ec32ec58c59f..3fb99ed5e8d9 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -1316,6 +1316,7 @@ int clk_hw_get_parent_index(struct clk_hw *hw); int clk_hw_set_parent(struct clk_hw *hw, struct clk_hw *new_parent); unsigned int __clk_get_enable_count(struct clk *clk); unsigned long clk_hw_get_rate(const struct clk_hw *hw); +int clk_hw_set_rate(struct clk_hw *hw, unsigned long req_rate); unsigned long clk_hw_get_flags(const struct clk_hw *hw); #define clk_hw_can_set_rate_parent(hw) \ (clk_hw_get_flags((hw)) & CLK_SET_RATE_PARENT)