diff options
author | Magnus Damm <damm@igel.co.jp> | 2009-05-25 04:10:28 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-05-26 04:08:39 -0400 |
commit | c94a85746f7bdc13035acdf88c130d7b6fa41bde (patch) | |
tree | 8aff35100dcb0a62c82452357ea267f92376dc7a | |
parent | c9904dd15922f349b5f06839e34b1723d4a75940 (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.h | 18 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/clock.c | 75 |
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 | ||
103 | struct clk_div_mult_table { | ||
104 | unsigned int *divisors; | ||
105 | unsigned int nr_divisors; | ||
106 | unsigned int *multipliers; | ||
107 | unsigned int nr_multipliers; | ||
108 | }; | ||
109 | |||
110 | struct cpufreq_frequency_table; | ||
111 | void 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 | |||
117 | long 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); | |||
36 | static DEFINE_SPINLOCK(clock_lock); | 37 | static DEFINE_SPINLOCK(clock_lock); |
37 | static DEFINE_MUTEX(clock_list_sem); | 38 | static DEFINE_MUTEX(clock_list_sem); |
38 | 39 | ||
40 | void 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 | |||
74 | long 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 */ |
40 | unsigned long followparent_recalc(struct clk *clk) | 115 | unsigned long followparent_recalc(struct clk *clk) |
41 | { | 116 | { |