xref: /openbmc/linux/drivers/sh/clk/cpg.c (revision 8f28ca6b)
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