• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/arm/plat-s3c24xx/
1/* linux/arch/arm/mach-s3c2410/clock.c
2 *
3 * Copyright (c) 2006 Simtec Electronics
4 *	Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410,S3C2440,S3C2442 Clock control support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21*/
22
23#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/kernel.h>
26#include <linux/list.h>
27#include <linux/errno.h>
28#include <linux/err.h>
29#include <linux/sysdev.h>
30#include <linux/clk.h>
31#include <linux/mutex.h>
32#include <linux/delay.h>
33#include <linux/serial_core.h>
34#include <linux/io.h>
35
36#include <asm/mach/map.h>
37
38#include <mach/hardware.h>
39
40#include <plat/regs-serial.h>
41#include <mach/regs-clock.h>
42#include <mach/regs-gpio.h>
43
44#include <plat/s3c2410.h>
45#include <plat/clock.h>
46#include <plat/cpu.h>
47
48int s3c2410_clkcon_enable(struct clk *clk, int enable)
49{
50	unsigned int clocks = clk->ctrlbit;
51	unsigned long clkcon;
52
53	clkcon = __raw_readl(S3C2410_CLKCON);
54
55	if (enable)
56		clkcon |= clocks;
57	else
58		clkcon &= ~clocks;
59
60	/* ensure none of the special function bits set */
61	clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
62
63	__raw_writel(clkcon, S3C2410_CLKCON);
64
65	return 0;
66}
67
68static int s3c2410_upll_enable(struct clk *clk, int enable)
69{
70	unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
71	unsigned long orig = clkslow;
72
73	if (enable)
74		clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF;
75	else
76		clkslow |= S3C2410_CLKSLOW_UCLK_OFF;
77
78	__raw_writel(clkslow, S3C2410_CLKSLOW);
79
80	/* if we started the UPLL, then allow to settle */
81
82	if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF))
83		udelay(200);
84
85	return 0;
86}
87
88/* standard clock definitions */
89
90static struct clk init_clocks_off[] = {
91	{
92		.name		= "nand",
93		.id		= -1,
94		.parent		= &clk_h,
95		.enable		= s3c2410_clkcon_enable,
96		.ctrlbit	= S3C2410_CLKCON_NAND,
97	}, {
98		.name		= "sdi",
99		.id		= -1,
100		.parent		= &clk_p,
101		.enable		= s3c2410_clkcon_enable,
102		.ctrlbit	= S3C2410_CLKCON_SDI,
103	}, {
104		.name		= "adc",
105		.id		= -1,
106		.parent		= &clk_p,
107		.enable		= s3c2410_clkcon_enable,
108		.ctrlbit	= S3C2410_CLKCON_ADC,
109	}, {
110		.name		= "i2c",
111		.id		= -1,
112		.parent		= &clk_p,
113		.enable		= s3c2410_clkcon_enable,
114		.ctrlbit	= S3C2410_CLKCON_IIC,
115	}, {
116		.name		= "iis",
117		.id		= -1,
118		.parent		= &clk_p,
119		.enable		= s3c2410_clkcon_enable,
120		.ctrlbit	= S3C2410_CLKCON_IIS,
121	}, {
122		.name		= "spi",
123		.id		= -1,
124		.parent		= &clk_p,
125		.enable		= s3c2410_clkcon_enable,
126		.ctrlbit	= S3C2410_CLKCON_SPI,
127	}
128};
129
130static struct clk init_clocks[] = {
131	{
132		.name		= "lcd",
133		.id		= -1,
134		.parent		= &clk_h,
135		.enable		= s3c2410_clkcon_enable,
136		.ctrlbit	= S3C2410_CLKCON_LCDC,
137	}, {
138		.name		= "gpio",
139		.id		= -1,
140		.parent		= &clk_p,
141		.enable		= s3c2410_clkcon_enable,
142		.ctrlbit	= S3C2410_CLKCON_GPIO,
143	}, {
144		.name		= "usb-host",
145		.id		= -1,
146		.parent		= &clk_h,
147		.enable		= s3c2410_clkcon_enable,
148		.ctrlbit	= S3C2410_CLKCON_USBH,
149	}, {
150		.name		= "usb-device",
151		.id		= -1,
152		.parent		= &clk_h,
153		.enable		= s3c2410_clkcon_enable,
154		.ctrlbit	= S3C2410_CLKCON_USBD,
155	}, {
156		.name		= "timers",
157		.id		= -1,
158		.parent		= &clk_p,
159		.enable		= s3c2410_clkcon_enable,
160		.ctrlbit	= S3C2410_CLKCON_PWMT,
161	}, {
162		.name		= "uart",
163		.id		= 0,
164		.parent		= &clk_p,
165		.enable		= s3c2410_clkcon_enable,
166		.ctrlbit	= S3C2410_CLKCON_UART0,
167	}, {
168		.name		= "uart",
169		.id		= 1,
170		.parent		= &clk_p,
171		.enable		= s3c2410_clkcon_enable,
172		.ctrlbit	= S3C2410_CLKCON_UART1,
173	}, {
174		.name		= "uart",
175		.id		= 2,
176		.parent		= &clk_p,
177		.enable		= s3c2410_clkcon_enable,
178		.ctrlbit	= S3C2410_CLKCON_UART2,
179	}, {
180		.name		= "rtc",
181		.id		= -1,
182		.parent		= &clk_p,
183		.enable		= s3c2410_clkcon_enable,
184		.ctrlbit	= S3C2410_CLKCON_RTC,
185	}, {
186		.name		= "watchdog",
187		.id		= -1,
188		.parent		= &clk_p,
189		.ctrlbit	= 0,
190	}, {
191		.name		= "usb-bus-host",
192		.id		= -1,
193		.parent		= &clk_usb_bus,
194	}, {
195		.name		= "usb-bus-gadget",
196		.id		= -1,
197		.parent		= &clk_usb_bus,
198	},
199};
200
201/* s3c2410_baseclk_add()
202 *
203 * Add all the clocks used by the s3c2410 or compatible CPUs
204 * such as the S3C2440 and S3C2442.
205 *
206 * We cannot use a system device as we are needed before any
207 * of the init-calls that initialise the devices are actually
208 * done.
209*/
210
211int __init s3c2410_baseclk_add(void)
212{
213	unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
214	unsigned long clkcon  = __raw_readl(S3C2410_CLKCON);
215	struct clk *clkp;
216	struct clk *xtal;
217	int ret;
218	int ptr;
219
220	clk_upll.enable = s3c2410_upll_enable;
221
222	if (s3c24xx_register_clock(&clk_usb_bus) < 0)
223		printk(KERN_ERR "failed to register usb bus clock\n");
224
225	/* register clocks from clock array */
226
227	clkp = init_clocks;
228	for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
229		/* ensure that we note the clock state */
230
231		clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
232
233		ret = s3c24xx_register_clock(clkp);
234		if (ret < 0) {
235			printk(KERN_ERR "Failed to register clock %s (%d)\n",
236			       clkp->name, ret);
237		}
238	}
239
240	/* We must be careful disabling the clocks we are not intending to
241	 * be using at boot time, as subsystems such as the LCD which do
242	 * their own DMA requests to the bus can cause the system to lockup
243	 * if they where in the middle of requesting bus access.
244	 *
245	 * Disabling the LCD clock if the LCD is active is very dangerous,
246	 * and therefore the bootloader should be careful to not enable
247	 * the LCD clock if it is not needed.
248	*/
249
250	/* install (and disable) the clocks we do not need immediately */
251
252	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
253	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
254
255	/* show the clock-slow value */
256
257	xtal = clk_get(NULL, "xtal");
258
259	printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
260	       print_mhz(clk_get_rate(xtal) /
261			 ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
262	       (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
263	       (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
264	       (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
265
266	s3c_pwmclk_init();
267	return 0;
268}
269