On Thu, May 21, 2015 at 4:57 PM, Ezequiel Garcia <ezequiel.garcia@xxxxxxxxxx> wrote: > This commit implements small rate changes to the fractional PLL. > This is done using the PLL frac parameter. The .set_rate function > first finds the parameters associated to the closest nominal rate. > > Then the new rate is set, using parameters from the table entry, > except for the frac parameter, which is calculated from the rate > using the fractional PLL rate formula. > > Using .round_rate, the driver guarantees that only rates near > a table nominal rate is applied. To this extent, add two parameters > fout_min and fout_max, which allows to define the allowed rate > adjustment. > > Signed-off-by: Ezequiel Garcia <ezequiel.garcia@xxxxxxxxxx> > --- > drivers/clk/pistachio/clk-pll.c | 48 +++++++++++++++++++++++++++++++---------- > drivers/clk/pistachio/clk.h | 2 ++ > 2 files changed, 39 insertions(+), 11 deletions(-) > > diff --git a/drivers/clk/pistachio/clk-pll.c b/drivers/clk/pistachio/clk-pll.c > index f12d520..cf000bb 100644 > --- a/drivers/clk/pistachio/clk-pll.c > +++ b/drivers/clk/pistachio/clk-pll.c > @@ -90,29 +90,50 @@ static struct pistachio_pll_rate_table * > pll_get_params(struct pistachio_clk_pll *pll, unsigned long fref, > unsigned long fout) > { > - unsigned int i; > + unsigned int i, best; > + unsigned long err, best_err = ~0; > > for (i = 0; i < pll->nr_rates; i++) { > - if (pll->rates[i].fref == fref && pll->rates[i].fout == fout) > - return &pll->rates[i]; > + err = abs(pll->rates[i].fout - fout); > + if (pll->rates[i].fref == fref && err < best_err) { > + best = i; > + best_err = err; > + } > } > > - return NULL; > + return &pll->rates[best]; > } > > static long pll_round_rate(struct clk_hw *hw, unsigned long rate, > unsigned long *parent_rate) > { > struct pistachio_clk_pll *pll = to_pistachio_pll(hw); > - unsigned int i; > + unsigned int i, best; > + unsigned long err, best_err = ~0; > > for (i = 0; i < pll->nr_rates; i++) { > - if (i > 0 && pll->rates[i].fref == *parent_rate && > - pll->rates[i].fout <= rate) > - return pll->rates[i - 1].fout; > + err = abs(pll->rates[i].fout - rate); > + if (pll->rates[i].fref == *parent_rate && err < best_err) { > + best = i; > + best_err = err; > + } > } > > - return pll->rates[0].fout; > + /* Make sure fout_{min,max} parameters have sane values */ > + if (!pll->rates[best].fout_min) > + pll->rates[best].fout_min = pll->rates[best].fout; > + if (!pll->rates[best].fout_max) > + pll->rates[best].fout_max = pll->rates[best].fout; Perhaps the rate tables should just always populate fout_min and fout_max?