Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 221670
b: refs/heads/master
c: 6af26c6
h: refs/heads/master
v: v3
  • Loading branch information
Guennadi Liakhovetski authored and Paul Mundt committed Nov 8, 2010
1 parent d199fbe commit 6d30f6f
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5aefa34fada9d17a00635516688de34702451708
refs/heads/master: 6af26c6c99f01e810f9944543df810e320284aa3
75 changes: 75 additions & 0 deletions trunk/drivers/sh/clk/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,81 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
}
EXPORT_SYMBOL_GPL(clk_round_rate);

long clk_round_parent(struct clk *clk, unsigned long target,
unsigned long *best_freq, unsigned long *parent_freq,
unsigned int div_min, unsigned int div_max)
{
struct cpufreq_frequency_table *freq, *best = NULL;
unsigned long error = ULONG_MAX, freq_high, freq_low, div;
struct clk *parent = clk_get_parent(clk);

if (!parent) {
*parent_freq = 0;
*best_freq = clk_round_rate(clk, target);
return abs(target - *best_freq);
}

for (freq = parent->freq_table; freq->frequency != CPUFREQ_TABLE_END;
freq++) {
if (freq->frequency == CPUFREQ_ENTRY_INVALID)
continue;

if (unlikely(freq->frequency / target <= div_min - 1)) {
unsigned long freq_max = (freq->frequency + div_min / 2) / div_min;
if (error > target - freq_max) {
error = target - freq_max;
best = freq;
if (best_freq)
*best_freq = freq_max;
}
pr_debug("too low freq %lu, error %lu\n", freq->frequency, target - freq_max);
if (!error)
break;
continue;
}

if (unlikely(freq->frequency / target >= div_max)) {
unsigned long freq_min = (freq->frequency + div_max / 2) / div_max;
if (error > freq_min - target) {
error = freq_min - target;
best = freq;
if (best_freq)
*best_freq = freq_min;
}
pr_debug("too high freq %lu, error %lu\n", freq->frequency, freq_min - target);
if (!error)
break;
continue;
}


div = freq->frequency / target;
freq_high = freq->frequency / div;
freq_low = freq->frequency / (div + 1);
if (freq_high - target < error) {
error = freq_high - target;
best = freq;
if (best_freq)
*best_freq = freq_high;
}
if (target - freq_low < error) {
error = target - freq_low;
best = freq;
if (best_freq)
*best_freq = freq_low;
}
pr_debug("%u / %lu = %lu, / %lu = %lu, best %lu, parent %u\n",
freq->frequency, div, freq_high, div + 1, freq_low,
*best_freq, best->frequency);
if (!error)
break;
}
if (parent_freq)
*parent_freq = best->frequency;
return error;
}
EXPORT_SYMBOL_GPL(clk_round_parent);

#ifdef CONFIG_PM
static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
{
Expand Down
4 changes: 4 additions & 0 deletions trunk/include/linux/sh_clk.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ int clk_rate_table_find(struct clk *clk,
long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
unsigned int div_max, unsigned long rate);

long clk_round_parent(struct clk *clk, unsigned long target,
unsigned long *best_freq, unsigned long *parent_freq,
unsigned int div_min, unsigned int div_max);

#define SH_CLK_MSTP32(_parent, _enable_reg, _enable_bit, _flags) \
{ \
.parent = _parent, \
Expand Down

0 comments on commit 6d30f6f

Please sign in to comment.