Blame view

arch/arm/plat-s3c24xx/s3c2410-clock.c 6.27 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /* linux/arch/arm/mach-s3c2410/clock.c
   *
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
3
   * Copyright (c) 2006 Simtec Electronics
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
   *	Ben Dooks <ben@simtec.co.uk>
   *
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
6
   * S3C2410,S3C2440,S3C2442 Clock control support
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
  
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/list.h>
  #include <linux/errno.h>
  #include <linux/err.h>
edbaa603e   Kay Sievers   driver-core: remo...
29
  #include <linux/device.h>
f8ce25476   Russell King   [ARM] Move asm/ha...
30
  #include <linux/clk.h>
00431707b   Arjan van de Ven   [ARM] Convert som...
31
  #include <linux/mutex.h>
8e40a2f91   Ben Dooks   [ARM] 3330/1: S3C...
32
  #include <linux/delay.h>
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
33
  #include <linux/serial_core.h>
fced80c73   Russell King   [ARM] Convert asm...
34
  #include <linux/io.h>
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
35
36
  
  #include <asm/mach/map.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

a09e64fbc   Russell King   [ARM] Move includ...
38
  #include <mach/hardware.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39

a2b7ba9ca   Ben Dooks   [ARM] S3C24XX: Mo...
40
  #include <plat/regs-serial.h>
a09e64fbc   Russell King   [ARM] Move includ...
41
42
  #include <mach/regs-clock.h>
  #include <mach/regs-gpio.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

a2b7ba9ca   Ben Dooks   [ARM] S3C24XX: Mo...
44
  #include <plat/s3c2410.h>
d5120ae72   Ben Dooks   [ARM] S3C24XX: Ad...
45
  #include <plat/clock.h>
a2b7ba9ca   Ben Dooks   [ARM] S3C24XX: Mo...
46
  #include <plat/cpu.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
48
  int s3c2410_clkcon_enable(struct clk *clk, int enable)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  {
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
50
51
  	unsigned int clocks = clk->ctrlbit;
  	unsigned long clkcon;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
53
  	clkcon = __raw_readl(S3C2410_CLKCON);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
55
56
  	if (enable)
  		clkcon |= clocks;
c086f282c   Ben Dooks   [ARM] 3018/1: S3C...
57
  	else
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
58
  		clkcon &= ~clocks;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
60
61
  	/* ensure none of the special function bits set */
  	clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
63
  	__raw_writel(clkcon, S3C2410_CLKCON);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64

2a513ce79   Ben Dooks   [ARM] 3303/1: S3C...
65
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  }
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
67
  static int s3c2410_upll_enable(struct clk *clk, int enable)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  {
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
69
70
  	unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
  	unsigned long orig = clkslow;
3fc3e1c06   Ben Dooks   [ARM] 3333/1: S3C...
71
72
  
  	if (enable)
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
73
  		clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF;
3fc3e1c06   Ben Dooks   [ARM] 3333/1: S3C...
74
  	else
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
75
  		clkslow |= S3C2410_CLKSLOW_UCLK_OFF;
3fc3e1c06   Ben Dooks   [ARM] 3333/1: S3C...
76

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
77
  	__raw_writel(clkslow, S3C2410_CLKSLOW);
3fc3e1c06   Ben Dooks   [ARM] 3333/1: S3C...
78

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
79
  	/* if we started the UPLL, then allow to settle */
3fc3e1c06   Ben Dooks   [ARM] 3333/1: S3C...
80

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
81
82
  	if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF))
  		udelay(200);
3fc3e1c06   Ben Dooks   [ARM] 3333/1: S3C...
83
84
85
  
  	return 0;
  }
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
86
  /* standard clock definitions */
4e04691bc   Ben Dooks   ARM: SAMSUNG: Add...
87
  static struct clk init_clocks_off[] = {
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
88
89
  	{
  		.name		= "nand",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
90
91
92
93
94
  		.parent		= &clk_h,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_NAND,
  	}, {
  		.name		= "sdi",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
95
96
97
98
99
  		.parent		= &clk_p,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_SDI,
  	}, {
  		.name		= "adc",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
100
101
102
103
104
  		.parent		= &clk_p,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_ADC,
  	}, {
  		.name		= "i2c",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
105
106
107
108
109
  		.parent		= &clk_p,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_IIC,
  	}, {
  		.name		= "iis",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
110
111
112
113
114
  		.parent		= &clk_p,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_IIS,
  	}, {
  		.name		= "spi",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
115
116
117
  		.parent		= &clk_p,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_SPI,
3fc3e1c06   Ben Dooks   [ARM] 3333/1: S3C...
118
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
  };
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
120
121
122
  static struct clk init_clocks[] = {
  	{
  		.name		= "lcd",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
123
124
125
126
127
  		.parent		= &clk_h,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_LCDC,
  	}, {
  		.name		= "gpio",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
128
129
130
131
132
  		.parent		= &clk_p,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_GPIO,
  	}, {
  		.name		= "usb-host",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
133
134
135
136
137
  		.parent		= &clk_h,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_USBH,
  	}, {
  		.name		= "usb-device",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
138
139
140
141
142
  		.parent		= &clk_h,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_USBD,
  	}, {
  		.name		= "timers",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
143
144
145
146
147
  		.parent		= &clk_p,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_PWMT,
  	}, {
  		.name		= "uart",
e83626f2f   Thomas Abraham   ARM: S3C24XX: Add...
148
  		.devname	= "s3c2410-uart.0",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
149
150
151
152
153
  		.parent		= &clk_p,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_UART0,
  	}, {
  		.name		= "uart",
e83626f2f   Thomas Abraham   ARM: S3C24XX: Add...
154
  		.devname	= "s3c2410-uart.1",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
155
156
157
158
159
  		.parent		= &clk_p,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_UART1,
  	}, {
  		.name		= "uart",
e83626f2f   Thomas Abraham   ARM: S3C24XX: Add...
160
  		.devname	= "s3c2410-uart.2",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
161
162
163
164
165
  		.parent		= &clk_p,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_UART2,
  	}, {
  		.name		= "rtc",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
166
167
168
169
170
  		.parent		= &clk_p,
  		.enable		= s3c2410_clkcon_enable,
  		.ctrlbit	= S3C2410_CLKCON_RTC,
  	}, {
  		.name		= "watchdog",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
171
172
173
174
  		.parent		= &clk_p,
  		.ctrlbit	= 0,
  	}, {
  		.name		= "usb-bus-host",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
175
176
177
  		.parent		= &clk_usb_bus,
  	}, {
  		.name		= "usb-bus-gadget",
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
178
179
  		.parent		= &clk_usb_bus,
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  };
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
181
182
183
184
185
186
187
188
189
  /* s3c2410_baseclk_add()
   *
   * Add all the clocks used by the s3c2410 or compatible CPUs
   * such as the S3C2440 and S3C2442.
   *
   * We cannot use a system device as we are needed before any
   * of the init-calls that initialise the devices are actually
   * done.
  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
191
  int __init s3c2410_baseclk_add(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  {
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
193
194
195
196
197
198
  	unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
  	unsigned long clkcon  = __raw_readl(S3C2410_CLKCON);
  	struct clk *clkp;
  	struct clk *xtal;
  	int ret;
  	int ptr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
200
  	clk_upll.enable = s3c2410_upll_enable;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
202
203
204
  	if (s3c24xx_register_clock(&clk_usb_bus) < 0)
  		printk(KERN_ERR "failed to register usb bus clock
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
206
  	/* register clocks from clock array */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
208
209
210
  	clkp = init_clocks;
  	for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
  		/* ensure that we note the clock state */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
212
  		clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
214
215
216
217
218
219
220
  		ret = s3c24xx_register_clock(clkp);
  		if (ret < 0) {
  			printk(KERN_ERR "Failed to register clock %s (%d)
  ",
  			       clkp->name, ret);
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
222
  	/* We must be careful disabling the clocks we are not intending to
3a4fa0a25   Robert P. J. Day   Fix misspellings ...
223
  	 * be using at boot time, as subsystems such as the LCD which do
a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
224
225
226
227
228
229
230
231
232
  	 * their own DMA requests to the bus can cause the system to lockup
  	 * if they where in the middle of requesting bus access.
  	 *
  	 * Disabling the LCD clock if the LCD is active is very dangerous,
  	 * and therefore the bootloader should be careful to not enable
  	 * the LCD clock if it is not needed.
  	*/
  
  	/* install (and disable) the clocks we do not need immediately */
4e04691bc   Ben Dooks   ARM: SAMSUNG: Add...
233
234
  	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
  	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
8e40a2f91   Ben Dooks   [ARM] 3330/1: S3C...
235

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
236
  	/* show the clock-slow value */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
238
  	xtal = clk_get(NULL, "xtal");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239

a21765a70   Ben Dooks   [ARM] 4157/2: S3C...
240
241
242
243
244
245
246
  	printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s
  ",
  	       print_mhz(clk_get_rate(xtal) /
  			 ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
  	       (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
  	       (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
  	       (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247

9d325f234   Ben Dooks   [ARM] S3C: Update...
248
  	s3c_pwmclk_init();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
  	return 0;
  }