aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMagnus Damm <damm@igel.co.jp>2009-05-25 04:10:28 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-05-26 04:08:39 -0400
commitc94a85746f7bdc13035acdf88c130d7b6fa41bde (patch)
tree8aff35100dcb0a62c82452357ea267f92376dc7a
parentc9904dd15922f349b5f06839e34b1723d4a75940 (diff)
sh: add shared clock framework frequency table code
Add SuperH-specific clock framework helper functions: - clk_rate_table_build() - build cpufreq table from divisors/multipliers - clk_rate_table_round() - use cpufreq table to find matching frequency Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r--arch/sh/include/asm/clock.h18
-rw-r--r--arch/sh/kernel/cpu/clock.c75
2 files changed, 93 insertions, 0 deletions
diff --git a/arch/sh/include/asm/clock.h b/arch/sh/include/asm/clock.h
index 64c93cb3d685..60d5d2bc714a 100644
--- a/arch/sh/include/asm/clock.h
+++ b/arch/sh/include/asm/clock.h
@@ -100,4 +100,22 @@ enum clk_sh_algo_id {
100 IP_N1, 100 IP_N1,
101}; 101};
102 102
103struct clk_div_mult_table {
104 unsigned int *divisors;
105 unsigned int nr_divisors;
106 unsigned int *multipliers;
107 unsigned int nr_multipliers;
108};
109
110struct cpufreq_frequency_table;
111void clk_rate_table_build(struct clk *clk,
112 struct cpufreq_frequency_table *freq_table,
113 int nr_freqs,
114 struct clk_div_mult_table *src_table,
115 unsigned long *bitmap);
116
117long clk_rate_table_round(struct clk *clk,
118 struct cpufreq_frequency_table *freq_table,
119 unsigned long rate);
120
103#endif /* __ASM_SH_CLOCK_H */ 121#endif /* __ASM_SH_CLOCK_H */
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index 012d23476a72..59764d6c5f41 100644
--- a/arch/sh/kernel/cpu/clock.c
+++ b/arch/sh/kernel/cpu/clock.c
@@ -29,6 +29,7 @@
29#include <linux/err.h> 29#include <linux/err.h>
30#include <linux/platform_device.h> 30#include <linux/platform_device.h>
31#include <linux/debugfs.h> 31#include <linux/debugfs.h>
32#include <linux/cpufreq.h>
32#include <asm/clock.h> 33#include <asm/clock.h>
33#include <asm/machvec.h> 34#include <asm/machvec.h>
34 35
@@ -36,6 +37,80 @@ static LIST_HEAD(clock_list);
36static DEFINE_SPINLOCK(clock_lock); 37static DEFINE_SPINLOCK(clock_lock);
37static DEFINE_MUTEX(clock_list_sem); 38static DEFINE_MUTEX(clock_list_sem);
38 39
40void clk_rate_table_build(struct clk *clk,
41 struct cpufreq_frequency_table *freq_table,
42 int nr_freqs,
43 struct clk_div_mult_table *src_table,
44 unsigned long *bitmap)
45{
46 unsigned long mult, div;
47 unsigned long freq;
48 int i;
49
50 for (i = 0; i < nr_freqs; i++) {
51 div = 1;
52 mult = 1;
53
54 if (src_table->divisors && i < src_table->nr_divisors)
55 div = src_table->divisors[i];
56
57 if (src_table->multipliers && i < src_table->nr_multipliers)
58 mult = src_table->multipliers[i];
59
60 if (!div || !mult || (bitmap && !test_bit(i, bitmap)))
61 freq = CPUFREQ_ENTRY_INVALID;
62 else
63 freq = clk->parent->rate * mult / div;
64
65 freq_table[i].index = i;
66 freq_table[i].frequency = freq;
67 }
68
69 /* Termination entry */
70 freq_table[i].index = i;
71 freq_table[i].frequency = CPUFREQ_TABLE_END;
72}
73
74long clk_rate_table_round(struct clk *clk,
75 struct cpufreq_frequency_table *freq_table,
76 unsigned long rate)
77{
78 unsigned long rate_error, rate_error_prev = ~0UL;
79 unsigned long rate_best_fit = rate;
80 unsigned long highest, lowest;
81 int i;
82
83 highest = lowest = 0;
84
85 for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
86 unsigned long freq = freq_table[i].frequency;
87
88 if (freq == CPUFREQ_ENTRY_INVALID)
89 continue;
90
91 if (freq > highest)
92 highest = freq;
93 if (freq < lowest)
94 lowest = freq;
95
96 rate_error = abs(freq - rate);
97 if (rate_error < rate_error_prev) {
98 rate_best_fit = freq;
99 rate_error_prev = rate_error;
100 }
101
102 if (rate_error == 0)
103 break;
104 }
105
106 if (rate >= highest)
107 rate_best_fit = highest;
108 if (rate <= lowest)
109 rate_best_fit = lowest;
110
111 return rate_best_fit;
112}
113
39/* Used for clocks that always have same value as the parent clock */ 114/* Used for clocks that always have same value as the parent clock */
40unsigned long followparent_recalc(struct clk *clk) 115unsigned long followparent_recalc(struct clk *clk)
41{ 116{