Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1/*
  2 * R8A7740 processor support
  3 *
  4 * Copyright (C) 2011  Renesas Solutions Corp.
  5 * Copyright (C) 2011  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  6 *
  7 * This program is free software; you can redistribute it and/or modify
  8 * it under the terms of the GNU General Public License as published by
  9 * the Free Software Foundation; either version 2 of the License
 10 *
 11 * This program is distributed in the hope that it will be useful,
 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14 * GNU General Public License for more details.
 15 *
 16 * You should have received a copy of the GNU General Public License
 17 * along with this program; if not, write to the Free Software
 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 19 */
 20#include <linux/init.h>
 21#include <linux/kernel.h>
 22#include <linux/io.h>
 23#include <linux/sh_clk.h>
 24#include <linux/clkdev.h>
 25#include <mach/common.h>
 26#include <mach/r8a7740.h>
 27
 28/*
 29 *        |  MDx  |  XTAL1/EXTAL1   |  System   | EXTALR |
 30 *  Clock |-------+-----------------+  clock    | 32.768 |   RCLK
 31 *  Mode  | 2/1/0 | src         MHz |  source   |  KHz   |  source
 32 * -------+-------+-----------------+-----------+--------+----------
 33 *    0   | 0 0 0 | External  20~50 | XTAL1     |    O   |  EXTALR
 34 *    1   | 0 0 1 | Crystal   20~30 | XTAL1     |    O   |  EXTALR
 35 *    2   | 0 1 0 | External  40~50 | XTAL1 / 2 |    O   |  EXTALR
 36 *    3   | 0 1 1 | Crystal   40~50 | XTAL1 / 2 |    O   |  EXTALR
 37 *    4   | 1 0 0 | External  20~50 | XTAL1     |    x   |  XTAL1 / 1024
 38 *    5   | 1 0 1 | Crystal   20~30 | XTAL1     |    x   |  XTAL1 / 1024
 39 *    6   | 1 1 0 | External  40~50 | XTAL1 / 2 |    x   |  XTAL1 / 2048
 40 *    7   | 1 1 1 | Crystal   40~50 | XTAL1 / 2 |    x   |  XTAL1 / 2048
 41 */
 42
 43/* CPG registers */
 44#define FRQCRA		0xe6150000
 45#define FRQCRB		0xe6150004
 46#define FRQCRC		0xe61500e0
 47#define PLLC01CR	0xe6150028
 48
 49#define SUBCKCR		0xe6150080
 50#define USBCKCR		0xe615008c
 51
 52#define MSTPSR0		0xe6150030
 53#define MSTPSR1		0xe6150038
 54#define MSTPSR2		0xe6150040
 55#define MSTPSR3		0xe6150048
 56#define MSTPSR4		0xe615004c
 57#define SMSTPCR0	0xe6150130
 58#define SMSTPCR1	0xe6150134
 59#define SMSTPCR2	0xe6150138
 60#define SMSTPCR3	0xe615013c
 61#define SMSTPCR4	0xe6150140
 62
 63/* Fixed 32 KHz root clock from EXTALR pin */
 64static struct clk extalr_clk = {
 65	.rate	= 32768,
 66};
 67
 68/*
 69 * 25MHz default rate for the EXTAL1 root input clock.
 70 * If needed, reset this with clk_set_rate() from the platform code.
 71 */
 72static struct clk extal1_clk = {
 73	.rate	= 25000000,
 74};
 75
 76/*
 77 * 48MHz default rate for the EXTAL2 root input clock.
 78 * If needed, reset this with clk_set_rate() from the platform code.
 79 */
 80static struct clk extal2_clk = {
 81	.rate	= 48000000,
 82};
 83
 84/*
 85 * 27MHz default rate for the DV_CLKI root input clock.
 86 * If needed, reset this with clk_set_rate() from the platform code.
 87 */
 88static struct clk dv_clk = {
 89	.rate	= 27000000,
 90};
 91
 92static unsigned long div_recalc(struct clk *clk)
 93{
 94	return clk->parent->rate / (int)(clk->priv);
 95}
 96
 97static struct sh_clk_ops div_clk_ops = {
 98	.recalc	= div_recalc,
 99};
100
101/* extal1 / 2 */
102static struct clk extal1_div2_clk = {
103	.ops	= &div_clk_ops,
104	.priv	= (void *)2,
105	.parent	= &extal1_clk,
106};
107
108/* extal1 / 1024 */
109static struct clk extal1_div1024_clk = {
110	.ops	= &div_clk_ops,
111	.priv	= (void *)1024,
112	.parent	= &extal1_clk,
113};
114
115/* extal1 / 2 / 1024 */
116static struct clk extal1_div2048_clk = {
117	.ops	= &div_clk_ops,
118	.priv	= (void *)1024,
119	.parent	= &extal1_div2_clk,
120};
121
122/* extal2 / 2 */
123static struct clk extal2_div2_clk = {
124	.ops	= &div_clk_ops,
125	.priv	= (void *)2,
126	.parent	= &extal2_clk,
127};
128
129static struct sh_clk_ops followparent_clk_ops = {
130	.recalc	= followparent_recalc,
131};
132
133/* Main clock */
134static struct clk system_clk = {
135	.ops	= &followparent_clk_ops,
136};
137
138static struct clk system_div2_clk = {
139	.ops	= &div_clk_ops,
140	.priv	= (void *)2,
141	.parent	= &system_clk,
142};
143
144/* r_clk */
145static struct clk r_clk = {
146	.ops	= &followparent_clk_ops,
147};
148
149/* PLLC0/PLLC1 */
150static unsigned long pllc01_recalc(struct clk *clk)
151{
152	unsigned long mult = 1;
153
154	if (__raw_readl(PLLC01CR) & (1 << 14))
155		mult = ((__raw_readl(clk->enable_reg) >> 24) & 0x7f) + 1;
156
157	return clk->parent->rate * mult;
158}
159
160static struct sh_clk_ops pllc01_clk_ops = {
161	.recalc		= pllc01_recalc,
162};
163
164static struct clk pllc0_clk = {
165	.ops		= &pllc01_clk_ops,
166	.flags		= CLK_ENABLE_ON_INIT,
167	.parent		= &system_clk,
168	.enable_reg	= (void __iomem *)FRQCRC,
169};
170
171static struct clk pllc1_clk = {
172	.ops		= &pllc01_clk_ops,
173	.flags		= CLK_ENABLE_ON_INIT,
174	.parent		= &system_div2_clk,
175	.enable_reg	= (void __iomem *)FRQCRA,
176};
177
178/* PLLC1 / 2 */
179static struct clk pllc1_div2_clk = {
180	.ops		= &div_clk_ops,
181	.priv		= (void *)2,
182	.parent		= &pllc1_clk,
183};
184
185/* USB clock */
186static struct clk *usb24s_parents[] = {
187	[0] = &system_clk,
188	[1] = &extal2_clk
189};
190
191static int usb24s_enable(struct clk *clk)
192{
193	__raw_writel(__raw_readl(USBCKCR) & ~(1 << 8), USBCKCR);
194
195	return 0;
196}
197
198static void usb24s_disable(struct clk *clk)
199{
200	__raw_writel(__raw_readl(USBCKCR) | (1 << 8), USBCKCR);
201}
202
203static int usb24s_set_parent(struct clk *clk, struct clk *parent)
204{
205	int i, ret;
206	u32 val;
207
208	if (!clk->parent_table || !clk->parent_num)
209		return -EINVAL;
210
211	/* Search the parent */
212	for (i = 0; i < clk->parent_num; i++)
213		if (clk->parent_table[i] == parent)
214			break;
215
216	if (i == clk->parent_num)
217		return -ENODEV;
218
219	ret = clk_reparent(clk, parent);
220	if (ret < 0)
221		return ret;
222
223	val = __raw_readl(USBCKCR);
224	val &= ~(1 << 7);
225	val |= i << 7;
226	__raw_writel(val, USBCKCR);
227
228	return 0;
229}
230
231static struct sh_clk_ops usb24s_clk_ops = {
232	.recalc		= followparent_recalc,
233	.enable		= usb24s_enable,
234	.disable	= usb24s_disable,
235	.set_parent	= usb24s_set_parent,
236};
237
238static struct clk usb24s_clk = {
239	.ops		= &usb24s_clk_ops,
240	.parent_table	= usb24s_parents,
241	.parent_num	= ARRAY_SIZE(usb24s_parents),
242	.parent		= &system_clk,
243};
244
245static unsigned long usb24_recalc(struct clk *clk)
246{
247	return clk->parent->rate /
248		((__raw_readl(USBCKCR) & (1 << 6)) ? 1 : 2);
249};
250
251static int usb24_set_rate(struct clk *clk, unsigned long rate)
252{
253	u32 val;
254
255	/* closer to which ? parent->rate or parent->rate/2 */
256	val = __raw_readl(USBCKCR);
257	val &= ~(1 << 6);
258	val |= (rate > (clk->parent->rate / 4) * 3) << 6;
259	__raw_writel(val, USBCKCR);
260
261	return 0;
262}
263
264static struct sh_clk_ops usb24_clk_ops = {
265	.recalc		= usb24_recalc,
266	.set_rate	= usb24_set_rate,
267};
268
269static struct clk usb24_clk = {
270	.ops		= &usb24_clk_ops,
271	.parent		= &usb24s_clk,
272};
273
274struct clk *main_clks[] = {
275	&extalr_clk,
276	&extal1_clk,
277	&extal2_clk,
278	&extal1_div2_clk,
279	&extal1_div1024_clk,
280	&extal1_div2048_clk,
281	&extal2_div2_clk,
282	&dv_clk,
283	&system_clk,
284	&system_div2_clk,
285	&r_clk,
286	&pllc0_clk,
287	&pllc1_clk,
288	&pllc1_div2_clk,
289	&usb24s_clk,
290	&usb24_clk,
291};
292
293static void div4_kick(struct clk *clk)
294{
295	unsigned long value;
296
297	/* set KICK bit in FRQCRB to update hardware setting */
298	value = __raw_readl(FRQCRB);
299	value |= (1 << 31);
300	__raw_writel(value, FRQCRB);
301}
302
303static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18,
304			  24, 32, 36, 48, 0, 72, 96, 0 };
305
306static struct clk_div_mult_table div4_div_mult_table = {
307	.divisors = divisors,
308	.nr_divisors = ARRAY_SIZE(divisors),
309};
310
311static struct clk_div4_table div4_table = {
312	.div_mult_table = &div4_div_mult_table,
313	.kick = div4_kick,
314};
315
316enum {
317	DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_HP,
318	DIV4_HPP, DIV4_USBP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP,
319	DIV4_NR
320};
321
322struct clk div4_clks[DIV4_NR] = {
323	[DIV4_I]	= SH_CLK_DIV4(&pllc1_clk, FRQCRA, 20, 0x6fff, CLK_ENABLE_ON_INIT),
324	[DIV4_ZG]	= SH_CLK_DIV4(&pllc1_clk, FRQCRA, 16, 0x6fff, CLK_ENABLE_ON_INIT),
325	[DIV4_B]	= SH_CLK_DIV4(&pllc1_clk, FRQCRA,  8, 0x6fff, CLK_ENABLE_ON_INIT),
326	[DIV4_M1]	= SH_CLK_DIV4(&pllc1_clk, FRQCRA,  4, 0x6fff, CLK_ENABLE_ON_INIT),
327	[DIV4_HP]	= SH_CLK_DIV4(&pllc1_clk, FRQCRB,  4, 0x6fff, 0),
328	[DIV4_HPP]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC, 20, 0x6fff, 0),
329	[DIV4_USBP]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC, 16, 0x6fff, 0),
330	[DIV4_S]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC, 12, 0x6fff, 0),
331	[DIV4_ZB]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC,  8, 0x6fff, 0),
332	[DIV4_M3]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC,  4, 0x6fff, 0),
333	[DIV4_CP]	= SH_CLK_DIV4(&pllc1_clk, FRQCRC,  0, 0x6fff, 0),
334};
335
336enum {
337	DIV6_SUB,
338	DIV6_NR
339};
340
341static struct clk div6_clks[DIV6_NR] = {
342	[DIV6_SUB]	= SH_CLK_DIV6(&pllc1_div2_clk, SUBCKCR, 0),
343};
344
345enum {
346	MSTP125,
347	MSTP116, MSTP111, MSTP100, MSTP117,
348
349	MSTP230,
350	MSTP222,
351	MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
352
353	MSTP329, MSTP328, MSTP323, MSTP320,
354	MSTP314, MSTP313, MSTP312,
355	MSTP309,
356
357	MSTP416, MSTP415, MSTP407, MSTP406,
358
359	MSTP_NR
360};
361
362static struct clk mstp_clks[MSTP_NR] = {
363	[MSTP125] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR1, 25, 0), /* TMU0 */
364	[MSTP117] = SH_CLK_MSTP32(&div4_clks[DIV4_B],	SMSTPCR1, 17, 0), /* LCDC1 */
365	[MSTP116] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR1, 16, 0), /* IIC0 */
366	[MSTP111] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR1, 11, 0), /* TMU1 */
367	[MSTP100] = SH_CLK_MSTP32(&div4_clks[DIV4_B],	SMSTPCR1,  0, 0), /* LCDC0 */
368
369	[MSTP230] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR2, 30, 0), /* SCIFA6 */
370	[MSTP222] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR2, 22, 0), /* SCIFA7 */
371	[MSTP207] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR2,  7, 0), /* SCIFA5 */
372	[MSTP206] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR2,  6, 0), /* SCIFB */
373	[MSTP204] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR2,  4, 0), /* SCIFA0 */
374	[MSTP203] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR2,  3, 0), /* SCIFA1 */
375	[MSTP202] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR2,  2, 0), /* SCIFA2 */
376	[MSTP201] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR2,  1, 0), /* SCIFA3 */
377	[MSTP200] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR2,  0, 0), /* SCIFA4 */
378
379	[MSTP329] = SH_CLK_MSTP32(&r_clk,		SMSTPCR3, 29, 0), /* CMT10 */
380	[MSTP328] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR3, 28, 0), /* FSI */
381	[MSTP323] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB],	SMSTPCR3, 23, 0), /* IIC1 */
382	[MSTP320] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR3, 20, 0), /* USBF */
383	[MSTP314] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR3, 14, 0), /* SDHI0 */
384	[MSTP313] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR3, 13, 0), /* SDHI1 */
385	[MSTP312] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR3, 12, 0), /* MMC */
386	[MSTP309] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR3,  9, 0), /* GEther */
387
388	[MSTP416] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR4, 16, 0), /* USBHOST */
389	[MSTP415] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR4, 15, 0), /* SDHI2 */
390	[MSTP407] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR4,  7, 0), /* USB-Func */
391	[MSTP406] = SH_CLK_MSTP32(&div4_clks[DIV4_HP],	SMSTPCR4,  6, 0), /* USB Phy */
392};
393
394static struct clk_lookup lookups[] = {
395	/* main clocks */
396	CLKDEV_CON_ID("extalr",			&extalr_clk),
397	CLKDEV_CON_ID("extal1",			&extal1_clk),
398	CLKDEV_CON_ID("extal2",			&extal2_clk),
399	CLKDEV_CON_ID("extal1_div2",		&extal1_div2_clk),
400	CLKDEV_CON_ID("extal1_div1024",		&extal1_div1024_clk),
401	CLKDEV_CON_ID("extal1_div2048",		&extal1_div2048_clk),
402	CLKDEV_CON_ID("extal2_div2",		&extal2_div2_clk),
403	CLKDEV_CON_ID("dv_clk",			&dv_clk),
404	CLKDEV_CON_ID("system_clk",		&system_clk),
405	CLKDEV_CON_ID("system_div2_clk",	&system_div2_clk),
406	CLKDEV_CON_ID("r_clk",			&r_clk),
407	CLKDEV_CON_ID("pllc0_clk",		&pllc0_clk),
408	CLKDEV_CON_ID("pllc1_clk",		&pllc1_clk),
409	CLKDEV_CON_ID("pllc1_div2_clk",		&pllc1_div2_clk),
410	CLKDEV_CON_ID("usb24s",			&usb24s_clk),
411
412	/* DIV4 clocks */
413	CLKDEV_CON_ID("i_clk",			&div4_clks[DIV4_I]),
414	CLKDEV_CON_ID("zg_clk",			&div4_clks[DIV4_ZG]),
415	CLKDEV_CON_ID("b_clk",			&div4_clks[DIV4_B]),
416	CLKDEV_CON_ID("m1_clk",			&div4_clks[DIV4_M1]),
417	CLKDEV_CON_ID("hp_clk",			&div4_clks[DIV4_HP]),
418	CLKDEV_CON_ID("hpp_clk",		&div4_clks[DIV4_HPP]),
419	CLKDEV_CON_ID("s_clk",			&div4_clks[DIV4_S]),
420	CLKDEV_CON_ID("zb_clk",			&div4_clks[DIV4_ZB]),
421	CLKDEV_CON_ID("m3_clk",			&div4_clks[DIV4_M3]),
422	CLKDEV_CON_ID("cp_clk",			&div4_clks[DIV4_CP]),
423
424	/* DIV6 clocks */
425	CLKDEV_CON_ID("sub_clk",		&div6_clks[DIV6_SUB]),
426
427	/* MSTP32 clocks */
428	CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0",	&mstp_clks[MSTP100]),
429	CLKDEV_DEV_ID("sh_tmu.1",		&mstp_clks[MSTP111]),
430	CLKDEV_DEV_ID("i2c-sh_mobile.0",	&mstp_clks[MSTP116]),
431	CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1",	&mstp_clks[MSTP117]),
432	CLKDEV_DEV_ID("sh_tmu.0",		&mstp_clks[MSTP125]),
433
434	CLKDEV_DEV_ID("sh-sci.4",		&mstp_clks[MSTP200]),
435	CLKDEV_DEV_ID("sh-sci.3",		&mstp_clks[MSTP201]),
436	CLKDEV_DEV_ID("sh-sci.2",		&mstp_clks[MSTP202]),
437	CLKDEV_DEV_ID("sh-sci.1",		&mstp_clks[MSTP203]),
438	CLKDEV_DEV_ID("sh-sci.0",		&mstp_clks[MSTP204]),
439	CLKDEV_DEV_ID("sh-sci.8",		&mstp_clks[MSTP206]),
440	CLKDEV_DEV_ID("sh-sci.5",		&mstp_clks[MSTP207]),
441
442	CLKDEV_DEV_ID("sh-sci.7",		&mstp_clks[MSTP222]),
443	CLKDEV_DEV_ID("sh-sci.6",		&mstp_clks[MSTP230]),
444
445	CLKDEV_DEV_ID("sh_cmt.10",		&mstp_clks[MSTP329]),
446	CLKDEV_DEV_ID("sh_fsi2",		&mstp_clks[MSTP328]),
447	CLKDEV_DEV_ID("i2c-sh_mobile.1",	&mstp_clks[MSTP323]),
448	CLKDEV_DEV_ID("renesas_usbhs",		&mstp_clks[MSTP320]),
449	CLKDEV_DEV_ID("sh_mobile_sdhi.0",	&mstp_clks[MSTP314]),
450	CLKDEV_DEV_ID("sh_mobile_sdhi.1",	&mstp_clks[MSTP313]),
451	CLKDEV_DEV_ID("sh_mmcif",		&mstp_clks[MSTP312]),
452	CLKDEV_DEV_ID("sh-eth",			&mstp_clks[MSTP309]),
453
454	CLKDEV_DEV_ID("sh_mobile_sdhi.2",	&mstp_clks[MSTP415]),
455
456	/* ICK */
457	CLKDEV_ICK_ID("host",	"renesas_usbhs",	&mstp_clks[MSTP416]),
458	CLKDEV_ICK_ID("func",	"renesas_usbhs",	&mstp_clks[MSTP407]),
459	CLKDEV_ICK_ID("phy",	"renesas_usbhs",	&mstp_clks[MSTP406]),
460	CLKDEV_ICK_ID("pci",	"renesas_usbhs",	&div4_clks[DIV4_USBP]),
461	CLKDEV_ICK_ID("usb24",	"renesas_usbhs",	&usb24_clk),
462};
463
464void __init r8a7740_clock_init(u8 md_ck)
465{
466	int k, ret = 0;
467
468	/* detect system clock parent */
469	if (md_ck & MD_CK1)
470		system_clk.parent = &extal1_div2_clk;
471	else
472		system_clk.parent = &extal1_clk;
473
474	/* detect RCLK parent */
475	switch (md_ck & (MD_CK2 | MD_CK1)) {
476	case MD_CK2 | MD_CK1:
477		r_clk.parent = &extal1_div2048_clk;
478		break;
479	case MD_CK2:
480		r_clk.parent = &extal1_div1024_clk;
481		break;
482	case MD_CK1:
483	default:
484		r_clk.parent = &extalr_clk;
485		break;
486	}
487
488	for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
489		ret = clk_register(main_clks[k]);
490
491	if (!ret)
492		ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
493
494	if (!ret)
495		ret = sh_clk_div6_register(div6_clks, DIV6_NR);
496
497	if (!ret)
498		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
499
500	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
501
502	if (!ret)
503		shmobile_clk_init();
504	else
505		panic("failed to setup r8a7740 clocks\n");
506}