[PATCH 05/10] clk: Add support for simple dividers
Uwe Kleine-König
u.kleine-koenig at pengutronix.de
Tue Apr 19 03:32:50 EDT 2011
Hello,
On Mon, Apr 18, 2011 at 07:45:53PM -0700, Saravana Kannan wrote:
> On 04/18/2011 03:07 AM, Sascha Hauer wrote:
> >On Mon, Apr 18, 2011 at 11:49:09AM +0200, Uwe Kleine-König wrote:
> >>On Fri, Apr 15, 2011 at 09:08:10PM +0200, Sascha Hauer wrote:
> >AFAIK there are two different implementation types in the tree. Some
> >implementations only allow to set to the exact rate round_rate returns
> >while others round down in set_rate.
> >
> >Has this been specified what behaviour is expected?
> >
>
> This is something I have nagged Russell once or twice about and then
> sent out an email to the list for which there was very limited
> response. I think clk_round_rate() is too generic and not very
> useful.
>
> We should really have something like:
> clk_set_rate_range(min, ideal, max)
(Note this is orthogonal to the question if set_rate may barf on values
other than the return values of round_rate.)
clk_set_rate_range can even be implemented with clk_round_rate that is
just required to fulfill:
clk_round_rate(clk, X) > 0 =>
clk_set_rate(clk, clk_round_rate(clk, X)) == clk_round_rate(clk, X)
and
clk_round_rate(clk, clk_round_rate(clk, X)) == clk_round_rate(clk, X)
and
X >= Y =>
clk_round_rate(clk, X) >= clk_round_rate(clk, Y)
which every implementation should assert provided that X and Y are the
domain of clk_round_rate(clk, .)
Something like:
long clk_round_rate_range(struct clk *clk, unsigned long minrate,
unsigned long optrate, unsigned long maxrate)
{
unsigned long bot = minrate, best, cur, top = maxrate;
unsigned long delta;
long tmp;
if (minrate > optrate || optrate > maxrate)
return -EINVAL;
if (maxrate > LONG_MAX)
/* can anything be done here? */
return -EINVAL;
best = cur = clk_round_rate(clk, optrate);
if (cur == optrate)
return optrate;
delta = optrate > best ? optrate - best : best - optrate;
while (1) {
if (cur > optrate) {
if (delta > cur - optrate)
best = cur;
top = cur;
cur = (bot + cur) / 2;
} else if (cur < optrate) {
if (delta > optrate - cur)
best = cur;
bot = cur;
cur = (cur + top + 1) / 2;
} else {
WARN(1, "Your clk_round_rate implementation is broken (clk = %pS, [%lu, %lu, %lu]\n.",
clk, minrate, optrate, maxrate);
return -EINVAL;
}
tmp = clk_round_rate(clk, cur);
if (tmp < 0)
return tmp;
cur = tmp;
if (bot == top)
break;
}
if (best < minrate || best > maxrate)
return -EINVAL;
return best;
}
int clk_set_rate_range(struct clk *clk, unsigned long minrate,
unsigned long optrate, unsigned long maxrate)
{
long rate = clk_round_rate_range(clk, minrate,
optrate, maxrate);
if (rate < 0)
return rate;
clk_set_rate(clk, rate);
}
Completely untestet so probably broken.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | http://www.pengutronix.de/ |
More information about the linux-arm-kernel
mailing list