From 5aefa34fada9d17a00635516688de34702451708 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 1 Nov 2010 15:30:31 -0400 Subject: sh: clkfwk: Fix up rate rounding error handling. According to the linux/clk.h definition we should be handing back an errno value or a valid rate. This fixes up the case where 0 can be returned for invalid frequencies or cases where rounding has no selectable candidate. Reported-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/sh/clk/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/sh') diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index fd0d1b98901c..861144360d89 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); } -- cgit v1.2.3 From 20f95e0b22ea45c1798261064baab57efeb3b3bc Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 1 Nov 2010 16:10:48 -0400 Subject: sh: intc: Update for single IRQ reservation helper. Signed-off-by: Paul Mundt --- drivers/sh/intc/core.c | 2 +- drivers/sh/intc/dynamic.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/sh') 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)); } -- cgit v1.2.3 From 6af26c6c99f01e810f9944543df810e320284aa3 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 2 Nov 2010 11:27:24 +0000 Subject: sh: add clk_round_parent() to optimize parent clock rate Sometimes it is possible and reasonable to adjust the parent clock rate to improve precision of the child clock, e.g., if the child clock has no siblings. clk_round_parent() is a new addition to the SH clock-framework API, that implements such an optimization for child clocks with divisors, taking all integer values in a range. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/sh/clk/core.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) (limited to 'drivers/sh') diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index 861144360d89..b3840597ad6e 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -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) { -- cgit v1.2.3 From a766b29790b2b6582345624a6e9e686d8015efe1 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 8 Nov 2010 09:40:23 +0900 Subject: sh: clkfwk: Fix up checkpatch warnings. The clk_round_parent() change introduced various checkpatch warnings, tidy them up. Signed-off-by: Paul Mundt --- drivers/sh/clk/core.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'drivers/sh') diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index b3840597ad6e..09615b51d591 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -561,57 +561,74 @@ long clk_round_parent(struct clk *clk, unsigned long target, continue; if (unlikely(freq->frequency / target <= div_min - 1)) { - unsigned long freq_max = (freq->frequency + div_min / 2) / div_min; + 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 %lu, error %lu\n", freq->frequency, target - 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; + 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 %lu, error %lu\n", freq->frequency, freq_min - target); + + 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); -- cgit v1.2.3 From ed10b490ea6498f76284043565d42ca3649ccca1 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 10 Nov 2010 18:02:25 +0900 Subject: sh: clkfwk: fix up compiler warnings. CC drivers/sh/clk/core.o drivers/sh/clk/core.c: In function 'clk_round_parent': drivers/sh/clk/core.c:574: warning: format '%lu' expects type 'long unsigned int', but argument 2 has type 'unsigned int' drivers/sh/clk/core.c:594: warning: format '%lu' expects type 'long unsigned int', but argument 2 has type 'unsigned int' Signed-off-by: Paul Mundt --- drivers/sh/clk/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/sh') diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index 09615b51d591..cb12a8e1466b 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -571,7 +571,7 @@ long clk_round_parent(struct clk *clk, unsigned long target, *best_freq = freq_max; } - pr_debug("too low freq %lu, error %lu\n", freq->frequency, + pr_debug("too low freq %u, error %lu\n", freq->frequency, target - freq_max); if (!error) @@ -591,7 +591,7 @@ long clk_round_parent(struct clk *clk, unsigned long target, *best_freq = freq_min; } - pr_debug("too high freq %lu, error %lu\n", freq->frequency, + pr_debug("too high freq %u, error %lu\n", freq->frequency, freq_min - target); if (!error) -- cgit v1.2.3 From 6318af900ca7cb2c94b27d3c358762e6ac187e25 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 15 Nov 2010 14:30:30 +0900 Subject: sh: intc: Fix up build failure introduced by radix tree changes. The radix tree retry logic got a bit of an overhaul and subsequently broke the virtual IRQ subgroup build. Simply switch over to radix_tree_deref_retry() as per the filemap changes, which the virq lookup logic was modelled after in the first place. Signed-off-by: Paul Mundt --- drivers/sh/intc/virq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/sh') 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(); -- cgit v1.2.3 From 9a1683d1dd14d6ed35d2884c6b79ff12fc6bef39 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 15 Nov 2010 18:14:43 +0900 Subject: sh: clkfwk: Kill off unused clk_set_rate_ex(). With the refactoring of the SH7722 clock framework some time ago this abstraction has become unecessary. Kill it off before anyone else gets the bright idea to start using it. Signed-off-by: Paul Mundt --- drivers/sh/clk/core.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers/sh') diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index cb12a8e1466b..69be6bb92323 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -454,12 +454,6 @@ unsigned long clk_get_rate(struct clk *clk) 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; @@ -467,7 +461,7 @@ int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id) 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, 0); if (ret != 0) goto out_unlock; } else { @@ -485,7 +479,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) { @@ -654,7 +648,7 @@ static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state) clkp->parent); if (likely(clkp->ops->set_rate)) clkp->ops->set_rate(clkp, - rate, NO_CHANGE); + rate, 0); else if (likely(clkp->ops->recalc)) clkp->rate = clkp->ops->recalc(clkp); } -- cgit v1.2.3 From 35a96c739fd7624b8edff990a74b86b5a85342da Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 15 Nov 2010 18:18:32 +0900 Subject: sh: clkfwk: Kill off now unused algo_id in set_rate op. Now that clk_set_rate_ex() is gone, there is also no way to get at rate setting algo id, which is now also completely unused. Kill it off before new clock ops start using it. Signed-off-by: Paul Mundt --- drivers/sh/clk/core.c | 5 ++--- drivers/sh/clk/cpg.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/sh') diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index 69be6bb92323..87743e7d4d42 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -461,7 +461,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate) spin_lock_irqsave(&clock_lock, flags); if (likely(clk->ops && clk->ops->set_rate)) { - ret = clk->ops->set_rate(clk, rate, 0); + ret = clk->ops->set_rate(clk, rate); if (ret != 0) goto out_unlock; } else { @@ -647,8 +647,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, 0); + 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..359e9a322c7b 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; @@ -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; -- cgit v1.2.3 From f278ea849e15147269190e943937fa82e66078b1 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Fri, 19 Nov 2010 16:40:35 +0900 Subject: sh: clkfwk: Build fix for non-legacy CPG changes. The disabling of the init op for non-legacy clocks neglected to do the same in the core clock framework, resulting in a build failure. Fix it up. Reported-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/sh/clk/core.c | 3 +++ drivers/sh/clk/cpg.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/sh') diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index 87743e7d4d42..3f5e387ed564 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -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); diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c index 359e9a322c7b..6172335ae323 100644 --- a/drivers/sh/clk/cpg.c +++ b/drivers/sh/clk/cpg.c @@ -131,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 */ -- cgit v1.2.3