summaryrefslogtreecommitdiff
path: root/drivers/sh
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sh')
-rw-r--r--drivers/sh/clk/core.c112
-rw-r--r--drivers/sh/clk/cpg.c7
-rw-r--r--drivers/sh/intc/core.c2
-rw-r--r--drivers/sh/intc/dynamic.c2
-rw-r--r--drivers/sh/intc/virq.c2
5 files changed, 106 insertions, 19 deletions
diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c
index fd0d1b98901c..3f5e387ed564 100644
--- a/drivers/sh/clk/core.c
+++ b/drivers/sh/clk/core.c
@@ -90,8 +90,8 @@ struct clk_rate_round_data {
static long clk_rate_round_helper(struct clk_rate_round_data *rounder)
{
unsigned long rate_error, rate_error_prev = ~0UL;
- unsigned long rate_best_fit = rounder->rate;
unsigned long highest, lowest, freq;
+ long rate_best_fit = -ENOENT;
int i;
highest = 0;
@@ -146,7 +146,7 @@ long clk_rate_table_round(struct clk *clk,
};
if (clk->nr_freqs < 1)
- return 0;
+ return -ENOSYS;
return clk_rate_round_helper(&table_round);
}
@@ -418,8 +418,11 @@ int clk_register(struct clk *clk)
list_add(&clk->sibling, &root_clks);
list_add(&clk->node, &clock_list);
+
+#ifdef CONFIG_SH_CLK_CPG_LEGACY
if (clk->ops && clk->ops->init)
clk->ops->init(clk);
+#endif
out_unlock:
mutex_unlock(&clock_list_sem);
@@ -455,19 +458,13 @@ EXPORT_SYMBOL_GPL(clk_get_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
- return clk_set_rate_ex(clk, rate, 0);
-}
-EXPORT_SYMBOL_GPL(clk_set_rate);
-
-int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
-{
int ret = -EOPNOTSUPP;
unsigned long flags;
spin_lock_irqsave(&clock_lock, flags);
if (likely(clk->ops && clk->ops->set_rate)) {
- ret = clk->ops->set_rate(clk, rate, algo_id);
+ ret = clk->ops->set_rate(clk, rate);
if (ret != 0)
goto out_unlock;
} else {
@@ -485,7 +482,7 @@ out_unlock:
return ret;
}
-EXPORT_SYMBOL_GPL(clk_set_rate_ex);
+EXPORT_SYMBOL_GPL(clk_set_rate);
int clk_set_parent(struct clk *clk, struct clk *parent)
{
@@ -541,6 +538,98 @@ 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_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 %u, error %lu\n", freq->frequency,
+ target - freq_max);
+
+ if (!error)
+ break;
+
+ continue;
+ }
+
+ if (unlikely(freq->frequency / target >= div_max)) {
+ unsigned long freq_min;
+
+ 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 %u, 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)
{
@@ -561,8 +650,7 @@ static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
clkp->ops->set_parent(clkp,
clkp->parent);
if (likely(clkp->ops->set_rate))
- clkp->ops->set_rate(clkp,
- rate, NO_CHANGE);
+ clkp->ops->set_rate(clkp, rate);
else if (likely(clkp->ops->recalc))
clkp->rate = clkp->ops->recalc(clkp);
}
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c
index 3aea5f0ceb09..6172335ae323 100644
--- a/drivers/sh/clk/cpg.c
+++ b/drivers/sh/clk/cpg.c
@@ -110,8 +110,7 @@ static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
return 0;
}
-static int sh_clk_div6_set_rate(struct clk *clk,
- unsigned long rate, int algo_id)
+static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long value;
int idx;
@@ -132,7 +131,7 @@ static int sh_clk_div6_enable(struct clk *clk)
unsigned long value;
int ret;
- ret = sh_clk_div6_set_rate(clk, clk->rate, 0);
+ ret = sh_clk_div6_set_rate(clk, clk->rate);
if (ret == 0) {
value = __raw_readl(clk->enable_reg);
value &= ~0x100; /* clear stop bit to enable clock */
@@ -253,7 +252,7 @@ static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
return 0;
}
-static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate, int algo_id)
+static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
{
struct clk_div4_table *d4t = clk->priv;
unsigned long value;
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c
index 873a99ff8f64..e5e9e6735f7d 100644
--- a/drivers/sh/intc/core.c
+++ b/drivers/sh/intc/core.c
@@ -79,7 +79,7 @@ static void __init intc_register_irq(struct intc_desc *desc,
* Register the IRQ position with the global IRQ map, then insert
* it in to the radix tree.
*/
- irq_reserve_irqs(irq, 1);
+ irq_reserve_irq(irq);
raw_spin_lock_irqsave(&intc_big_lock, flags);
radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq));
diff --git a/drivers/sh/intc/dynamic.c b/drivers/sh/intc/dynamic.c
index 4187cce20ffd..a3677c9dfe36 100644
--- a/drivers/sh/intc/dynamic.c
+++ b/drivers/sh/intc/dynamic.c
@@ -60,5 +60,5 @@ void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
int i;
for (i = 0; i < nr_vecs; i++)
- irq_reserve_irqs(evt2irq(vectors[i].vect), 1);
+ irq_reserve_irq(evt2irq(vectors[i].vect));
}
diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c
index e5bf5d3c698e..4e0ff7181164 100644
--- a/drivers/sh/intc/virq.c
+++ b/drivers/sh/intc/virq.c
@@ -215,7 +215,7 @@ restart:
entry = radix_tree_deref_slot((void **)entries[i]);
if (unlikely(!entry))
continue;
- if (unlikely(entry == RADIX_TREE_RETRY))
+ if (radix_tree_deref_retry(entry))
goto restart;
irq = create_irq();