1de9186c2SPaul Mundt /*
2de9186c2SPaul Mundt * Helper routines for SuperH Clock Pulse Generator blocks (CPG).
3de9186c2SPaul Mundt *
4de9186c2SPaul Mundt * Copyright (C) 2010 Magnus Damm
54d6ddb08SPaul Mundt * Copyright (C) 2010 - 2012 Paul Mundt
6de9186c2SPaul Mundt *
7de9186c2SPaul Mundt * This file is subject to the terms and conditions of the GNU General Public
8de9186c2SPaul Mundt * License. See the file "COPYING" in the main directory of this archive
9de9186c2SPaul Mundt * for more details.
10de9186c2SPaul Mundt */
11de9186c2SPaul Mundt #include <linux/clk.h>
12de9186c2SPaul Mundt #include <linux/compiler.h>
13de9186c2SPaul Mundt #include <linux/slab.h>
14de9186c2SPaul Mundt #include <linux/io.h>
15de9186c2SPaul Mundt #include <linux/sh_clk.h>
16de9186c2SPaul Mundt
17764f4e4eSPaul Mundt #define CPG_CKSTP_BIT BIT(8)
18764f4e4eSPaul Mundt
sh_clk_read(struct clk * clk)19104fa61aSPaul Mundt static unsigned int sh_clk_read(struct clk *clk)
20de9186c2SPaul Mundt {
214d6ddb08SPaul Mundt if (clk->flags & CLK_ENABLE_REG_8BIT)
22104fa61aSPaul Mundt return ioread8(clk->mapped_reg);
234d6ddb08SPaul Mundt else if (clk->flags & CLK_ENABLE_REG_16BIT)
24104fa61aSPaul Mundt return ioread16(clk->mapped_reg);
254d6ddb08SPaul Mundt
26104fa61aSPaul Mundt return ioread32(clk->mapped_reg);
27104fa61aSPaul Mundt }
28104fa61aSPaul Mundt
sh_clk_write(int value,struct clk * clk)29104fa61aSPaul Mundt static void sh_clk_write(int value, struct clk *clk)
30104fa61aSPaul Mundt {
31104fa61aSPaul Mundt if (clk->flags & CLK_ENABLE_REG_8BIT)
32104fa61aSPaul Mundt iowrite8(value, clk->mapped_reg);
33104fa61aSPaul Mundt else if (clk->flags & CLK_ENABLE_REG_16BIT)
34104fa61aSPaul Mundt iowrite16(value, clk->mapped_reg);
35104fa61aSPaul Mundt else
36104fa61aSPaul Mundt iowrite32(value, clk->mapped_reg);
37104fa61aSPaul Mundt }
38104fa61aSPaul Mundt
sh_clk_mstp_enable(struct clk * clk)39104fa61aSPaul Mundt static int sh_clk_mstp_enable(struct clk *clk)
40104fa61aSPaul Mundt {
41104fa61aSPaul Mundt sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk);
42a028c6daSGuennadi Liakhovetski if (clk->status_reg) {
438f28ca6bSKrzysztof Kozlowski unsigned int (*read)(const void __iomem *addr);
44a028c6daSGuennadi Liakhovetski int i;
45a028c6daSGuennadi Liakhovetski void __iomem *mapped_status = (phys_addr_t)clk->status_reg -
46a028c6daSGuennadi Liakhovetski (phys_addr_t)clk->enable_reg + clk->mapped_reg;
47a028c6daSGuennadi Liakhovetski
48a028c6daSGuennadi Liakhovetski if (clk->flags & CLK_ENABLE_REG_8BIT)
49a8e3943bSKuninori Morimoto read = ioread8;
50a028c6daSGuennadi Liakhovetski else if (clk->flags & CLK_ENABLE_REG_16BIT)
51a8e3943bSKuninori Morimoto read = ioread16;
52a028c6daSGuennadi Liakhovetski else
53a8e3943bSKuninori Morimoto read = ioread32;
54a028c6daSGuennadi Liakhovetski
55a028c6daSGuennadi Liakhovetski for (i = 1000;
56a028c6daSGuennadi Liakhovetski (read(mapped_status) & (1 << clk->enable_bit)) && i;
57a028c6daSGuennadi Liakhovetski i--)
58a028c6daSGuennadi Liakhovetski cpu_relax();
59a028c6daSGuennadi Liakhovetski if (!i) {
60a028c6daSGuennadi Liakhovetski pr_err("cpg: failed to enable %p[%d]\n",
61a028c6daSGuennadi Liakhovetski clk->enable_reg, clk->enable_bit);
62a028c6daSGuennadi Liakhovetski return -ETIMEDOUT;
63a028c6daSGuennadi Liakhovetski }
64a028c6daSGuennadi Liakhovetski }
65de9186c2SPaul Mundt return 0;
66de9186c2SPaul Mundt }
67de9186c2SPaul Mundt
sh_clk_mstp_disable(struct clk * clk)684d6ddb08SPaul Mundt static void sh_clk_mstp_disable(struct clk *clk)
69de9186c2SPaul Mundt {
70104fa61aSPaul Mundt sh_clk_write(sh_clk_read(clk) | (1 << clk->enable_bit), clk);
71de9186c2SPaul Mundt }
72de9186c2SPaul Mundt
734d6ddb08SPaul Mundt static struct sh_clk_ops sh_clk_mstp_clk_ops = {
744d6ddb08SPaul Mundt .enable = sh_clk_mstp_enable,
754d6ddb08SPaul Mundt .disable = sh_clk_mstp_disable,
76de9186c2SPaul Mundt .recalc = followparent_recalc,
77de9186c2SPaul Mundt };
78de9186c2SPaul Mundt
sh_clk_mstp_register(struct clk * clks,int nr)794d6ddb08SPaul Mundt int __init sh_clk_mstp_register(struct clk *clks, int nr)
80de9186c2SPaul Mundt {
81de9186c2SPaul Mundt struct clk *clkp;
82de9186c2SPaul Mundt int ret = 0;
83de9186c2SPaul Mundt int k;
84de9186c2SPaul Mundt
85de9186c2SPaul Mundt for (k = 0; !ret && (k < nr); k++) {
86de9186c2SPaul Mundt clkp = clks + k;
874d6ddb08SPaul Mundt clkp->ops = &sh_clk_mstp_clk_ops;
88de9186c2SPaul Mundt ret |= clk_register(clkp);
89de9186c2SPaul Mundt }
90de9186c2SPaul Mundt
91de9186c2SPaul Mundt return ret;
92de9186c2SPaul Mundt }
93de9186c2SPaul Mundt
94a60977a5SPaul Mundt /*
95a60977a5SPaul Mundt * Div/mult table lookup helpers
96a60977a5SPaul Mundt */
clk_to_div_table(struct clk * clk)97a60977a5SPaul Mundt static inline struct clk_div_table *clk_to_div_table(struct clk *clk)
98a60977a5SPaul Mundt {
99a60977a5SPaul Mundt return clk->priv;
100a60977a5SPaul Mundt }
101a60977a5SPaul Mundt
clk_to_div_mult_table(struct clk * clk)102a60977a5SPaul Mundt static inline struct clk_div_mult_table *clk_to_div_mult_table(struct clk *clk)
103a60977a5SPaul Mundt {
104a60977a5SPaul Mundt return clk_to_div_table(clk)->div_mult_table;
105a60977a5SPaul Mundt }
106a60977a5SPaul Mundt
107a60977a5SPaul Mundt /*
10875f5f8a5SPaul Mundt * Common div ops
10975f5f8a5SPaul Mundt */
sh_clk_div_round_rate(struct clk * clk,unsigned long rate)11075f5f8a5SPaul Mundt static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
11175f5f8a5SPaul Mundt {
11275f5f8a5SPaul Mundt return clk_rate_table_round(clk, clk->freq_table, rate);
11375f5f8a5SPaul Mundt }
11475f5f8a5SPaul Mundt
sh_clk_div_recalc(struct clk * clk)11575f5f8a5SPaul Mundt static unsigned long sh_clk_div_recalc(struct clk *clk)
11675f5f8a5SPaul Mundt {
11775f5f8a5SPaul Mundt struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
11875f5f8a5SPaul Mundt unsigned int idx;
11975f5f8a5SPaul Mundt
12075f5f8a5SPaul Mundt clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
12175f5f8a5SPaul Mundt table, clk->arch_flags ? &clk->arch_flags : NULL);
12275f5f8a5SPaul Mundt
12375f5f8a5SPaul Mundt idx = (sh_clk_read(clk) >> clk->enable_bit) & clk->div_mask;
12475f5f8a5SPaul Mundt
12575f5f8a5SPaul Mundt return clk->freq_table[idx].frequency;
12675f5f8a5SPaul Mundt }
12775f5f8a5SPaul Mundt
sh_clk_div_set_rate(struct clk * clk,unsigned long rate)1280fa22168SPaul Mundt static int sh_clk_div_set_rate(struct clk *clk, unsigned long rate)
1290fa22168SPaul Mundt {
1300fa22168SPaul Mundt struct clk_div_table *dt = clk_to_div_table(clk);
1310fa22168SPaul Mundt unsigned long value;
1320fa22168SPaul Mundt int idx;
1330fa22168SPaul Mundt
1340fa22168SPaul Mundt idx = clk_rate_table_find(clk, clk->freq_table, rate);
1350fa22168SPaul Mundt if (idx < 0)
1360fa22168SPaul Mundt return idx;
1370fa22168SPaul Mundt
1380fa22168SPaul Mundt value = sh_clk_read(clk);
1390fa22168SPaul Mundt value &= ~(clk->div_mask << clk->enable_bit);
1400fa22168SPaul Mundt value |= (idx << clk->enable_bit);
1410fa22168SPaul Mundt sh_clk_write(value, clk);
1420fa22168SPaul Mundt
1430fa22168SPaul Mundt /* XXX: Should use a post-change notifier */
1440fa22168SPaul Mundt if (dt->kick)
1450fa22168SPaul Mundt dt->kick(clk);
1460fa22168SPaul Mundt
1470fa22168SPaul Mundt return 0;
1480fa22168SPaul Mundt }
1490fa22168SPaul Mundt
sh_clk_div_enable(struct clk * clk)150764f4e4eSPaul Mundt static int sh_clk_div_enable(struct clk *clk)
151764f4e4eSPaul Mundt {
1525a799b82SKuninori Morimoto if (clk->div_mask == SH_CLK_DIV6_MSK) {
1535a799b82SKuninori Morimoto int ret = sh_clk_div_set_rate(clk, clk->rate);
1545a799b82SKuninori Morimoto if (ret < 0)
1555a799b82SKuninori Morimoto return ret;
1565a799b82SKuninori Morimoto }
1575a799b82SKuninori Morimoto
158764f4e4eSPaul Mundt sh_clk_write(sh_clk_read(clk) & ~CPG_CKSTP_BIT, clk);
159764f4e4eSPaul Mundt return 0;
160764f4e4eSPaul Mundt }
161764f4e4eSPaul Mundt
sh_clk_div_disable(struct clk * clk)162764f4e4eSPaul Mundt static void sh_clk_div_disable(struct clk *clk)
163764f4e4eSPaul Mundt {
164764f4e4eSPaul Mundt unsigned int val;
165764f4e4eSPaul Mundt
166764f4e4eSPaul Mundt val = sh_clk_read(clk);
167764f4e4eSPaul Mundt val |= CPG_CKSTP_BIT;
168764f4e4eSPaul Mundt
169764f4e4eSPaul Mundt /*
170764f4e4eSPaul Mundt * div6 clocks require the divisor field to be non-zero or the
171764f4e4eSPaul Mundt * above CKSTP toggle silently fails. Ensure that the divisor
172764f4e4eSPaul Mundt * array is reset to its initial state on disable.
173764f4e4eSPaul Mundt */
174764f4e4eSPaul Mundt if (clk->flags & CLK_MASK_DIV_ON_DISABLE)
175764f4e4eSPaul Mundt val |= clk->div_mask;
176764f4e4eSPaul Mundt
177764f4e4eSPaul Mundt sh_clk_write(val, clk);
178764f4e4eSPaul Mundt }
179764f4e4eSPaul Mundt
180e3c87607SPaul Mundt static struct sh_clk_ops sh_clk_div_clk_ops = {
181e3c87607SPaul Mundt .recalc = sh_clk_div_recalc,
182e3c87607SPaul Mundt .set_rate = sh_clk_div_set_rate,
183e3c87607SPaul Mundt .round_rate = sh_clk_div_round_rate,
184e3c87607SPaul Mundt };
185e3c87607SPaul Mundt
186e3c87607SPaul Mundt static struct sh_clk_ops sh_clk_div_enable_clk_ops = {
187e3c87607SPaul Mundt .recalc = sh_clk_div_recalc,
188e3c87607SPaul Mundt .set_rate = sh_clk_div_set_rate,
189e3c87607SPaul Mundt .round_rate = sh_clk_div_round_rate,
190e3c87607SPaul Mundt .enable = sh_clk_div_enable,
191e3c87607SPaul Mundt .disable = sh_clk_div_disable,
192e3c87607SPaul Mundt };
193e3c87607SPaul Mundt
sh_clk_init_parent(struct clk * clk)194609d7558SPaul Mundt static int __init sh_clk_init_parent(struct clk *clk)
195609d7558SPaul Mundt {
196609d7558SPaul Mundt u32 val;
197609d7558SPaul Mundt
198609d7558SPaul Mundt if (clk->parent)
199609d7558SPaul Mundt return 0;
200609d7558SPaul Mundt
201609d7558SPaul Mundt if (!clk->parent_table || !clk->parent_num)
202609d7558SPaul Mundt return 0;
203609d7558SPaul Mundt
204609d7558SPaul Mundt if (!clk->src_width) {
205609d7558SPaul Mundt pr_err("sh_clk_init_parent: cannot select parent clock\n");
206609d7558SPaul Mundt return -EINVAL;
207609d7558SPaul Mundt }
208609d7558SPaul Mundt
209609d7558SPaul Mundt val = (sh_clk_read(clk) >> clk->src_shift);
210609d7558SPaul Mundt val &= (1 << clk->src_width) - 1;
211609d7558SPaul Mundt
212609d7558SPaul Mundt if (val >= clk->parent_num) {
213609d7558SPaul Mundt pr_err("sh_clk_init_parent: parent table size failed\n");
214609d7558SPaul Mundt return -EINVAL;
215609d7558SPaul Mundt }
216609d7558SPaul Mundt
217609d7558SPaul Mundt clk_reparent(clk, clk->parent_table[val]);
218609d7558SPaul Mundt if (!clk->parent) {
219609d7558SPaul Mundt pr_err("sh_clk_init_parent: unable to set parent");
220609d7558SPaul Mundt return -EINVAL;
221609d7558SPaul Mundt }
222609d7558SPaul Mundt
223609d7558SPaul Mundt return 0;
224609d7558SPaul Mundt }
225609d7558SPaul Mundt
sh_clk_div_register_ops(struct clk * clks,int nr,struct clk_div_table * table,struct sh_clk_ops * ops)226609d7558SPaul Mundt static int __init sh_clk_div_register_ops(struct clk *clks, int nr,
227609d7558SPaul Mundt struct clk_div_table *table, struct sh_clk_ops *ops)
228609d7558SPaul Mundt {
229609d7558SPaul Mundt struct clk *clkp;
230609d7558SPaul Mundt void *freq_table;
231609d7558SPaul Mundt int nr_divs = table->div_mult_table->nr_divisors;
232609d7558SPaul Mundt int freq_table_size = sizeof(struct cpufreq_frequency_table);
233609d7558SPaul Mundt int ret = 0;
234609d7558SPaul Mundt int k;
235609d7558SPaul Mundt
236609d7558SPaul Mundt freq_table_size *= (nr_divs + 1);
2376396bb22SKees Cook freq_table = kcalloc(nr, freq_table_size, GFP_KERNEL);
238609d7558SPaul Mundt if (!freq_table) {
239609d7558SPaul Mundt pr_err("%s: unable to alloc memory\n", __func__);
240609d7558SPaul Mundt return -ENOMEM;
241609d7558SPaul Mundt }
242609d7558SPaul Mundt
243609d7558SPaul Mundt for (k = 0; !ret && (k < nr); k++) {
244609d7558SPaul Mundt clkp = clks + k;
245609d7558SPaul Mundt
246609d7558SPaul Mundt clkp->ops = ops;
247609d7558SPaul Mundt clkp->priv = table;
248609d7558SPaul Mundt
249609d7558SPaul Mundt clkp->freq_table = freq_table + (k * freq_table_size);
250609d7558SPaul Mundt clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
251609d7558SPaul Mundt
252609d7558SPaul Mundt ret = clk_register(clkp);
253609d7558SPaul Mundt if (ret == 0)
254609d7558SPaul Mundt ret = sh_clk_init_parent(clkp);
255609d7558SPaul Mundt }
256609d7558SPaul Mundt
257609d7558SPaul Mundt return ret;
258609d7558SPaul Mundt }
259609d7558SPaul Mundt
26075f5f8a5SPaul Mundt /*
261a60977a5SPaul Mundt * div6 support
262a60977a5SPaul Mundt */
263de9186c2SPaul Mundt static int sh_clk_div6_divisors[64] = {
264de9186c2SPaul Mundt 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
265de9186c2SPaul Mundt 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
266de9186c2SPaul Mundt 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
267de9186c2SPaul Mundt 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
268de9186c2SPaul Mundt };
269de9186c2SPaul Mundt
270a60977a5SPaul Mundt static struct clk_div_mult_table div6_div_mult_table = {
271de9186c2SPaul Mundt .divisors = sh_clk_div6_divisors,
272de9186c2SPaul Mundt .nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
273de9186c2SPaul Mundt };
274de9186c2SPaul Mundt
275a60977a5SPaul Mundt static struct clk_div_table sh_clk_div6_table = {
276a60977a5SPaul Mundt .div_mult_table = &div6_div_mult_table,
277a60977a5SPaul Mundt };
278a60977a5SPaul Mundt
sh_clk_div6_set_parent(struct clk * clk,struct clk * parent)279de9186c2SPaul Mundt static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
280de9186c2SPaul Mundt {
281a60977a5SPaul Mundt struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
282de9186c2SPaul Mundt u32 value;
283de9186c2SPaul Mundt int ret, i;
284de9186c2SPaul Mundt
285de9186c2SPaul Mundt if (!clk->parent_table || !clk->parent_num)
286de9186c2SPaul Mundt return -EINVAL;
287de9186c2SPaul Mundt
288de9186c2SPaul Mundt /* Search the parent */
289de9186c2SPaul Mundt for (i = 0; i < clk->parent_num; i++)
290de9186c2SPaul Mundt if (clk->parent_table[i] == parent)
291de9186c2SPaul Mundt break;
292de9186c2SPaul Mundt
293de9186c2SPaul Mundt if (i == clk->parent_num)
294de9186c2SPaul Mundt return -ENODEV;
295de9186c2SPaul Mundt
296de9186c2SPaul Mundt ret = clk_reparent(clk, parent);
297de9186c2SPaul Mundt if (ret < 0)
298de9186c2SPaul Mundt return ret;
299de9186c2SPaul Mundt
300104fa61aSPaul Mundt value = sh_clk_read(clk) &
301de9186c2SPaul Mundt ~(((1 << clk->src_width) - 1) << clk->src_shift);
302de9186c2SPaul Mundt
303104fa61aSPaul Mundt sh_clk_write(value | (i << clk->src_shift), clk);
304de9186c2SPaul Mundt
305de9186c2SPaul Mundt /* Rebuild the frequency table */
306de9186c2SPaul Mundt clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
30752c10ad2SKuninori Morimoto table, NULL);
308de9186c2SPaul Mundt
309de9186c2SPaul Mundt return 0;
310de9186c2SPaul Mundt }
311de9186c2SPaul Mundt
312a0ec360fSMagnus Damm static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = {
31375f5f8a5SPaul Mundt .recalc = sh_clk_div_recalc,
314de9186c2SPaul Mundt .round_rate = sh_clk_div_round_rate,
3150fa22168SPaul Mundt .set_rate = sh_clk_div_set_rate,
316764f4e4eSPaul Mundt .enable = sh_clk_div_enable,
317764f4e4eSPaul Mundt .disable = sh_clk_div_disable,
318de9186c2SPaul Mundt .set_parent = sh_clk_div6_set_parent,
319de9186c2SPaul Mundt };
320de9186c2SPaul Mundt
sh_clk_div6_register(struct clk * clks,int nr)321de9186c2SPaul Mundt int __init sh_clk_div6_register(struct clk *clks, int nr)
322de9186c2SPaul Mundt {
323609d7558SPaul Mundt return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table,
324609d7558SPaul Mundt &sh_clk_div_enable_clk_ops);
325de9186c2SPaul Mundt }
326de9186c2SPaul Mundt
sh_clk_div6_reparent_register(struct clk * clks,int nr)327de9186c2SPaul Mundt int __init sh_clk_div6_reparent_register(struct clk *clks, int nr)
328de9186c2SPaul Mundt {
329609d7558SPaul Mundt return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table,
330de9186c2SPaul Mundt &sh_clk_div6_reparent_clk_ops);
331de9186c2SPaul Mundt }
332de9186c2SPaul Mundt
333a60977a5SPaul Mundt /*
334a60977a5SPaul Mundt * div4 support
335a60977a5SPaul Mundt */
sh_clk_div4_set_parent(struct clk * clk,struct clk * parent)336de9186c2SPaul Mundt static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
337de9186c2SPaul Mundt {
338a60977a5SPaul Mundt struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
339de9186c2SPaul Mundt u32 value;
340de9186c2SPaul Mundt int ret;
341de9186c2SPaul Mundt
342de9186c2SPaul Mundt /* we really need a better way to determine parent index, but for
343de9186c2SPaul Mundt * now assume internal parent comes with CLK_ENABLE_ON_INIT set,
344de9186c2SPaul Mundt * no CLK_ENABLE_ON_INIT means external clock...
345de9186c2SPaul Mundt */
346de9186c2SPaul Mundt
347de9186c2SPaul Mundt if (parent->flags & CLK_ENABLE_ON_INIT)
348104fa61aSPaul Mundt value = sh_clk_read(clk) & ~(1 << 7);
349de9186c2SPaul Mundt else
350104fa61aSPaul Mundt value = sh_clk_read(clk) | (1 << 7);
351de9186c2SPaul Mundt
352de9186c2SPaul Mundt ret = clk_reparent(clk, parent);
353de9186c2SPaul Mundt if (ret < 0)
354de9186c2SPaul Mundt return ret;
355de9186c2SPaul Mundt
356104fa61aSPaul Mundt sh_clk_write(value, clk);
357de9186c2SPaul Mundt
358de9186c2SPaul Mundt /* Rebiuld the frequency table */
359de9186c2SPaul Mundt clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
360de9186c2SPaul Mundt table, &clk->arch_flags);
361de9186c2SPaul Mundt
362de9186c2SPaul Mundt return 0;
363de9186c2SPaul Mundt }
364de9186c2SPaul Mundt
365a0ec360fSMagnus Damm static struct sh_clk_ops sh_clk_div4_reparent_clk_ops = {
36675f5f8a5SPaul Mundt .recalc = sh_clk_div_recalc,
3670fa22168SPaul Mundt .set_rate = sh_clk_div_set_rate,
368de9186c2SPaul Mundt .round_rate = sh_clk_div_round_rate,
369764f4e4eSPaul Mundt .enable = sh_clk_div_enable,
370764f4e4eSPaul Mundt .disable = sh_clk_div_disable,
371de9186c2SPaul Mundt .set_parent = sh_clk_div4_set_parent,
372de9186c2SPaul Mundt };
373de9186c2SPaul Mundt
sh_clk_div4_register(struct clk * clks,int nr,struct clk_div4_table * table)374de9186c2SPaul Mundt int __init sh_clk_div4_register(struct clk *clks, int nr,
375de9186c2SPaul Mundt struct clk_div4_table *table)
376de9186c2SPaul Mundt {
377609d7558SPaul Mundt return sh_clk_div_register_ops(clks, nr, table, &sh_clk_div_clk_ops);
378de9186c2SPaul Mundt }
379de9186c2SPaul Mundt
sh_clk_div4_enable_register(struct clk * clks,int nr,struct clk_div4_table * table)380de9186c2SPaul Mundt int __init sh_clk_div4_enable_register(struct clk *clks, int nr,
381de9186c2SPaul Mundt struct clk_div4_table *table)
382de9186c2SPaul Mundt {
383609d7558SPaul Mundt return sh_clk_div_register_ops(clks, nr, table,
384e3c87607SPaul Mundt &sh_clk_div_enable_clk_ops);
385de9186c2SPaul Mundt }
386de9186c2SPaul Mundt
sh_clk_div4_reparent_register(struct clk * clks,int nr,struct clk_div4_table * table)387de9186c2SPaul Mundt int __init sh_clk_div4_reparent_register(struct clk *clks, int nr,
388de9186c2SPaul Mundt struct clk_div4_table *table)
389de9186c2SPaul Mundt {
390609d7558SPaul Mundt return sh_clk_div_register_ops(clks, nr, table,
391de9186c2SPaul Mundt &sh_clk_div4_reparent_clk_ops);
392de9186c2SPaul Mundt }
3939d626eccSKuninori Morimoto
3949d626eccSKuninori Morimoto /* FSI-DIV */
fsidiv_recalc(struct clk * clk)3959d626eccSKuninori Morimoto static unsigned long fsidiv_recalc(struct clk *clk)
3969d626eccSKuninori Morimoto {
3979d626eccSKuninori Morimoto u32 value;
3989d626eccSKuninori Morimoto
3999d626eccSKuninori Morimoto value = __raw_readl(clk->mapping->base);
4009d626eccSKuninori Morimoto
4019d626eccSKuninori Morimoto value >>= 16;
4029d626eccSKuninori Morimoto if (value < 2)
4039d626eccSKuninori Morimoto return clk->parent->rate;
4049d626eccSKuninori Morimoto
4059d626eccSKuninori Morimoto return clk->parent->rate / value;
4069d626eccSKuninori Morimoto }
4079d626eccSKuninori Morimoto
fsidiv_round_rate(struct clk * clk,unsigned long rate)4089d626eccSKuninori Morimoto static long fsidiv_round_rate(struct clk *clk, unsigned long rate)
4099d626eccSKuninori Morimoto {
4109d626eccSKuninori Morimoto return clk_rate_div_range_round(clk, 1, 0xffff, rate);
4119d626eccSKuninori Morimoto }
4129d626eccSKuninori Morimoto
fsidiv_disable(struct clk * clk)4139d626eccSKuninori Morimoto static void fsidiv_disable(struct clk *clk)
4149d626eccSKuninori Morimoto {
4159d626eccSKuninori Morimoto __raw_writel(0, clk->mapping->base);
4169d626eccSKuninori Morimoto }
4179d626eccSKuninori Morimoto
fsidiv_enable(struct clk * clk)4189d626eccSKuninori Morimoto static int fsidiv_enable(struct clk *clk)
4199d626eccSKuninori Morimoto {
4209d626eccSKuninori Morimoto u32 value;
4219d626eccSKuninori Morimoto
4229d626eccSKuninori Morimoto value = __raw_readl(clk->mapping->base) >> 16;
4239d626eccSKuninori Morimoto if (value < 2)
4249d626eccSKuninori Morimoto return 0;
4259d626eccSKuninori Morimoto
4269d626eccSKuninori Morimoto __raw_writel((value << 16) | 0x3, clk->mapping->base);
4279d626eccSKuninori Morimoto
4289d626eccSKuninori Morimoto return 0;
4299d626eccSKuninori Morimoto }
4309d626eccSKuninori Morimoto
fsidiv_set_rate(struct clk * clk,unsigned long rate)4319d626eccSKuninori Morimoto static int fsidiv_set_rate(struct clk *clk, unsigned long rate)
4329d626eccSKuninori Morimoto {
4339d626eccSKuninori Morimoto int idx;
4349d626eccSKuninori Morimoto
4359d626eccSKuninori Morimoto idx = (clk->parent->rate / rate) & 0xffff;
4369d626eccSKuninori Morimoto if (idx < 2)
4379d626eccSKuninori Morimoto __raw_writel(0, clk->mapping->base);
4389d626eccSKuninori Morimoto else
4399d626eccSKuninori Morimoto __raw_writel(idx << 16, clk->mapping->base);
4409d626eccSKuninori Morimoto
4419d626eccSKuninori Morimoto return 0;
4429d626eccSKuninori Morimoto }
4439d626eccSKuninori Morimoto
4449d626eccSKuninori Morimoto static struct sh_clk_ops fsidiv_clk_ops = {
4459d626eccSKuninori Morimoto .recalc = fsidiv_recalc,
4469d626eccSKuninori Morimoto .round_rate = fsidiv_round_rate,
4479d626eccSKuninori Morimoto .set_rate = fsidiv_set_rate,
4489d626eccSKuninori Morimoto .enable = fsidiv_enable,
4499d626eccSKuninori Morimoto .disable = fsidiv_disable,
4509d626eccSKuninori Morimoto };
4519d626eccSKuninori Morimoto
sh_clk_fsidiv_register(struct clk * clks,int nr)4529d626eccSKuninori Morimoto int __init sh_clk_fsidiv_register(struct clk *clks, int nr)
4539d626eccSKuninori Morimoto {
4549d626eccSKuninori Morimoto struct clk_mapping *map;
4559d626eccSKuninori Morimoto int i;
4569d626eccSKuninori Morimoto
4579d626eccSKuninori Morimoto for (i = 0; i < nr; i++) {
4589d626eccSKuninori Morimoto
4599d626eccSKuninori Morimoto map = kzalloc(sizeof(struct clk_mapping), GFP_KERNEL);
4609d626eccSKuninori Morimoto if (!map) {
4619d626eccSKuninori Morimoto pr_err("%s: unable to alloc memory\n", __func__);
4629d626eccSKuninori Morimoto return -ENOMEM;
4639d626eccSKuninori Morimoto }
4649d626eccSKuninori Morimoto
4659d626eccSKuninori Morimoto /* clks[i].enable_reg came from SH_CLK_FSIDIV() */
4669d626eccSKuninori Morimoto map->phys = (phys_addr_t)clks[i].enable_reg;
4679d626eccSKuninori Morimoto map->len = 8;
4689d626eccSKuninori Morimoto
4699d626eccSKuninori Morimoto clks[i].enable_reg = 0; /* remove .enable_reg */
4709d626eccSKuninori Morimoto clks[i].ops = &fsidiv_clk_ops;
4719d626eccSKuninori Morimoto clks[i].mapping = map;
4729d626eccSKuninori Morimoto
4739d626eccSKuninori Morimoto clk_register(&clks[i]);
4749d626eccSKuninori Morimoto }
4759d626eccSKuninori Morimoto
4769d626eccSKuninori Morimoto return 0;
4779d626eccSKuninori Morimoto }
478