blob: 5a1e97e1f8f64bb889a55eb2ff1ead4886350de4 [file] [log] [blame]
Ben Dooks4b31d8b2008-10-21 14:07:00 +01001/* linux/arch/arm/plat-s3c64xx/clock.c
2 *
3 * Copyright 2008 Openmoko, Inc.
4 * Copyright 2008 Simtec Electronics
5 * Ben Dooks <ben@simtec.co.uk>
6 * http://armlinux.simtec.co.uk/
7 *
8 * S3C64XX Base clock support
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/interrupt.h>
18#include <linux/ioport.h>
19#include <linux/delay.h>
20#include <linux/io.h>
21
22#include <mach/hardware.h>
23#include <mach/map.h>
24
Ben Dooks3627379f2008-10-31 16:14:36 +000025#include <plat/regs-sys.h>
Ben Dooks4b31d8b2008-10-21 14:07:00 +010026#include <plat/regs-clock.h>
27#include <plat/cpu.h>
28#include <plat/devs.h>
29#include <plat/clock.h>
30
31struct clk clk_27m = {
32 .name = "clk_27m",
33 .id = -1,
34 .rate = 27000000,
35};
36
Ben Dooks3627379f2008-10-31 16:14:36 +000037static int clk_48m_ctrl(struct clk *clk, int enable)
38{
39 unsigned long flags;
40 u32 val;
41
42 /* can't rely on clock lock, this register has other usages */
43 local_irq_save(flags);
44
45 val = __raw_readl(S3C64XX_OTHERS);
46 if (enable)
47 val |= S3C64XX_OTHERS_USBMASK;
48 else
49 val &= ~S3C64XX_OTHERS_USBMASK;
50
51 __raw_writel(val, S3C64XX_OTHERS);
52 local_irq_restore(flags);
53
54 return 0;
55}
56
Ben Dooks4b31d8b2008-10-21 14:07:00 +010057struct clk clk_48m = {
58 .name = "clk_48m",
59 .id = -1,
60 .rate = 48000000,
Ben Dooks3627379f2008-10-31 16:14:36 +000061 .enable = clk_48m_ctrl,
Ben Dooks4b31d8b2008-10-21 14:07:00 +010062};
63
64static int inline s3c64xx_gate(void __iomem *reg,
65 struct clk *clk,
66 int enable)
67{
68 unsigned int ctrlbit = clk->ctrlbit;
69 u32 con;
70
71 con = __raw_readl(reg);
72
73 if (enable)
74 con |= ctrlbit;
75 else
76 con &= ~ctrlbit;
77
78 __raw_writel(con, reg);
79 return 0;
80}
81
82static int s3c64xx_pclk_ctrl(struct clk *clk, int enable)
83{
84 return s3c64xx_gate(S3C_PCLK_GATE, clk, enable);
85}
86
87static int s3c64xx_hclk_ctrl(struct clk *clk, int enable)
88{
89 return s3c64xx_gate(S3C_HCLK_GATE, clk, enable);
90}
91
Ben Dookscf18acf2008-10-21 14:07:02 +010092int s3c64xx_sclk_ctrl(struct clk *clk, int enable)
Ben Dooks4b31d8b2008-10-21 14:07:00 +010093{
94 return s3c64xx_gate(S3C_SCLK_GATE, clk, enable);
95}
96
97static struct clk init_clocks_disable[] = {
98 {
99 .name = "nand",
100 .id = -1,
101 .parent = &clk_h,
102 }, {
103 .name = "adc",
104 .id = -1,
105 .parent = &clk_p,
106 .enable = s3c64xx_pclk_ctrl,
107 .ctrlbit = S3C_CLKCON_PCLK_TSADC,
108 }, {
109 .name = "i2c",
110 .id = -1,
111 .parent = &clk_p,
112 .enable = s3c64xx_pclk_ctrl,
113 .ctrlbit = S3C_CLKCON_PCLK_IIC,
114 }, {
115 .name = "iis",
116 .id = 0,
117 .parent = &clk_p,
118 .enable = s3c64xx_pclk_ctrl,
119 .ctrlbit = S3C_CLKCON_PCLK_IIS0,
120 }, {
121 .name = "iis",
122 .id = 1,
123 .parent = &clk_p,
124 .enable = s3c64xx_pclk_ctrl,
125 .ctrlbit = S3C_CLKCON_PCLK_IIS1,
126 }, {
127 .name = "spi",
128 .id = 0,
129 .parent = &clk_p,
130 .enable = s3c64xx_pclk_ctrl,
131 .ctrlbit = S3C_CLKCON_PCLK_SPI0,
132 }, {
133 .name = "spi",
134 .id = 1,
135 .parent = &clk_p,
136 .enable = s3c64xx_pclk_ctrl,
137 .ctrlbit = S3C_CLKCON_PCLK_SPI1,
138 }, {
139 .name = "48m",
140 .id = 0,
141 .parent = &clk_48m,
142 .enable = s3c64xx_sclk_ctrl,
143 .ctrlbit = S3C_CLKCON_SCLK_MMC0_48,
144 }, {
145 .name = "48m",
146 .id = 1,
147 .parent = &clk_48m,
148 .enable = s3c64xx_sclk_ctrl,
149 .ctrlbit = S3C_CLKCON_SCLK_MMC1_48,
150 }, {
151 .name = "48m",
152 .id = 2,
153 .parent = &clk_48m,
154 .enable = s3c64xx_sclk_ctrl,
155 .ctrlbit = S3C_CLKCON_SCLK_MMC2_48,
156 },
157};
158
159static struct clk init_clocks[] = {
160 {
161 .name = "lcd",
162 .id = -1,
163 .parent = &clk_h,
164 .enable = s3c64xx_hclk_ctrl,
165 .ctrlbit = S3C_CLKCON_HCLK_LCD,
166 }, {
167 .name = "gpio",
168 .id = -1,
169 .parent = &clk_p,
170 .enable = s3c64xx_pclk_ctrl,
171 .ctrlbit = S3C_CLKCON_PCLK_GPIO,
172 }, {
173 .name = "usb-host",
174 .id = -1,
175 .parent = &clk_h,
176 .enable = s3c64xx_hclk_ctrl,
177 .ctrlbit = S3C_CLKCON_SCLK_UHOST,
178 }, {
179 .name = "hsmmc",
180 .id = 0,
181 .parent = &clk_h,
182 .enable = s3c64xx_hclk_ctrl,
183 .ctrlbit = S3C_CLKCON_HCLK_HSMMC0,
184 }, {
185 .name = "hsmmc",
186 .id = 1,
187 .parent = &clk_h,
188 .enable = s3c64xx_hclk_ctrl,
189 .ctrlbit = S3C_CLKCON_HCLK_HSMMC1,
190 }, {
191 .name = "hsmmc",
192 .id = 2,
193 .parent = &clk_h,
194 .enable = s3c64xx_hclk_ctrl,
195 .ctrlbit = S3C_CLKCON_HCLK_HSMMC2,
196 }, {
197 .name = "timers",
198 .id = -1,
199 .parent = &clk_p,
200 .enable = s3c64xx_pclk_ctrl,
201 .ctrlbit = S3C_CLKCON_PCLK_PWM,
202 }, {
203 .name = "uart",
204 .id = 0,
205 .parent = &clk_p,
206 .enable = s3c64xx_pclk_ctrl,
207 .ctrlbit = S3C_CLKCON_PCLK_UART0,
208 }, {
209 .name = "uart",
210 .id = 1,
211 .parent = &clk_p,
212 .enable = s3c64xx_pclk_ctrl,
213 .ctrlbit = S3C_CLKCON_PCLK_UART1,
214 }, {
215 .name = "uart",
216 .id = 2,
217 .parent = &clk_p,
218 .enable = s3c64xx_pclk_ctrl,
219 .ctrlbit = S3C_CLKCON_PCLK_UART2,
220 }, {
221 .name = "uart",
222 .id = 3,
223 .parent = &clk_p,
224 .enable = s3c64xx_pclk_ctrl,
225 .ctrlbit = S3C_CLKCON_PCLK_UART3,
226 }, {
227 .name = "rtc",
228 .id = -1,
229 .parent = &clk_p,
230 .enable = s3c64xx_pclk_ctrl,
231 .ctrlbit = S3C_CLKCON_PCLK_RTC,
232 }, {
233 .name = "watchdog",
234 .id = -1,
235 .parent = &clk_p,
236 .ctrlbit = S3C_CLKCON_PCLK_WDT,
237 }, {
238 .name = "ac97",
239 .id = -1,
240 .parent = &clk_p,
241 .ctrlbit = S3C_CLKCON_PCLK_AC97,
242 }
243};
244
245static struct clk *clks[] __initdata = {
246 &clk_ext,
247 &clk_epll,
248 &clk_27m,
249 &clk_48m,
250};
251
252void s3c64xx_register_clocks(void)
253{
254 struct clk *clkp;
255 int ret;
256 int ptr;
257
258 s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
259
260 clkp = init_clocks;
261 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
262 ret = s3c24xx_register_clock(clkp);
263 if (ret < 0) {
264 printk(KERN_ERR "Failed to register clock %s (%d)\n",
265 clkp->name, ret);
266 }
267 }
268
269 clkp = init_clocks_disable;
270 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
271
272 ret = s3c24xx_register_clock(clkp);
273 if (ret < 0) {
274 printk(KERN_ERR "Failed to register clock %s (%d)\n",
275 clkp->name, ret);
276 }
277
278 (clkp->enable)(clkp, 0);
279 }
Ben Dooks9d325f22008-11-21 10:36:05 +0000280
281 s3c_pwmclk_init();
Ben Dooks4b31d8b2008-10-21 14:07:00 +0100282}