aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sh/clk
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
commit8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch)
treea8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/sh/clk
parent406089d01562f1e2bf9f089fd7637009ebaad589 (diff)
Patched in Tegra support.
Diffstat (limited to 'drivers/sh/clk')
-rw-r--r--drivers/sh/clk/core.c116
-rw-r--r--drivers/sh/clk/cpg.c482
2 files changed, 285 insertions, 313 deletions
diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c
index 7715de2629c..dc8d022c07a 100644
--- a/drivers/sh/clk/core.c
+++ b/drivers/sh/clk/core.c
@@ -25,6 +25,7 @@
25#include <linux/seq_file.h> 25#include <linux/seq_file.h>
26#include <linux/err.h> 26#include <linux/err.h>
27#include <linux/io.h> 27#include <linux/io.h>
28#include <linux/debugfs.h>
28#include <linux/cpufreq.h> 29#include <linux/cpufreq.h>
29#include <linux/clk.h> 30#include <linux/clk.h>
30#include <linux/sh_clk.h> 31#include <linux/sh_clk.h>
@@ -172,26 +173,6 @@ long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
172 return clk_rate_round_helper(&div_range_round); 173 return clk_rate_round_helper(&div_range_round);
173} 174}
174 175
175static long clk_rate_mult_range_iter(unsigned int pos,
176 struct clk_rate_round_data *rounder)
177{
178 return clk_get_rate(rounder->arg) * pos;
179}
180
181long clk_rate_mult_range_round(struct clk *clk, unsigned int mult_min,
182 unsigned int mult_max, unsigned long rate)
183{
184 struct clk_rate_round_data mult_range_round = {
185 .min = mult_min,
186 .max = mult_max,
187 .func = clk_rate_mult_range_iter,
188 .arg = clk_get_parent(clk),
189 .rate = rate,
190 };
191
192 return clk_rate_round_helper(&mult_range_round);
193}
194
195int clk_rate_table_find(struct clk *clk, 176int clk_rate_table_find(struct clk *clk,
196 struct cpufreq_frequency_table *freq_table, 177 struct cpufreq_frequency_table *freq_table,
197 unsigned long rate) 178 unsigned long rate)
@@ -224,6 +205,9 @@ int clk_reparent(struct clk *child, struct clk *parent)
224 list_add(&child->sibling, &parent->children); 205 list_add(&child->sibling, &parent->children);
225 child->parent = parent; 206 child->parent = parent;
226 207
208 /* now do the debugfs renaming to reattach the child
209 to the proper parent */
210
227 return 0; 211 return 0;
228} 212}
229 213
@@ -355,7 +339,7 @@ static int clk_establish_mapping(struct clk *clk)
355 */ 339 */
356 if (!clk->parent) { 340 if (!clk->parent) {
357 clk->mapping = &dummy_mapping; 341 clk->mapping = &dummy_mapping;
358 goto out; 342 return 0;
359 } 343 }
360 344
361 /* 345 /*
@@ -384,9 +368,6 @@ static int clk_establish_mapping(struct clk *clk)
384 } 368 }
385 369
386 clk->mapping = mapping; 370 clk->mapping = mapping;
387out:
388 clk->mapped_reg = clk->mapping->base;
389 clk->mapped_reg += (phys_addr_t)clk->enable_reg - clk->mapping->phys;
390 return 0; 371 return 0;
391} 372}
392 373
@@ -405,12 +386,10 @@ static void clk_teardown_mapping(struct clk *clk)
405 386
406 /* Nothing to do */ 387 /* Nothing to do */
407 if (mapping == &dummy_mapping) 388 if (mapping == &dummy_mapping)
408 goto out; 389 return;
409 390
410 kref_put(&mapping->ref, clk_destroy_mapping); 391 kref_put(&mapping->ref, clk_destroy_mapping);
411 clk->mapping = NULL; 392 clk->mapping = NULL;
412out:
413 clk->mapped_reg = NULL;
414} 393}
415 394
416int clk_register(struct clk *clk) 395int clk_register(struct clk *clk)
@@ -686,6 +665,89 @@ static int __init clk_syscore_init(void)
686subsys_initcall(clk_syscore_init); 665subsys_initcall(clk_syscore_init);
687#endif 666#endif
688 667
668/*
669 * debugfs support to trace clock tree hierarchy and attributes
670 */
671static struct dentry *clk_debugfs_root;
672
673static int clk_debugfs_register_one(struct clk *c)
674{
675 int err;
676 struct dentry *d;
677 struct clk *pa = c->parent;
678 char s[255];
679 char *p = s;
680
681 p += sprintf(p, "%p", c);
682 d = debugfs_create_dir(s, pa ? pa->dentry : clk_debugfs_root);
683 if (!d)
684 return -ENOMEM;
685 c->dentry = d;
686
687 d = debugfs_create_u8("usecount", S_IRUGO, c->dentry, (u8 *)&c->usecount);
688 if (!d) {
689 err = -ENOMEM;
690 goto err_out;
691 }
692 d = debugfs_create_u32("rate", S_IRUGO, c->dentry, (u32 *)&c->rate);
693 if (!d) {
694 err = -ENOMEM;
695 goto err_out;
696 }
697 d = debugfs_create_x32("flags", S_IRUGO, c->dentry, (u32 *)&c->flags);
698 if (!d) {
699 err = -ENOMEM;
700 goto err_out;
701 }
702 return 0;
703
704err_out:
705 debugfs_remove_recursive(c->dentry);
706 return err;
707}
708
709static int clk_debugfs_register(struct clk *c)
710{
711 int err;
712 struct clk *pa = c->parent;
713
714 if (pa && !pa->dentry) {
715 err = clk_debugfs_register(pa);
716 if (err)
717 return err;
718 }
719
720 if (!c->dentry) {
721 err = clk_debugfs_register_one(c);
722 if (err)
723 return err;
724 }
725 return 0;
726}
727
728static int __init clk_debugfs_init(void)
729{
730 struct clk *c;
731 struct dentry *d;
732 int err;
733
734 d = debugfs_create_dir("clock", NULL);
735 if (!d)
736 return -ENOMEM;
737 clk_debugfs_root = d;
738
739 list_for_each_entry(c, &clock_list, node) {
740 err = clk_debugfs_register(c);
741 if (err)
742 goto err_out;
743 }
744 return 0;
745err_out:
746 debugfs_remove_recursive(clk_debugfs_root);
747 return err;
748}
749late_initcall(clk_debugfs_init);
750
689static int __init clk_late_init(void) 751static int __init clk_late_init(void)
690{ 752{
691 unsigned long flags; 753 unsigned long flags;
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c
index 5aedcdf4ac5..82dd6fb1783 100644
--- a/drivers/sh/clk/cpg.c
+++ b/drivers/sh/clk/cpg.c
@@ -2,7 +2,6 @@
2 * Helper routines for SuperH Clock Pulse Generator blocks (CPG). 2 * Helper routines for SuperH Clock Pulse Generator blocks (CPG).
3 * 3 *
4 * Copyright (C) 2010 Magnus Damm 4 * Copyright (C) 2010 Magnus Damm
5 * Copyright (C) 2010 - 2012 Paul Mundt
6 * 5 *
7 * This file is subject to the terms and conditions of the GNU General Public 6 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file "COPYING" in the main directory of this archive 7 * License. See the file "COPYING" in the main directory of this archive
@@ -14,46 +13,26 @@
14#include <linux/io.h> 13#include <linux/io.h>
15#include <linux/sh_clk.h> 14#include <linux/sh_clk.h>
16 15
17#define CPG_CKSTP_BIT BIT(8) 16static int sh_clk_mstp32_enable(struct clk *clk)
18
19static unsigned int sh_clk_read(struct clk *clk)
20{
21 if (clk->flags & CLK_ENABLE_REG_8BIT)
22 return ioread8(clk->mapped_reg);
23 else if (clk->flags & CLK_ENABLE_REG_16BIT)
24 return ioread16(clk->mapped_reg);
25
26 return ioread32(clk->mapped_reg);
27}
28
29static void sh_clk_write(int value, struct clk *clk)
30{ 17{
31 if (clk->flags & CLK_ENABLE_REG_8BIT) 18 __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << clk->enable_bit),
32 iowrite8(value, clk->mapped_reg); 19 clk->enable_reg);
33 else if (clk->flags & CLK_ENABLE_REG_16BIT)
34 iowrite16(value, clk->mapped_reg);
35 else
36 iowrite32(value, clk->mapped_reg);
37}
38
39static int sh_clk_mstp_enable(struct clk *clk)
40{
41 sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk);
42 return 0; 20 return 0;
43} 21}
44 22
45static void sh_clk_mstp_disable(struct clk *clk) 23static void sh_clk_mstp32_disable(struct clk *clk)
46{ 24{
47 sh_clk_write(sh_clk_read(clk) | (1 << clk->enable_bit), clk); 25 __raw_writel(__raw_readl(clk->enable_reg) | (1 << clk->enable_bit),
26 clk->enable_reg);
48} 27}
49 28
50static struct sh_clk_ops sh_clk_mstp_clk_ops = { 29static struct clk_ops sh_clk_mstp32_clk_ops = {
51 .enable = sh_clk_mstp_enable, 30 .enable = sh_clk_mstp32_enable,
52 .disable = sh_clk_mstp_disable, 31 .disable = sh_clk_mstp32_disable,
53 .recalc = followparent_recalc, 32 .recalc = followparent_recalc,
54}; 33};
55 34
56int __init sh_clk_mstp_register(struct clk *clks, int nr) 35int __init sh_clk_mstp32_register(struct clk *clks, int nr)
57{ 36{
58 struct clk *clkp; 37 struct clk *clkp;
59 int ret = 0; 38 int ret = 0;
@@ -61,145 +40,139 @@ int __init sh_clk_mstp_register(struct clk *clks, int nr)
61 40
62 for (k = 0; !ret && (k < nr); k++) { 41 for (k = 0; !ret && (k < nr); k++) {
63 clkp = clks + k; 42 clkp = clks + k;
64 clkp->ops = &sh_clk_mstp_clk_ops; 43 clkp->ops = &sh_clk_mstp32_clk_ops;
65 ret |= clk_register(clkp); 44 ret |= clk_register(clkp);
66 } 45 }
67 46
68 return ret; 47 return ret;
69} 48}
70 49
71/*
72 * Div/mult table lookup helpers
73 */
74static inline struct clk_div_table *clk_to_div_table(struct clk *clk)
75{
76 return clk->priv;
77}
78
79static inline struct clk_div_mult_table *clk_to_div_mult_table(struct clk *clk)
80{
81 return clk_to_div_table(clk)->div_mult_table;
82}
83
84/*
85 * Common div ops
86 */
87static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate) 50static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
88{ 51{
89 return clk_rate_table_round(clk, clk->freq_table, rate); 52 return clk_rate_table_round(clk, clk->freq_table, rate);
90} 53}
91 54
92static unsigned long sh_clk_div_recalc(struct clk *clk) 55static int sh_clk_div6_divisors[64] = {
56 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
57 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
58 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
59 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
60};
61
62static struct clk_div_mult_table sh_clk_div6_table = {
63 .divisors = sh_clk_div6_divisors,
64 .nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
65};
66
67static unsigned long sh_clk_div6_recalc(struct clk *clk)
93{ 68{
94 struct clk_div_mult_table *table = clk_to_div_mult_table(clk); 69 struct clk_div_mult_table *table = &sh_clk_div6_table;
95 unsigned int idx; 70 unsigned int idx;
96 71
97 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, 72 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
98 table, clk->arch_flags ? &clk->arch_flags : NULL); 73 table, NULL);
99 74
100 idx = (sh_clk_read(clk) >> clk->enable_bit) & clk->div_mask; 75 idx = __raw_readl(clk->enable_reg) & 0x003f;
101 76
102 return clk->freq_table[idx].frequency; 77 return clk->freq_table[idx].frequency;
103} 78}
104 79
105static int sh_clk_div_set_rate(struct clk *clk, unsigned long rate) 80static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
106{ 81{
107 struct clk_div_table *dt = clk_to_div_table(clk); 82 struct clk_div_mult_table *table = &sh_clk_div6_table;
108 unsigned long value; 83 u32 value;
109 int idx; 84 int ret, i;
110 85
111 idx = clk_rate_table_find(clk, clk->freq_table, rate); 86 if (!clk->parent_table || !clk->parent_num)
112 if (idx < 0) 87 return -EINVAL;
113 return idx;
114 88
115 value = sh_clk_read(clk); 89 /* Search the parent */
116 value &= ~(clk->div_mask << clk->enable_bit); 90 for (i = 0; i < clk->parent_num; i++)
117 value |= (idx << clk->enable_bit); 91 if (clk->parent_table[i] == parent)
118 sh_clk_write(value, clk); 92 break;
93
94 if (i == clk->parent_num)
95 return -ENODEV;
96
97 ret = clk_reparent(clk, parent);
98 if (ret < 0)
99 return ret;
100
101 value = __raw_readl(clk->enable_reg) &
102 ~(((1 << clk->src_width) - 1) << clk->src_shift);
103
104 __raw_writel(value | (i << clk->src_shift), clk->enable_reg);
119 105
120 /* XXX: Should use a post-change notifier */ 106 /* Rebuild the frequency table */
121 if (dt->kick) 107 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
122 dt->kick(clk); 108 table, NULL);
123 109
124 return 0; 110 return 0;
125} 111}
126 112
127static int sh_clk_div_enable(struct clk *clk) 113static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate)
128{ 114{
129 sh_clk_write(sh_clk_read(clk) & ~CPG_CKSTP_BIT, clk); 115 unsigned long value;
116 int idx;
117
118 idx = clk_rate_table_find(clk, clk->freq_table, rate);
119 if (idx < 0)
120 return idx;
121
122 value = __raw_readl(clk->enable_reg);
123 value &= ~0x3f;
124 value |= idx;
125 __raw_writel(value, clk->enable_reg);
130 return 0; 126 return 0;
131} 127}
132 128
133static void sh_clk_div_disable(struct clk *clk) 129static int sh_clk_div6_enable(struct clk *clk)
134{ 130{
135 unsigned int val; 131 unsigned long value;
132 int ret;
136 133
137 val = sh_clk_read(clk); 134 ret = sh_clk_div6_set_rate(clk, clk->rate);
138 val |= CPG_CKSTP_BIT; 135 if (ret == 0) {
136 value = __raw_readl(clk->enable_reg);
137 value &= ~0x100; /* clear stop bit to enable clock */
138 __raw_writel(value, clk->enable_reg);
139 }
140 return ret;
141}
139 142
140 /* 143static void sh_clk_div6_disable(struct clk *clk)
141 * div6 clocks require the divisor field to be non-zero or the 144{
142 * above CKSTP toggle silently fails. Ensure that the divisor 145 unsigned long value;
143 * array is reset to its initial state on disable.
144 */
145 if (clk->flags & CLK_MASK_DIV_ON_DISABLE)
146 val |= clk->div_mask;
147 146
148 sh_clk_write(val, clk); 147 value = __raw_readl(clk->enable_reg);
148 value |= 0x100; /* stop clock */
149 value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
150 __raw_writel(value, clk->enable_reg);
149} 151}
150 152
151static struct sh_clk_ops sh_clk_div_clk_ops = { 153static struct clk_ops sh_clk_div6_clk_ops = {
152 .recalc = sh_clk_div_recalc, 154 .recalc = sh_clk_div6_recalc,
153 .set_rate = sh_clk_div_set_rate,
154 .round_rate = sh_clk_div_round_rate, 155 .round_rate = sh_clk_div_round_rate,
156 .set_rate = sh_clk_div6_set_rate,
157 .enable = sh_clk_div6_enable,
158 .disable = sh_clk_div6_disable,
155}; 159};
156 160
157static struct sh_clk_ops sh_clk_div_enable_clk_ops = { 161static struct clk_ops sh_clk_div6_reparent_clk_ops = {
158 .recalc = sh_clk_div_recalc, 162 .recalc = sh_clk_div6_recalc,
159 .set_rate = sh_clk_div_set_rate,
160 .round_rate = sh_clk_div_round_rate, 163 .round_rate = sh_clk_div_round_rate,
161 .enable = sh_clk_div_enable, 164 .set_rate = sh_clk_div6_set_rate,
162 .disable = sh_clk_div_disable, 165 .enable = sh_clk_div6_enable,
166 .disable = sh_clk_div6_disable,
167 .set_parent = sh_clk_div6_set_parent,
163}; 168};
164 169
165static int __init sh_clk_init_parent(struct clk *clk) 170static int __init sh_clk_div6_register_ops(struct clk *clks, int nr,
166{ 171 struct clk_ops *ops)
167 u32 val;
168
169 if (clk->parent)
170 return 0;
171
172 if (!clk->parent_table || !clk->parent_num)
173 return 0;
174
175 if (!clk->src_width) {
176 pr_err("sh_clk_init_parent: cannot select parent clock\n");
177 return -EINVAL;
178 }
179
180 val = (sh_clk_read(clk) >> clk->src_shift);
181 val &= (1 << clk->src_width) - 1;
182
183 if (val >= clk->parent_num) {
184 pr_err("sh_clk_init_parent: parent table size failed\n");
185 return -EINVAL;
186 }
187
188 clk_reparent(clk, clk->parent_table[val]);
189 if (!clk->parent) {
190 pr_err("sh_clk_init_parent: unable to set parent");
191 return -EINVAL;
192 }
193
194 return 0;
195}
196
197static int __init sh_clk_div_register_ops(struct clk *clks, int nr,
198 struct clk_div_table *table, struct sh_clk_ops *ops)
199{ 172{
200 struct clk *clkp; 173 struct clk *clkp;
201 void *freq_table; 174 void *freq_table;
202 int nr_divs = table->div_mult_table->nr_divisors; 175 int nr_divs = sh_clk_div6_table.nr_divisors;
203 int freq_table_size = sizeof(struct cpufreq_frequency_table); 176 int freq_table_size = sizeof(struct cpufreq_frequency_table);
204 int ret = 0; 177 int ret = 0;
205 int k; 178 int k;
@@ -207,7 +180,7 @@ static int __init sh_clk_div_register_ops(struct clk *clks, int nr,
207 freq_table_size *= (nr_divs + 1); 180 freq_table_size *= (nr_divs + 1);
208 freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL); 181 freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
209 if (!freq_table) { 182 if (!freq_table) {
210 pr_err("%s: unable to alloc memory\n", __func__); 183 pr_err("sh_clk_div6_register: unable to alloc memory\n");
211 return -ENOMEM; 184 return -ENOMEM;
212 } 185 }
213 186
@@ -215,98 +188,44 @@ static int __init sh_clk_div_register_ops(struct clk *clks, int nr,
215 clkp = clks + k; 188 clkp = clks + k;
216 189
217 clkp->ops = ops; 190 clkp->ops = ops;
218 clkp->priv = table;
219
220 clkp->freq_table = freq_table + (k * freq_table_size); 191 clkp->freq_table = freq_table + (k * freq_table_size);
221 clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END; 192 clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
222 193
223 ret = clk_register(clkp); 194 ret = clk_register(clkp);
224 if (ret == 0)
225 ret = sh_clk_init_parent(clkp);
226 } 195 }
227 196
228 return ret; 197 return ret;
229} 198}
230 199
231/* 200int __init sh_clk_div6_register(struct clk *clks, int nr)
232 * div6 support
233 */
234static int sh_clk_div6_divisors[64] = {
235 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
236 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
237 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
238 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
239};
240
241static struct clk_div_mult_table div6_div_mult_table = {
242 .divisors = sh_clk_div6_divisors,
243 .nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
244};
245
246static struct clk_div_table sh_clk_div6_table = {
247 .div_mult_table = &div6_div_mult_table,
248};
249
250static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
251{ 201{
252 struct clk_div_mult_table *table = clk_to_div_mult_table(clk); 202 return sh_clk_div6_register_ops(clks, nr, &sh_clk_div6_clk_ops);
253 u32 value;
254 int ret, i;
255
256 if (!clk->parent_table || !clk->parent_num)
257 return -EINVAL;
258
259 /* Search the parent */
260 for (i = 0; i < clk->parent_num; i++)
261 if (clk->parent_table[i] == parent)
262 break;
263
264 if (i == clk->parent_num)
265 return -ENODEV;
266
267 ret = clk_reparent(clk, parent);
268 if (ret < 0)
269 return ret;
270
271 value = sh_clk_read(clk) &
272 ~(((1 << clk->src_width) - 1) << clk->src_shift);
273
274 sh_clk_write(value | (i << clk->src_shift), clk);
275
276 /* Rebuild the frequency table */
277 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
278 table, NULL);
279
280 return 0;
281} 203}
282 204
283static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = { 205int __init sh_clk_div6_reparent_register(struct clk *clks, int nr)
284 .recalc = sh_clk_div_recalc,
285 .round_rate = sh_clk_div_round_rate,
286 .set_rate = sh_clk_div_set_rate,
287 .enable = sh_clk_div_enable,
288 .disable = sh_clk_div_disable,
289 .set_parent = sh_clk_div6_set_parent,
290};
291
292int __init sh_clk_div6_register(struct clk *clks, int nr)
293{ 206{
294 return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table, 207 return sh_clk_div6_register_ops(clks, nr,
295 &sh_clk_div_enable_clk_ops); 208 &sh_clk_div6_reparent_clk_ops);
296} 209}
297 210
298int __init sh_clk_div6_reparent_register(struct clk *clks, int nr) 211static unsigned long sh_clk_div4_recalc(struct clk *clk)
299{ 212{
300 return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table, 213 struct clk_div4_table *d4t = clk->priv;
301 &sh_clk_div6_reparent_clk_ops); 214 struct clk_div_mult_table *table = d4t->div_mult_table;
215 unsigned int idx;
216
217 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
218 table, &clk->arch_flags);
219
220 idx = (__raw_readl(clk->enable_reg) >> clk->enable_bit) & 0x000f;
221
222 return clk->freq_table[idx].frequency;
302} 223}
303 224
304/*
305 * div4 support
306 */
307static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent) 225static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
308{ 226{
309 struct clk_div_mult_table *table = clk_to_div_mult_table(clk); 227 struct clk_div4_table *d4t = clk->priv;
228 struct clk_div_mult_table *table = d4t->div_mult_table;
310 u32 value; 229 u32 value;
311 int ret; 230 int ret;
312 231
@@ -316,15 +235,15 @@ static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
316 */ 235 */
317 236
318 if (parent->flags & CLK_ENABLE_ON_INIT) 237 if (parent->flags & CLK_ENABLE_ON_INIT)
319 value = sh_clk_read(clk) & ~(1 << 7); 238 value = __raw_readl(clk->enable_reg) & ~(1 << 7);
320 else 239 else
321 value = sh_clk_read(clk) | (1 << 7); 240 value = __raw_readl(clk->enable_reg) | (1 << 7);
322 241
323 ret = clk_reparent(clk, parent); 242 ret = clk_reparent(clk, parent);
324 if (ret < 0) 243 if (ret < 0)
325 return ret; 244 return ret;
326 245
327 sh_clk_write(value, clk); 246 __raw_writel(value, clk->enable_reg);
328 247
329 /* Rebiuld the frequency table */ 248 /* Rebiuld the frequency table */
330 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, 249 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -333,116 +252,107 @@ static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
333 return 0; 252 return 0;
334} 253}
335 254
336static struct sh_clk_ops sh_clk_div4_reparent_clk_ops = { 255static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
337 .recalc = sh_clk_div_recalc,
338 .set_rate = sh_clk_div_set_rate,
339 .round_rate = sh_clk_div_round_rate,
340 .enable = sh_clk_div_enable,
341 .disable = sh_clk_div_disable,
342 .set_parent = sh_clk_div4_set_parent,
343};
344
345int __init sh_clk_div4_register(struct clk *clks, int nr,
346 struct clk_div4_table *table)
347{ 256{
348 return sh_clk_div_register_ops(clks, nr, table, &sh_clk_div_clk_ops); 257 struct clk_div4_table *d4t = clk->priv;
349} 258 unsigned long value;
350 259 int idx = clk_rate_table_find(clk, clk->freq_table, rate);
351int __init sh_clk_div4_enable_register(struct clk *clks, int nr, 260 if (idx < 0)
352 struct clk_div4_table *table) 261 return idx;
353{
354 return sh_clk_div_register_ops(clks, nr, table,
355 &sh_clk_div_enable_clk_ops);
356}
357
358int __init sh_clk_div4_reparent_register(struct clk *clks, int nr,
359 struct clk_div4_table *table)
360{
361 return sh_clk_div_register_ops(clks, nr, table,
362 &sh_clk_div4_reparent_clk_ops);
363}
364
365/* FSI-DIV */
366static unsigned long fsidiv_recalc(struct clk *clk)
367{
368 u32 value;
369 262
370 value = __raw_readl(clk->mapping->base); 263 value = __raw_readl(clk->enable_reg);
264 value &= ~(0xf << clk->enable_bit);
265 value |= (idx << clk->enable_bit);
266 __raw_writel(value, clk->enable_reg);
371 267
372 value >>= 16; 268 if (d4t->kick)
373 if (value < 2) 269 d4t->kick(clk);
374 return clk->parent->rate;
375 270
376 return clk->parent->rate / value; 271 return 0;
377} 272}
378 273
379static long fsidiv_round_rate(struct clk *clk, unsigned long rate) 274static int sh_clk_div4_enable(struct clk *clk)
380{ 275{
381 return clk_rate_div_range_round(clk, 1, 0xffff, rate); 276 __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << 8), clk->enable_reg);
277 return 0;
382} 278}
383 279
384static void fsidiv_disable(struct clk *clk) 280static void sh_clk_div4_disable(struct clk *clk)
385{ 281{
386 __raw_writel(0, clk->mapping->base); 282 __raw_writel(__raw_readl(clk->enable_reg) | (1 << 8), clk->enable_reg);
387} 283}
388 284
389static int fsidiv_enable(struct clk *clk) 285static struct clk_ops sh_clk_div4_clk_ops = {
390{ 286 .recalc = sh_clk_div4_recalc,
391 u32 value; 287 .set_rate = sh_clk_div4_set_rate,
392 288 .round_rate = sh_clk_div_round_rate,
393 value = __raw_readl(clk->mapping->base) >> 16; 289};
394 if (value < 2)
395 return 0;
396 290
397 __raw_writel((value << 16) | 0x3, clk->mapping->base); 291static struct clk_ops sh_clk_div4_enable_clk_ops = {
292 .recalc = sh_clk_div4_recalc,
293 .set_rate = sh_clk_div4_set_rate,
294 .round_rate = sh_clk_div_round_rate,
295 .enable = sh_clk_div4_enable,
296 .disable = sh_clk_div4_disable,
297};
398 298
399 return 0; 299static struct clk_ops sh_clk_div4_reparent_clk_ops = {
400} 300 .recalc = sh_clk_div4_recalc,
301 .set_rate = sh_clk_div4_set_rate,
302 .round_rate = sh_clk_div_round_rate,
303 .enable = sh_clk_div4_enable,
304 .disable = sh_clk_div4_disable,
305 .set_parent = sh_clk_div4_set_parent,
306};
401 307
402static int fsidiv_set_rate(struct clk *clk, unsigned long rate) 308static int __init sh_clk_div4_register_ops(struct clk *clks, int nr,
309 struct clk_div4_table *table, struct clk_ops *ops)
403{ 310{
404 int idx; 311 struct clk *clkp;
405 312 void *freq_table;
406 idx = (clk->parent->rate / rate) & 0xffff; 313 int nr_divs = table->div_mult_table->nr_divisors;
407 if (idx < 2) 314 int freq_table_size = sizeof(struct cpufreq_frequency_table);
408 __raw_writel(0, clk->mapping->base); 315 int ret = 0;
409 else 316 int k;
410 __raw_writel(idx << 16, clk->mapping->base);
411 317
412 return 0; 318 freq_table_size *= (nr_divs + 1);
413} 319 freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
320 if (!freq_table) {
321 pr_err("sh_clk_div4_register: unable to alloc memory\n");
322 return -ENOMEM;
323 }
414 324
415static struct sh_clk_ops fsidiv_clk_ops = { 325 for (k = 0; !ret && (k < nr); k++) {
416 .recalc = fsidiv_recalc, 326 clkp = clks + k;
417 .round_rate = fsidiv_round_rate,
418 .set_rate = fsidiv_set_rate,
419 .enable = fsidiv_enable,
420 .disable = fsidiv_disable,
421};
422 327
423int __init sh_clk_fsidiv_register(struct clk *clks, int nr) 328 clkp->ops = ops;
424{ 329 clkp->priv = table;
425 struct clk_mapping *map;
426 int i;
427 330
428 for (i = 0; i < nr; i++) { 331 clkp->freq_table = freq_table + (k * freq_table_size);
332 clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
429 333
430 map = kzalloc(sizeof(struct clk_mapping), GFP_KERNEL); 334 ret = clk_register(clkp);
431 if (!map) { 335 }
432 pr_err("%s: unable to alloc memory\n", __func__);
433 return -ENOMEM;
434 }
435 336
436 /* clks[i].enable_reg came from SH_CLK_FSIDIV() */ 337 return ret;
437 map->phys = (phys_addr_t)clks[i].enable_reg; 338}
438 map->len = 8;
439 339
440 clks[i].enable_reg = 0; /* remove .enable_reg */ 340int __init sh_clk_div4_register(struct clk *clks, int nr,
441 clks[i].ops = &fsidiv_clk_ops; 341 struct clk_div4_table *table)
442 clks[i].mapping = map; 342{
343 return sh_clk_div4_register_ops(clks, nr, table, &sh_clk_div4_clk_ops);
344}
443 345
444 clk_register(&clks[i]); 346int __init sh_clk_div4_enable_register(struct clk *clks, int nr,
445 } 347 struct clk_div4_table *table)
348{
349 return sh_clk_div4_register_ops(clks, nr, table,
350 &sh_clk_div4_enable_clk_ops);
351}
446 352
447 return 0; 353int __init sh_clk_div4_reparent_register(struct clk *clks, int nr,
354 struct clk_div4_table *table)
355{
356 return sh_clk_div4_register_ops(clks, nr, table,
357 &sh_clk_div4_reparent_clk_ops);
448} 358}