aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-s3c24xx
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2008-12-18 09:52:00 -0500
committerBen Dooks <ben-linux@fluff.org>2008-12-18 09:52:00 -0500
commitc6ad115876763e4f15055982ecb9579cb7abab5f (patch)
tree75d2b0f5f31540ff8a2dcdde9e0f087b25c68868 /arch/arm/plat-s3c24xx
parent1d19fdba149f4db055902c30b27adfb7d1ead058 (diff)
parent28ab44c5be60a9b91021a7cc7b4e202775c04764 (diff)
Merge branch 'next-s3c24xx' into next-merged
Diffstat (limited to 'arch/arm/plat-s3c24xx')
-rw-r--r--arch/arm/plat-s3c24xx/Kconfig36
-rw-r--r--arch/arm/plat-s3c24xx/Makefile13
-rw-r--r--arch/arm/plat-s3c24xx/adc.c372
-rw-r--r--arch/arm/plat-s3c24xx/clock-dclk.c194
-rw-r--r--arch/arm/plat-s3c24xx/clock.c493
-rw-r--r--arch/arm/plat-s3c24xx/cpu.c141
-rw-r--r--arch/arm/plat-s3c24xx/devs.c10
-rw-r--r--arch/arm/plat-s3c24xx/gpiolib.c49
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/clock.h64
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/cpu.h54
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/devs.h49
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/pll.h37
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/s3c2400.h2
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/s3c2410.h2
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/s3c2412.h2
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/s3c2443.h2
-rw-r--r--arch/arm/plat-s3c24xx/irq.c1
-rw-r--r--arch/arm/plat-s3c24xx/pm.c4
-rw-r--r--arch/arm/plat-s3c24xx/pwm-clock.c437
-rw-r--r--arch/arm/plat-s3c24xx/s3c2410-clock.c276
-rw-r--r--arch/arm/plat-s3c24xx/s3c244x-clock.c5
-rw-r--r--arch/arm/plat-s3c24xx/s3c244x.c27
-rw-r--r--arch/arm/plat-s3c24xx/s3c244x.h2
-rw-r--r--arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c37
-rw-r--r--arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c37
-rw-r--r--arch/arm/plat-s3c24xx/time.c260
26 files changed, 1072 insertions, 1534 deletions
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
index 7fe28aaa08ca..0e07de2c9a9b 100644
--- a/arch/arm/plat-s3c24xx/Kconfig
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -15,6 +15,19 @@ config PLAT_S3C24XX
15 15
16if PLAT_S3C24XX 16if PLAT_S3C24XX
17 17
18# code that is shared between a number of the s3c24xx implementations
19
20config S3C2410_CLOCK
21 bool
22 help
23 Clock code for the S3C2410, and similar processors which
24 is currently includes the S3C2410, S3C2440, S3C2442.
25
26config S3C24XX_DCLK
27 bool
28 help
29 Clock code for supporting DCLK/CLKOUT on S3C24XX architectures
30
18config CPU_S3C244X 31config CPU_S3C244X
19 bool 32 bool
20 depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442) 33 depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
@@ -70,6 +83,29 @@ config S3C2410_DMA_DEBUG
70 Enable debugging output for the DMA code. This option sends info 83 Enable debugging output for the DMA code. This option sends info
71 to the kernel log, at priority KERN_DEBUG. 84 to the kernel log, at priority KERN_DEBUG.
72 85
86config S3C24XX_ADC
87 bool "ADC common driver support"
88 help
89 Core support for the ADC block found in the S3C24XX SoC systems
90 for drivers such as the touchscreen and hwmon to use to share
91 this resource.
92
93# SPI default pin configuration code
94
95config S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13
96 bool
97 help
98 SPI GPIO configuration code for BUS0 when connected to
99 GPE11, GPE12 and GPE13.
100
101config S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7
102 bool
103 help
104 SPI GPIO configuration code for BUS 1 when connected to
105 GPG5, GPG6 and GPG7.
106
107# common code for s3c24xx based machines, such as the SMDKs.
108
73config MACH_SMDK 109config MACH_SMDK
74 bool 110 bool
75 help 111 help
diff --git a/arch/arm/plat-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile
index d82767b2b833..a8cfdefc29e9 100644
--- a/arch/arm/plat-s3c24xx/Makefile
+++ b/arch/arm/plat-s3c24xx/Makefile
@@ -17,9 +17,8 @@ obj-y += irq.o
17obj-y += devs.o 17obj-y += devs.o
18obj-y += gpio.o 18obj-y += gpio.o
19obj-y += gpiolib.o 19obj-y += gpiolib.o
20obj-y += time.o
21obj-y += clock.o 20obj-y += clock.o
22obj-y += pwm-clock.o 21obj-$(CONFIG_S3C24XX_DCLK) += clock-dclk.o
23 22
24# Architecture dependant builds 23# Architecture dependant builds
25 24
@@ -30,5 +29,15 @@ obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
30obj-$(CONFIG_PM) += pm.o 29obj-$(CONFIG_PM) += pm.o
31obj-$(CONFIG_PM) += sleep.o 30obj-$(CONFIG_PM) += sleep.o
32obj-$(CONFIG_HAVE_PWM) += pwm.o 31obj-$(CONFIG_HAVE_PWM) += pwm.o
32obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o
33obj-$(CONFIG_S3C2410_DMA) += dma.o 33obj-$(CONFIG_S3C2410_DMA) += dma.o
34obj-$(CONFIG_S3C24XX_ADC) += adc.o
35
36# SPI gpio central GPIO functions
37
38obj-$(CONFIG_S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13) += spi-bus0-gpe11_12_13.o
39obj-$(CONFIG_S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7) += spi-bus1-gpg5_6_7.o
40
41# machine common support
42
34obj-$(CONFIG_MACH_SMDK) += common-smdk.o 43obj-$(CONFIG_MACH_SMDK) += common-smdk.o
diff --git a/arch/arm/plat-s3c24xx/adc.c b/arch/arm/plat-s3c24xx/adc.c
new file mode 100644
index 000000000000..9a5c767e0a42
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/adc.c
@@ -0,0 +1,372 @@
1/* arch/arm/plat-s3c24xx/adc.c
2 *
3 * Copyright (c) 2008 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
6 *
7 * S3C24XX ADC device core
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License.
12*/
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/platform_device.h>
17#include <linux/list.h>
18#include <linux/err.h>
19#include <linux/clk.h>
20#include <linux/interrupt.h>
21#include <linux/io.h>
22
23#include <plat/regs-adc.h>
24#include <plat/adc.h>
25
26/* This driver is designed to control the usage of the ADC block between
27 * the touchscreen and any other drivers that may need to use it, such as
28 * the hwmon driver.
29 *
30 * Priority will be given to the touchscreen driver, but as this itself is
31 * rate limited it should not starve other requests which are processed in
32 * order that they are received.
33 *
34 * Each user registers to get a client block which uniquely identifies it
35 * and stores information such as the necessary functions to callback when
36 * action is required.
37 */
38
39struct s3c_adc_client {
40 struct platform_device *pdev;
41 struct list_head pend;
42
43 unsigned int nr_samples;
44 unsigned char is_ts;
45 unsigned char channel;
46
47 void (*select_cb)(unsigned selected);
48 void (*convert_cb)(unsigned val1, unsigned val2);
49};
50
51struct adc_device {
52 struct platform_device *pdev;
53 struct platform_device *owner;
54 struct clk *clk;
55 struct s3c_adc_client *cur;
56 struct s3c_adc_client *ts_pend;
57 void __iomem *regs;
58
59 unsigned int prescale;
60
61 int irq;
62};
63
64static struct adc_device *adc_dev;
65
66static LIST_HEAD(adc_pending);
67
68#define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
69
70static inline void s3c_adc_convert(struct adc_device *adc)
71{
72 unsigned con = readl(adc->regs + S3C2410_ADCCON);
73
74 con |= S3C2410_ADCCON_ENABLE_START;
75 writel(con, adc->regs + S3C2410_ADCCON);
76}
77
78static inline void s3c_adc_select(struct adc_device *adc,
79 struct s3c_adc_client *client)
80{
81 unsigned con = readl(adc->regs + S3C2410_ADCCON);
82
83 client->select_cb(1);
84
85 con &= ~S3C2410_ADCCON_MUXMASK;
86 con &= ~S3C2410_ADCCON_STDBM;
87 con &= ~S3C2410_ADCCON_STARTMASK;
88
89 if (!client->is_ts)
90 con |= S3C2410_ADCCON_SELMUX(client->channel);
91
92 writel(con, adc->regs + S3C2410_ADCCON);
93}
94
95static void s3c_adc_dbgshow(struct adc_device *adc)
96{
97 adc_dbg(adc, "CON=%08x, TSC=%08x, DLY=%08x\n",
98 readl(adc->regs + S3C2410_ADCCON),
99 readl(adc->regs + S3C2410_ADCTSC),
100 readl(adc->regs + S3C2410_ADCDLY));
101}
102
103void s3c_adc_try(struct adc_device *adc)
104{
105 struct s3c_adc_client *next = adc->ts_pend;
106
107 if (!next && !list_empty(&adc_pending)) {
108 next = list_first_entry(&adc_pending,
109 struct s3c_adc_client, pend);
110 list_del(&next->pend);
111 } else
112 adc->ts_pend = NULL;
113
114 if (next) {
115 adc_dbg(adc, "new client is %p\n", next);
116 adc->cur = next;
117 s3c_adc_select(adc, next);
118 s3c_adc_convert(adc);
119 s3c_adc_dbgshow(adc);
120 }
121}
122
123int s3c_adc_start(struct s3c_adc_client *client,
124 unsigned int channel, unsigned int nr_samples)
125{
126 struct adc_device *adc = adc_dev;
127 unsigned long flags;
128
129 if (!adc) {
130 printk(KERN_ERR "%s: failed to find adc\n", __func__);
131 return -EINVAL;
132 }
133
134 if (client->is_ts && adc->ts_pend)
135 return -EAGAIN;
136
137 local_irq_save(flags);
138
139 client->channel = channel;
140 client->nr_samples = nr_samples;
141
142 if (client->is_ts)
143 adc->ts_pend = client;
144 else
145 list_add_tail(&client->pend, &adc_pending);
146
147 if (!adc->cur)
148 s3c_adc_try(adc);
149 local_irq_restore(flags);
150
151 return 0;
152}
153EXPORT_SYMBOL_GPL(s3c_adc_start);
154
155static void s3c_adc_default_select(unsigned select)
156{
157}
158
159struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
160 void (*select)(unsigned int selected),
161 void (*conv)(unsigned d0, unsigned d1),
162 unsigned int is_ts)
163{
164 struct s3c_adc_client *client;
165
166 WARN_ON(!pdev);
167 WARN_ON(!conv);
168
169 if (!select)
170 select = s3c_adc_default_select;
171
172 if (!conv || !pdev)
173 return ERR_PTR(-EINVAL);
174
175 client = kzalloc(sizeof(struct s3c_adc_client), GFP_KERNEL);
176 if (!client) {
177 dev_err(&pdev->dev, "no memory for adc client\n");
178 return ERR_PTR(-ENOMEM);
179 }
180
181 client->pdev = pdev;
182 client->is_ts = is_ts;
183 client->select_cb = select;
184 client->convert_cb = conv;
185
186 return client;
187}
188EXPORT_SYMBOL_GPL(s3c_adc_register);
189
190void s3c_adc_release(struct s3c_adc_client *client)
191{
192 /* We should really check that nothing is in progress. */
193 kfree(client);
194}
195EXPORT_SYMBOL_GPL(s3c_adc_release);
196
197static irqreturn_t s3c_adc_irq(int irq, void *pw)
198{
199 struct adc_device *adc = pw;
200 struct s3c_adc_client *client = adc->cur;
201 unsigned long flags;
202 unsigned data0, data1;
203
204 if (!client) {
205 dev_warn(&adc->pdev->dev, "%s: no adc pending\n", __func__);
206 return IRQ_HANDLED;
207 }
208
209 data0 = readl(adc->regs + S3C2410_ADCDAT0);
210 data1 = readl(adc->regs + S3C2410_ADCDAT1);
211 adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);
212
213 (client->convert_cb)(data0 & 0x3ff, data1 & 0x3ff);
214
215 if (--client->nr_samples > 0) {
216 /* fire another conversion for this */
217
218 client->select_cb(1);
219 s3c_adc_convert(adc);
220 } else {
221 local_irq_save(flags);
222 (client->select_cb)(0);
223 adc->cur = NULL;
224
225 s3c_adc_try(adc);
226 local_irq_restore(flags);
227 }
228
229 return IRQ_HANDLED;
230}
231
232static int s3c_adc_probe(struct platform_device *pdev)
233{
234 struct device *dev = &pdev->dev;
235 struct adc_device *adc;
236 struct resource *regs;
237 int ret;
238
239 adc = kzalloc(sizeof(struct adc_device), GFP_KERNEL);
240 if (adc == NULL) {
241 dev_err(dev, "failed to allocate adc_device\n");
242 return -ENOMEM;
243 }
244
245 adc->pdev = pdev;
246 adc->prescale = S3C2410_ADCCON_PRSCVL(49);
247
248 adc->irq = platform_get_irq(pdev, 1);
249 if (adc->irq <= 0) {
250 dev_err(dev, "failed to get adc irq\n");
251 ret = -ENOENT;
252 goto err_alloc;
253 }
254
255 ret = request_irq(adc->irq, s3c_adc_irq, 0, dev_name(dev), adc);
256 if (ret < 0) {
257 dev_err(dev, "failed to attach adc irq\n");
258 goto err_alloc;
259 }
260
261 adc->clk = clk_get(dev, "adc");
262 if (IS_ERR(adc->clk)) {
263 dev_err(dev, "failed to get adc clock\n");
264 ret = PTR_ERR(adc->clk);
265 goto err_irq;
266 }
267
268 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
269 if (!regs) {
270 dev_err(dev, "failed to find registers\n");
271 ret = -ENXIO;
272 goto err_clk;
273 }
274
275 adc->regs = ioremap(regs->start, resource_size(regs));
276 if (!adc->regs) {
277 dev_err(dev, "failed to map registers\n");
278 ret = -ENXIO;
279 goto err_clk;
280 }
281
282 clk_enable(adc->clk);
283
284 writel(adc->prescale | S3C2410_ADCCON_PRSCEN,
285 adc->regs + S3C2410_ADCCON);
286
287 dev_info(dev, "attached adc driver\n");
288
289 platform_set_drvdata(pdev, adc);
290 adc_dev = adc;
291
292 return 0;
293
294 err_clk:
295 clk_put(adc->clk);
296
297 err_irq:
298 free_irq(adc->irq, adc);
299
300 err_alloc:
301 kfree(adc);
302 return ret;
303}
304
305static int s3c_adc_remove(struct platform_device *pdev)
306{
307 struct adc_device *adc = platform_get_drvdata(pdev);
308
309 iounmap(adc->regs);
310 free_irq(adc->irq, adc);
311 clk_disable(adc->clk);
312 clk_put(adc->clk);
313 kfree(adc);
314
315 return 0;
316}
317
318#ifdef CONFIG_PM
319static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state)
320{
321 struct adc_device *adc = platform_get_drvdata(pdev);
322 u32 con;
323
324 con = readl(adc->regs + S3C2410_ADCCON);
325 con |= S3C2410_ADCCON_STDBM;
326 writel(con, adc->regs + S3C2410_ADCCON);
327
328 clk_disable(adc->clk);
329
330 return 0;
331}
332
333static int s3c_adc_resume(struct platform_device *pdev)
334{
335 struct adc_device *adc = platform_get_drvdata(pdev);
336
337 clk_enable(adc->clk);
338
339 writel(adc->prescale | S3C2410_ADCCON_PRSCEN,
340 adc->regs + S3C2410_ADCCON);
341
342 return 0;
343}
344
345#else
346#define s3c_adc_suspend NULL
347#define s3c_adc_resume NULL
348#endif
349
350static struct platform_driver s3c_adc_driver = {
351 .driver = {
352 .name = "s3c24xx-adc",
353 .owner = THIS_MODULE,
354 },
355 .probe = s3c_adc_probe,
356 .remove = __devexit_p(s3c_adc_remove),
357 .suspend = s3c_adc_suspend,
358 .resume = s3c_adc_resume,
359};
360
361static int __init adc_init(void)
362{
363 int ret;
364
365 ret = platform_driver_register(&s3c_adc_driver);
366 if (ret)
367 printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
368
369 return ret;
370}
371
372arch_initcall(adc_init);
diff --git a/arch/arm/plat-s3c24xx/clock-dclk.c b/arch/arm/plat-s3c24xx/clock-dclk.c
new file mode 100644
index 000000000000..5b75a797b5ab
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/clock-dclk.c
@@ -0,0 +1,194 @@
1/* linux/arch/arm/plat-s3c24xx/clock-dclk.c
2 *
3 * Copyright (c) 2004,2008 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 * http://armlinux.simtec.co.uk/
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 version 2 as
9 * published by the Free Software Foundation.
10 *
11 * S3C24XX - definitions for DCLK and CLKOUT registers
12 */
13
14#include <linux/kernel.h>
15#include <linux/errno.h>
16#include <linux/clk.h>
17#include <linux/io.h>
18
19#include <mach/regs-clock.h>
20#include <mach/regs-gpio.h>
21
22#include <plat/clock.h>
23#include <plat/cpu.h>
24
25/* clocks that could be registered by external code */
26
27static int s3c24xx_dclk_enable(struct clk *clk, int enable)
28{
29 unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
30
31 if (enable)
32 dclkcon |= clk->ctrlbit;
33 else
34 dclkcon &= ~clk->ctrlbit;
35
36 __raw_writel(dclkcon, S3C24XX_DCLKCON);
37
38 return 0;
39}
40
41static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
42{
43 unsigned long dclkcon;
44 unsigned int uclk;
45
46 if (parent == &clk_upll)
47 uclk = 1;
48 else if (parent == &clk_p)
49 uclk = 0;
50 else
51 return -EINVAL;
52
53 clk->parent = parent;
54
55 dclkcon = __raw_readl(S3C24XX_DCLKCON);
56
57 if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
58 if (uclk)
59 dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
60 else
61 dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
62 } else {
63 if (uclk)
64 dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
65 else
66 dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
67 }
68
69 __raw_writel(dclkcon, S3C24XX_DCLKCON);
70
71 return 0;
72}
73static unsigned long s3c24xx_calc_div(struct clk *clk, unsigned long rate)
74{
75 unsigned long div;
76
77 if ((rate == 0) || !clk->parent)
78 return 0;
79
80 div = clk_get_rate(clk->parent) / rate;
81 if (div < 2)
82 div = 2;
83 else if (div > 16)
84 div = 16;
85
86 return div;
87}
88
89static unsigned long s3c24xx_round_dclk_rate(struct clk *clk,
90 unsigned long rate)
91{
92 unsigned long div = s3c24xx_calc_div(clk, rate);
93
94 if (div == 0)
95 return 0;
96
97 return clk_get_rate(clk->parent) / div;
98}
99
100static int s3c24xx_set_dclk_rate(struct clk *clk, unsigned long rate)
101{
102 unsigned long mask, data, div = s3c24xx_calc_div(clk, rate);
103
104 if (div == 0)
105 return -EINVAL;
106
107 if (clk == &s3c24xx_dclk0) {
108 mask = S3C2410_DCLKCON_DCLK0_DIV_MASK |
109 S3C2410_DCLKCON_DCLK0_CMP_MASK;
110 data = S3C2410_DCLKCON_DCLK0_DIV(div) |
111 S3C2410_DCLKCON_DCLK0_CMP((div + 1) / 2);
112 } else if (clk == &s3c24xx_dclk1) {
113 mask = S3C2410_DCLKCON_DCLK1_DIV_MASK |
114 S3C2410_DCLKCON_DCLK1_CMP_MASK;
115 data = S3C2410_DCLKCON_DCLK1_DIV(div) |
116 S3C2410_DCLKCON_DCLK1_CMP((div + 1) / 2);
117 } else
118 return -EINVAL;
119
120 clk->rate = clk_get_rate(clk->parent) / div;
121 __raw_writel(((__raw_readl(S3C24XX_DCLKCON) & ~mask) | data),
122 S3C24XX_DCLKCON);
123 return clk->rate;
124}
125static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
126{
127 unsigned long mask;
128 unsigned long source;
129
130 /* calculate the MISCCR setting for the clock */
131
132 if (parent == &clk_xtal)
133 source = S3C2410_MISCCR_CLK0_MPLL;
134 else if (parent == &clk_upll)
135 source = S3C2410_MISCCR_CLK0_UPLL;
136 else if (parent == &clk_f)
137 source = S3C2410_MISCCR_CLK0_FCLK;
138 else if (parent == &clk_h)
139 source = S3C2410_MISCCR_CLK0_HCLK;
140 else if (parent == &clk_p)
141 source = S3C2410_MISCCR_CLK0_PCLK;
142 else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
143 source = S3C2410_MISCCR_CLK0_DCLK0;
144 else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
145 source = S3C2410_MISCCR_CLK0_DCLK0;
146 else
147 return -EINVAL;
148
149 clk->parent = parent;
150
151 if (clk == &s3c24xx_clkout0)
152 mask = S3C2410_MISCCR_CLK0_MASK;
153 else {
154 source <<= 4;
155 mask = S3C2410_MISCCR_CLK1_MASK;
156 }
157
158 s3c2410_modify_misccr(mask, source);
159 return 0;
160}
161
162/* external clock definitions */
163
164struct clk s3c24xx_dclk0 = {
165 .name = "dclk0",
166 .id = -1,
167 .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
168 .enable = s3c24xx_dclk_enable,
169 .set_parent = s3c24xx_dclk_setparent,
170 .set_rate = s3c24xx_set_dclk_rate,
171 .round_rate = s3c24xx_round_dclk_rate,
172};
173
174struct clk s3c24xx_dclk1 = {
175 .name = "dclk1",
176 .id = -1,
177 .ctrlbit = S3C2410_DCLKCON_DCLK1EN,
178 .enable = s3c24xx_dclk_enable,
179 .set_parent = s3c24xx_dclk_setparent,
180 .set_rate = s3c24xx_set_dclk_rate,
181 .round_rate = s3c24xx_round_dclk_rate,
182};
183
184struct clk s3c24xx_clkout0 = {
185 .name = "clkout0",
186 .id = -1,
187 .set_parent = s3c24xx_clkout_setparent,
188};
189
190struct clk s3c24xx_clkout1 = {
191 .name = "clkout1",
192 .id = -1,
193 .set_parent = s3c24xx_clkout_setparent,
194};
diff --git a/arch/arm/plat-s3c24xx/clock.c b/arch/arm/plat-s3c24xx/clock.c
index a005ddbd9ef3..8474d05274bd 100644
--- a/arch/arm/plat-s3c24xx/clock.c
+++ b/arch/arm/plat-s3c24xx/clock.c
@@ -27,18 +27,8 @@
27*/ 27*/
28 28
29#include <linux/init.h> 29#include <linux/init.h>
30#include <linux/module.h>
31#include <linux/kernel.h> 30#include <linux/kernel.h>
32#include <linux/list.h>
33#include <linux/errno.h>
34#include <linux/err.h>
35#include <linux/platform_device.h>
36#include <linux/sysdev.h>
37#include <linux/interrupt.h>
38#include <linux/ioport.h>
39#include <linux/clk.h> 31#include <linux/clk.h>
40#include <linux/mutex.h>
41#include <linux/delay.h>
42#include <linux/io.h> 32#include <linux/io.h>
43 33
44#include <mach/hardware.h> 34#include <mach/hardware.h>
@@ -47,490 +37,23 @@
47#include <mach/regs-clock.h> 37#include <mach/regs-clock.h>
48#include <mach/regs-gpio.h> 38#include <mach/regs-gpio.h>
49 39
40#include <plat/cpu-freq.h>
41
50#include <plat/clock.h> 42#include <plat/clock.h>
51#include <plat/cpu.h> 43#include <plat/cpu.h>
52 44#include <plat/pll.h>
53/* clock information */
54
55static LIST_HEAD(clocks);
56
57DEFINE_MUTEX(clocks_mutex);
58
59/* enable and disable calls for use with the clk struct */
60
61static int clk_null_enable(struct clk *clk, int enable)
62{
63 return 0;
64}
65
66/* Clock API calls */
67
68struct clk *clk_get(struct device *dev, const char *id)
69{
70 struct clk *p;
71 struct clk *clk = ERR_PTR(-ENOENT);
72 int idno;
73
74 if (dev == NULL || dev->bus != &platform_bus_type)
75 idno = -1;
76 else
77 idno = to_platform_device(dev)->id;
78
79 mutex_lock(&clocks_mutex);
80
81 list_for_each_entry(p, &clocks, list) {
82 if (p->id == idno &&
83 strcmp(id, p->name) == 0 &&
84 try_module_get(p->owner)) {
85 clk = p;
86 break;
87 }
88 }
89
90 /* check for the case where a device was supplied, but the
91 * clock that was being searched for is not device specific */
92
93 if (IS_ERR(clk)) {
94 list_for_each_entry(p, &clocks, list) {
95 if (p->id == -1 && strcmp(id, p->name) == 0 &&
96 try_module_get(p->owner)) {
97 clk = p;
98 break;
99 }
100 }
101 }
102
103 mutex_unlock(&clocks_mutex);
104 return clk;
105}
106
107void clk_put(struct clk *clk)
108{
109 module_put(clk->owner);
110}
111
112int clk_enable(struct clk *clk)
113{
114 if (IS_ERR(clk) || clk == NULL)
115 return -EINVAL;
116
117 clk_enable(clk->parent);
118
119 mutex_lock(&clocks_mutex);
120
121 if ((clk->usage++) == 0)
122 (clk->enable)(clk, 1);
123
124 mutex_unlock(&clocks_mutex);
125 return 0;
126}
127
128void clk_disable(struct clk *clk)
129{
130 if (IS_ERR(clk) || clk == NULL)
131 return;
132
133 mutex_lock(&clocks_mutex);
134
135 if ((--clk->usage) == 0)
136 (clk->enable)(clk, 0);
137
138 mutex_unlock(&clocks_mutex);
139 clk_disable(clk->parent);
140}
141
142
143unsigned long clk_get_rate(struct clk *clk)
144{
145 if (IS_ERR(clk))
146 return 0;
147
148 if (clk->rate != 0)
149 return clk->rate;
150
151 if (clk->get_rate != NULL)
152 return (clk->get_rate)(clk);
153
154 if (clk->parent != NULL)
155 return clk_get_rate(clk->parent);
156
157 return clk->rate;
158}
159
160long clk_round_rate(struct clk *clk, unsigned long rate)
161{
162 if (!IS_ERR(clk) && clk->round_rate)
163 return (clk->round_rate)(clk, rate);
164
165 return rate;
166}
167
168int clk_set_rate(struct clk *clk, unsigned long rate)
169{
170 int ret;
171
172 if (IS_ERR(clk))
173 return -EINVAL;
174
175 /* We do not default just do a clk->rate = rate as
176 * the clock may have been made this way by choice.
177 */
178
179 WARN_ON(clk->set_rate == NULL);
180
181 if (clk->set_rate == NULL)
182 return -EINVAL;
183
184 mutex_lock(&clocks_mutex);
185 ret = (clk->set_rate)(clk, rate);
186 mutex_unlock(&clocks_mutex);
187
188 return ret;
189}
190
191struct clk *clk_get_parent(struct clk *clk)
192{
193 return clk->parent;
194}
195
196int clk_set_parent(struct clk *clk, struct clk *parent)
197{
198 int ret = 0;
199
200 if (IS_ERR(clk))
201 return -EINVAL;
202
203 mutex_lock(&clocks_mutex);
204
205 if (clk->set_parent)
206 ret = (clk->set_parent)(clk, parent);
207
208 mutex_unlock(&clocks_mutex);
209
210 return ret;
211}
212
213EXPORT_SYMBOL(clk_get);
214EXPORT_SYMBOL(clk_put);
215EXPORT_SYMBOL(clk_enable);
216EXPORT_SYMBOL(clk_disable);
217EXPORT_SYMBOL(clk_get_rate);
218EXPORT_SYMBOL(clk_round_rate);
219EXPORT_SYMBOL(clk_set_rate);
220EXPORT_SYMBOL(clk_get_parent);
221EXPORT_SYMBOL(clk_set_parent);
222
223/* base clocks */
224
225static int clk_default_setrate(struct clk *clk, unsigned long rate)
226{
227 clk->rate = rate;
228 return 0;
229}
230
231struct clk clk_xtal = {
232 .name = "xtal",
233 .id = -1,
234 .rate = 0,
235 .parent = NULL,
236 .ctrlbit = 0,
237};
238
239struct clk clk_mpll = {
240 .name = "mpll",
241 .id = -1,
242 .set_rate = clk_default_setrate,
243};
244
245struct clk clk_upll = {
246 .name = "upll",
247 .id = -1,
248 .parent = NULL,
249 .ctrlbit = 0,
250};
251
252struct clk clk_f = {
253 .name = "fclk",
254 .id = -1,
255 .rate = 0,
256 .parent = &clk_mpll,
257 .ctrlbit = 0,
258 .set_rate = clk_default_setrate,
259};
260
261struct clk clk_h = {
262 .name = "hclk",
263 .id = -1,
264 .rate = 0,
265 .parent = NULL,
266 .ctrlbit = 0,
267 .set_rate = clk_default_setrate,
268};
269
270struct clk clk_p = {
271 .name = "pclk",
272 .id = -1,
273 .rate = 0,
274 .parent = NULL,
275 .ctrlbit = 0,
276 .set_rate = clk_default_setrate,
277};
278
279struct clk clk_usb_bus = {
280 .name = "usb-bus",
281 .id = -1,
282 .rate = 0,
283 .parent = &clk_upll,
284};
285
286/* clocks that could be registered by external code */
287
288static int s3c24xx_dclk_enable(struct clk *clk, int enable)
289{
290 unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
291
292 if (enable)
293 dclkcon |= clk->ctrlbit;
294 else
295 dclkcon &= ~clk->ctrlbit;
296
297 __raw_writel(dclkcon, S3C24XX_DCLKCON);
298
299 return 0;
300}
301
302static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
303{
304 unsigned long dclkcon;
305 unsigned int uclk;
306
307 if (parent == &clk_upll)
308 uclk = 1;
309 else if (parent == &clk_p)
310 uclk = 0;
311 else
312 return -EINVAL;
313
314 clk->parent = parent;
315
316 dclkcon = __raw_readl(S3C24XX_DCLKCON);
317
318 if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
319 if (uclk)
320 dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
321 else
322 dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
323 } else {
324 if (uclk)
325 dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
326 else
327 dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
328 }
329
330 __raw_writel(dclkcon, S3C24XX_DCLKCON);
331
332 return 0;
333}
334
335static unsigned long s3c24xx_calc_div(struct clk *clk, unsigned long rate)
336{
337 unsigned long div;
338
339 if ((rate == 0) || !clk->parent)
340 return 0;
341
342 div = clk_get_rate(clk->parent) / rate;
343 if (div < 2)
344 div = 2;
345 else if (div > 16)
346 div = 16;
347
348 return div;
349}
350
351static unsigned long s3c24xx_round_dclk_rate(struct clk *clk,
352 unsigned long rate)
353{
354 unsigned long div = s3c24xx_calc_div(clk, rate);
355
356 if (div == 0)
357 return 0;
358
359 return clk_get_rate(clk->parent) / div;
360}
361
362static int s3c24xx_set_dclk_rate(struct clk *clk, unsigned long rate)
363{
364 unsigned long mask, data, div = s3c24xx_calc_div(clk, rate);
365
366 if (div == 0)
367 return -EINVAL;
368
369 if (clk == &s3c24xx_dclk0) {
370 mask = S3C2410_DCLKCON_DCLK0_DIV_MASK |
371 S3C2410_DCLKCON_DCLK0_CMP_MASK;
372 data = S3C2410_DCLKCON_DCLK0_DIV(div) |
373 S3C2410_DCLKCON_DCLK0_CMP((div + 1) / 2);
374 } else if (clk == &s3c24xx_dclk1) {
375 mask = S3C2410_DCLKCON_DCLK1_DIV_MASK |
376 S3C2410_DCLKCON_DCLK1_CMP_MASK;
377 data = S3C2410_DCLKCON_DCLK1_DIV(div) |
378 S3C2410_DCLKCON_DCLK1_CMP((div + 1) / 2);
379 } else
380 return -EINVAL;
381
382 clk->rate = clk_get_rate(clk->parent) / div;
383 __raw_writel(((__raw_readl(S3C24XX_DCLKCON) & ~mask) | data),
384 S3C24XX_DCLKCON);
385 return clk->rate;
386}
387
388static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
389{
390 unsigned long mask;
391 unsigned long source;
392
393 /* calculate the MISCCR setting for the clock */
394
395 if (parent == &clk_xtal)
396 source = S3C2410_MISCCR_CLK0_MPLL;
397 else if (parent == &clk_upll)
398 source = S3C2410_MISCCR_CLK0_UPLL;
399 else if (parent == &clk_f)
400 source = S3C2410_MISCCR_CLK0_FCLK;
401 else if (parent == &clk_h)
402 source = S3C2410_MISCCR_CLK0_HCLK;
403 else if (parent == &clk_p)
404 source = S3C2410_MISCCR_CLK0_PCLK;
405 else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
406 source = S3C2410_MISCCR_CLK0_DCLK0;
407 else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
408 source = S3C2410_MISCCR_CLK0_DCLK0;
409 else
410 return -EINVAL;
411
412 clk->parent = parent;
413
414 if (clk == &s3c24xx_clkout0)
415 mask = S3C2410_MISCCR_CLK0_MASK;
416 else {
417 source <<= 4;
418 mask = S3C2410_MISCCR_CLK1_MASK;
419 }
420
421 s3c2410_modify_misccr(mask, source);
422 return 0;
423}
424
425/* external clock definitions */
426
427struct clk s3c24xx_dclk0 = {
428 .name = "dclk0",
429 .id = -1,
430 .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
431 .enable = s3c24xx_dclk_enable,
432 .set_parent = s3c24xx_dclk_setparent,
433 .set_rate = s3c24xx_set_dclk_rate,
434 .round_rate = s3c24xx_round_dclk_rate,
435};
436
437struct clk s3c24xx_dclk1 = {
438 .name = "dclk1",
439 .id = -1,
440 .ctrlbit = S3C2410_DCLKCON_DCLK1EN,
441 .enable = s3c24xx_dclk_enable,
442 .set_parent = s3c24xx_dclk_setparent,
443 .set_rate = s3c24xx_set_dclk_rate,
444 .round_rate = s3c24xx_round_dclk_rate,
445};
446
447struct clk s3c24xx_clkout0 = {
448 .name = "clkout0",
449 .id = -1,
450 .set_parent = s3c24xx_clkout_setparent,
451};
452
453struct clk s3c24xx_clkout1 = {
454 .name = "clkout1",
455 .id = -1,
456 .set_parent = s3c24xx_clkout_setparent,
457};
458
459struct clk s3c24xx_uclk = {
460 .name = "uclk",
461 .id = -1,
462};
463
464/* initialise the clock system */
465
466int s3c24xx_register_clock(struct clk *clk)
467{
468 clk->owner = THIS_MODULE;
469
470 if (clk->enable == NULL)
471 clk->enable = clk_null_enable;
472
473 /* add to the list of available clocks */
474
475 mutex_lock(&clocks_mutex);
476 list_add(&clk->list, &clocks);
477 mutex_unlock(&clocks_mutex);
478
479 return 0;
480}
481
482int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
483{
484 int fails = 0;
485
486 for (; nr_clks > 0; nr_clks--, clks++) {
487 if (s3c24xx_register_clock(*clks) < 0)
488 fails++;
489 }
490
491 return fails;
492}
493 45
494/* initalise all the clocks */ 46/* initalise all the clocks */
495 47
496int __init s3c24xx_setup_clocks(unsigned long xtal, 48void __init_or_cpufreq s3c24xx_setup_clocks(unsigned long fclk,
497 unsigned long fclk, 49 unsigned long hclk,
498 unsigned long hclk, 50 unsigned long pclk)
499 unsigned long pclk)
500{ 51{
501 printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n"); 52 clk_upll.rate = s3c24xx_get_pll(__raw_readl(S3C2410_UPLLCON),
502 53 clk_xtal.rate);
503 /* initialise the main system clocks */
504
505 clk_xtal.rate = xtal;
506 clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal);
507 54
508 clk_mpll.rate = fclk; 55 clk_mpll.rate = fclk;
509 clk_h.rate = hclk; 56 clk_h.rate = hclk;
510 clk_p.rate = pclk; 57 clk_p.rate = pclk;
511 clk_f.rate = fclk; 58 clk_f.rate = fclk;
512
513 /* assume uart clocks are correctly setup */
514
515 /* register our clocks */
516
517 if (s3c24xx_register_clock(&clk_xtal) < 0)
518 printk(KERN_ERR "failed to register master xtal\n");
519
520 if (s3c24xx_register_clock(&clk_mpll) < 0)
521 printk(KERN_ERR "failed to register mpll clock\n");
522
523 if (s3c24xx_register_clock(&clk_upll) < 0)
524 printk(KERN_ERR "failed to register upll clock\n");
525
526 if (s3c24xx_register_clock(&clk_f) < 0)
527 printk(KERN_ERR "failed to register cpu fclk\n");
528
529 if (s3c24xx_register_clock(&clk_h) < 0)
530 printk(KERN_ERR "failed to register cpu hclk\n");
531
532 if (s3c24xx_register_clock(&clk_p) < 0)
533 printk(KERN_ERR "failed to register cpu pclk\n");
534
535 return 0;
536} 59}
diff --git a/arch/arm/plat-s3c24xx/cpu.c b/arch/arm/plat-s3c24xx/cpu.c
index 22a329513c0f..7a0f494c93b6 100644
--- a/arch/arm/plat-s3c24xx/cpu.c
+++ b/arch/arm/plat-s3c24xx/cpu.c
@@ -55,16 +55,6 @@
55#include <plat/s3c2442.h> 55#include <plat/s3c2442.h>
56#include <plat/s3c2443.h> 56#include <plat/s3c2443.h>
57 57
58struct cpu_table {
59 unsigned long idcode;
60 unsigned long idmask;
61 void (*map_io)(struct map_desc *mach_desc, int size);
62 void (*init_uarts)(struct s3c2410_uartcfg *cfg, int no);
63 void (*init_clocks)(int xtal);
64 int (*init)(void);
65 const char *name;
66};
67
68/* table of supported CPUs */ 58/* table of supported CPUs */
69 59
70static const char name_s3c2400[] = "S3C2400"; 60static const char name_s3c2400[] = "S3C2400";
@@ -169,23 +159,7 @@ static struct map_desc s3c_iodesc[] __initdata = {
169 IODESC_ENT(UART) 159 IODESC_ENT(UART)
170}; 160};
171 161
172static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode) 162/* read cpu identificaiton code */
173{
174 struct cpu_table *tab;
175 int count;
176
177 tab = cpu_ids;
178 for (count = 0; count < ARRAY_SIZE(cpu_ids); count++, tab++) {
179 if ((idcode & tab->idmask) == tab->idcode)
180 return tab;
181 }
182
183 return NULL;
184}
185
186/* cpu information */
187
188static struct cpu_table *cpu;
189 163
190static unsigned long s3c24xx_read_idcode_v5(void) 164static unsigned long s3c24xx_read_idcode_v5(void)
191{ 165{
@@ -231,6 +205,7 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
231 unsigned long idcode = 0x0; 205 unsigned long idcode = 0x0;
232 206
233 /* initialise the io descriptors we need for initialisation */ 207 /* initialise the io descriptors we need for initialisation */
208 iotable_init(mach_desc, size);
234 iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); 209 iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
235 210
236 if (cpu_architecture() >= CPU_ARCH_ARMv5) { 211 if (cpu_architecture() >= CPU_ARCH_ARMv5) {
@@ -239,117 +214,7 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
239 idcode = s3c24xx_read_idcode_v4(); 214 idcode = s3c24xx_read_idcode_v4();
240 } 215 }
241 216
242 cpu = s3c_lookup_cpu(idcode);
243
244 if (cpu == NULL) {
245 printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode);
246 panic("Unknown S3C24XX CPU");
247 }
248
249 printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode);
250
251 if (cpu->map_io == NULL || cpu->init == NULL) {
252 printk(KERN_ERR "CPU %s support not enabled\n", cpu->name);
253 panic("Unsupported S3C24XX CPU");
254 }
255
256 arm_pm_restart = s3c24xx_pm_restart; 217 arm_pm_restart = s3c24xx_pm_restart;
257 218
258 (cpu->map_io)(mach_desc, size); 219 s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids));
259}
260
261/* s3c24xx_init_clocks
262 *
263 * Initialise the clock subsystem and associated information from the
264 * given master crystal value.
265 *
266 * xtal = 0 -> use default PLL crystal value (normally 12MHz)
267 * != 0 -> PLL crystal value in Hz
268*/
269
270void __init s3c24xx_init_clocks(int xtal)
271{
272 if (xtal == 0)
273 xtal = 12*1000*1000;
274
275 if (cpu == NULL)
276 panic("s3c24xx_init_clocks: no cpu setup?\n");
277
278 if (cpu->init_clocks == NULL)
279 panic("s3c24xx_init_clocks: cpu has no clock init\n");
280 else
281 (cpu->init_clocks)(xtal);
282}
283
284/* uart management */
285
286static int nr_uarts __initdata = 0;
287
288static struct s3c2410_uartcfg uart_cfgs[3];
289
290/* s3c24xx_init_uartdevs
291 *
292 * copy the specified platform data and configuration into our central
293 * set of devices, before the data is thrown away after the init process.
294 *
295 * This also fills in the array passed to the serial driver for the
296 * early initialisation of the console.
297*/
298
299void __init s3c24xx_init_uartdevs(char *name,
300 struct s3c24xx_uart_resources *res,
301 struct s3c2410_uartcfg *cfg, int no)
302{
303 struct platform_device *platdev;
304 struct s3c2410_uartcfg *cfgptr = uart_cfgs;
305 struct s3c24xx_uart_resources *resp;
306 int uart;
307
308 memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);
309
310 for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
311 platdev = s3c24xx_uart_src[cfgptr->hwport];
312
313 resp = res + cfgptr->hwport;
314
315 s3c24xx_uart_devs[uart] = platdev;
316
317 platdev->name = name;
318 platdev->resource = resp->resources;
319 platdev->num_resources = resp->nr_resources;
320
321 platdev->dev.platform_data = cfgptr;
322 }
323
324 nr_uarts = no;
325} 220}
326
327void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)
328{
329 if (cpu == NULL)
330 return;
331
332 if (cpu->init_uarts == NULL) {
333 printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");
334 } else
335 (cpu->init_uarts)(cfg, no);
336}
337
338static int __init s3c_arch_init(void)
339{
340 int ret;
341
342 // do the correct init for cpu
343
344 if (cpu == NULL)
345 panic("s3c_arch_init: NULL cpu\n");
346
347 ret = (cpu->init)();
348 if (ret != 0)
349 return ret;
350
351 ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts);
352 return ret;
353}
354
355arch_initcall(s3c_arch_init);
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index adf535aaf43a..6a33dbc494f4 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -372,12 +372,20 @@ static struct resource s3c_adc_resource[] = {
372}; 372};
373 373
374struct platform_device s3c_device_adc = { 374struct platform_device s3c_device_adc = {
375 .name = "s3c2410-adc", 375 .name = "s3c24xx-adc",
376 .id = -1, 376 .id = -1,
377 .num_resources = ARRAY_SIZE(s3c_adc_resource), 377 .num_resources = ARRAY_SIZE(s3c_adc_resource),
378 .resource = s3c_adc_resource, 378 .resource = s3c_adc_resource,
379}; 379};
380 380
381/* HWMON */
382
383struct platform_device s3c_device_hwmon = {
384 .name = "s3c24xx-hwmon",
385 .id = -1,
386 .dev.parent = &s3c_device_adc.dev,
387};
388
381/* SDI */ 389/* SDI */
382 390
383static struct resource s3c_sdi_resource[] = { 391static struct resource s3c_sdi_resource[] = {
diff --git a/arch/arm/plat-s3c24xx/gpiolib.c b/arch/arm/plat-s3c24xx/gpiolib.c
index 3caec6bad3eb..b07c2d0dd533 100644
--- a/arch/arm/plat-s3c24xx/gpiolib.c
+++ b/arch/arm/plat-s3c24xx/gpiolib.c
@@ -161,8 +161,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
161 .ngpio = 24, 161 .ngpio = 24,
162 .direction_input = s3c24xx_gpiolib_banka_input, 162 .direction_input = s3c24xx_gpiolib_banka_input,
163 .direction_output = s3c24xx_gpiolib_banka_output, 163 .direction_output = s3c24xx_gpiolib_banka_output,
164 .set = s3c24xx_gpiolib_set,
165 .get = s3c24xx_gpiolib_get,
166 }, 164 },
167 }, 165 },
168 [1] = { 166 [1] = {
@@ -172,10 +170,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
172 .owner = THIS_MODULE, 170 .owner = THIS_MODULE,
173 .label = "GPIOB", 171 .label = "GPIOB",
174 .ngpio = 16, 172 .ngpio = 16,
175 .direction_input = s3c24xx_gpiolib_input,
176 .direction_output = s3c24xx_gpiolib_output,
177 .set = s3c24xx_gpiolib_set,
178 .get = s3c24xx_gpiolib_get,
179 }, 173 },
180 }, 174 },
181 [2] = { 175 [2] = {
@@ -185,10 +179,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
185 .owner = THIS_MODULE, 179 .owner = THIS_MODULE,
186 .label = "GPIOC", 180 .label = "GPIOC",
187 .ngpio = 16, 181 .ngpio = 16,
188 .direction_input = s3c24xx_gpiolib_input,
189 .direction_output = s3c24xx_gpiolib_output,
190 .set = s3c24xx_gpiolib_set,
191 .get = s3c24xx_gpiolib_get,
192 }, 182 },
193 }, 183 },
194 [3] = { 184 [3] = {
@@ -198,10 +188,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
198 .owner = THIS_MODULE, 188 .owner = THIS_MODULE,
199 .label = "GPIOD", 189 .label = "GPIOD",
200 .ngpio = 16, 190 .ngpio = 16,
201 .direction_input = s3c24xx_gpiolib_input,
202 .direction_output = s3c24xx_gpiolib_output,
203 .set = s3c24xx_gpiolib_set,
204 .get = s3c24xx_gpiolib_get,
205 }, 191 },
206 }, 192 },
207 [4] = { 193 [4] = {
@@ -211,10 +197,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
211 .label = "GPIOE", 197 .label = "GPIOE",
212 .owner = THIS_MODULE, 198 .owner = THIS_MODULE,
213 .ngpio = 16, 199 .ngpio = 16,
214 .direction_input = s3c24xx_gpiolib_input,
215 .direction_output = s3c24xx_gpiolib_output,
216 .set = s3c24xx_gpiolib_set,
217 .get = s3c24xx_gpiolib_get,
218 }, 200 },
219 }, 201 },
220 [5] = { 202 [5] = {
@@ -224,10 +206,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
224 .owner = THIS_MODULE, 206 .owner = THIS_MODULE,
225 .label = "GPIOF", 207 .label = "GPIOF",
226 .ngpio = 8, 208 .ngpio = 8,
227 .direction_input = s3c24xx_gpiolib_input,
228 .direction_output = s3c24xx_gpiolib_output,
229 .set = s3c24xx_gpiolib_set,
230 .get = s3c24xx_gpiolib_get,
231 }, 209 },
232 }, 210 },
233 [6] = { 211 [6] = {
@@ -237,21 +215,38 @@ static struct s3c24xx_gpio_chip gpios[] = {
237 .owner = THIS_MODULE, 215 .owner = THIS_MODULE,
238 .label = "GPIOG", 216 .label = "GPIOG",
239 .ngpio = 10, 217 .ngpio = 10,
240 .direction_input = s3c24xx_gpiolib_input,
241 .direction_output = s3c24xx_gpiolib_output,
242 .set = s3c24xx_gpiolib_set,
243 .get = s3c24xx_gpiolib_get,
244 }, 218 },
245 }, 219 },
246}; 220};
247 221
222static __init void s3c24xx_gpiolib_add(struct s3c24xx_gpio_chip *chip)
223{
224 struct gpio_chip *gc = &chip->chip;
225
226 BUG_ON(!chip->base);
227 BUG_ON(!gc->label);
228 BUG_ON(!gc->ngpio);
229
230 if (!gc->direction_input)
231 gc->direction_input = s3c24xx_gpiolib_input;
232 if (!gc->direction_output)
233 gc->direction_output = s3c24xx_gpiolib_output;
234 if (!gc->set)
235 gc->set = s3c24xx_gpiolib_set;
236 if (!gc->get)
237 gc->get = s3c24xx_gpiolib_get;
238
239 /* gpiochip_add() prints own failure message on error. */
240 gpiochip_add(gc);
241}
242
248static __init int s3c24xx_gpiolib_init(void) 243static __init int s3c24xx_gpiolib_init(void)
249{ 244{
250 struct s3c24xx_gpio_chip *chip = gpios; 245 struct s3c24xx_gpio_chip *chip = gpios;
251 int gpn; 246 int gpn;
252 247
253 for (gpn = 0; gpn < ARRAY_SIZE(gpios); gpn++, chip++) 248 for (gpn = 0; gpn < ARRAY_SIZE(gpios); gpn++, chip++)
254 gpiochip_add(&chip->chip); 249 s3c24xx_gpiolib_add(chip);
255 250
256 return 0; 251 return 0;
257} 252}
diff --git a/arch/arm/plat-s3c24xx/include/plat/clock.h b/arch/arm/plat-s3c24xx/include/plat/clock.h
deleted file mode 100644
index 235b753cd877..000000000000
--- a/arch/arm/plat-s3c24xx/include/plat/clock.h
+++ /dev/null
@@ -1,64 +0,0 @@
1/* linux/include/asm-arm/plat-s3c24xx/clock.h
2 * linux/arch/arm/mach-s3c2410/clock.h
3 *
4 * Copyright (c) 2004-2005 Simtec Electronics
5 * http://www.simtec.co.uk/products/SWLINUX/
6 * Written by Ben Dooks, <ben@simtec.co.uk>
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 version 2 as
10 * published by the Free Software Foundation.
11*/
12
13struct clk {
14 struct list_head list;
15 struct module *owner;
16 struct clk *parent;
17 const char *name;
18 int id;
19 int usage;
20 unsigned long rate;
21 unsigned long ctrlbit;
22
23 int (*enable)(struct clk *, int enable);
24 int (*set_rate)(struct clk *c, unsigned long rate);
25 unsigned long (*get_rate)(struct clk *c);
26 unsigned long (*round_rate)(struct clk *c, unsigned long rate);
27 int (*set_parent)(struct clk *c, struct clk *parent);
28};
29
30/* other clocks which may be registered by board support */
31
32extern struct clk s3c24xx_dclk0;
33extern struct clk s3c24xx_dclk1;
34extern struct clk s3c24xx_clkout0;
35extern struct clk s3c24xx_clkout1;
36extern struct clk s3c24xx_uclk;
37
38extern struct clk clk_usb_bus;
39
40/* core clock support */
41
42extern struct clk clk_f;
43extern struct clk clk_h;
44extern struct clk clk_p;
45extern struct clk clk_mpll;
46extern struct clk clk_upll;
47extern struct clk clk_xtal;
48
49/* exports for arch/arm/mach-s3c2410
50 *
51 * Please DO NOT use these outside of arch/arm/mach-s3c2410
52*/
53
54extern struct mutex clocks_mutex;
55
56extern int s3c2410_clkcon_enable(struct clk *clk, int enable);
57
58extern int s3c24xx_register_clock(struct clk *clk);
59extern int s3c24xx_register_clocks(struct clk **clk, int nr_clks);
60
61extern int s3c24xx_setup_clocks(unsigned long xtal,
62 unsigned long fclk,
63 unsigned long hclk,
64 unsigned long pclk);
diff --git a/arch/arm/plat-s3c24xx/include/plat/cpu.h b/arch/arm/plat-s3c24xx/include/plat/cpu.h
deleted file mode 100644
index 23e420e8bd5b..000000000000
--- a/arch/arm/plat-s3c24xx/include/plat/cpu.h
+++ /dev/null
@@ -1,54 +0,0 @@
1/* linux/include/asm-arm/plat-s3c24xx/cpu.h
2 *
3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Header file for S3C24XX CPU 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 version 2 as
10 * published by the Free Software Foundation.
11*/
12
13/* todo - fix when rmk changes iodescs to use `void __iomem *` */
14
15#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE }
16
17#ifndef MHZ
18#define MHZ (1000*1000)
19#endif
20
21#define print_mhz(m) ((m) / MHZ), ((m / 1000) % 1000)
22
23/* forward declaration */
24struct s3c24xx_uart_resources;
25struct platform_device;
26struct s3c2410_uartcfg;
27struct map_desc;
28
29/* core initialisation functions */
30
31extern void s3c24xx_init_irq(void);
32
33extern void s3c24xx_init_io(struct map_desc *mach_desc, int size);
34
35extern void s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no);
36
37extern void s3c24xx_init_clocks(int xtal);
38
39extern void s3c24xx_init_uartdevs(char *name,
40 struct s3c24xx_uart_resources *res,
41 struct s3c2410_uartcfg *cfg, int no);
42
43/* timer for 2410/2440 */
44
45struct sys_timer;
46extern struct sys_timer s3c24xx_timer;
47
48/* system device classes */
49
50extern struct sysdev_class s3c2410_sysclass;
51extern struct sysdev_class s3c2412_sysclass;
52extern struct sysdev_class s3c2440_sysclass;
53extern struct sysdev_class s3c2442_sysclass;
54extern struct sysdev_class s3c2443_sysclass;
diff --git a/arch/arm/plat-s3c24xx/include/plat/devs.h b/arch/arm/plat-s3c24xx/include/plat/devs.h
deleted file mode 100644
index badaac9d64a8..000000000000
--- a/arch/arm/plat-s3c24xx/include/plat/devs.h
+++ /dev/null
@@ -1,49 +0,0 @@
1/* linux/include/asm-arm/plat-s3c24xx/devs.h
2 *
3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Header file for s3c2410 standard platform devices
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 version 2 as
10 * published by the Free Software Foundation.
11*/
12#include <linux/platform_device.h>
13
14struct s3c24xx_uart_resources {
15 struct resource *resources;
16 unsigned long nr_resources;
17};
18
19extern struct s3c24xx_uart_resources s3c2410_uart_resources[];
20
21extern struct platform_device *s3c24xx_uart_devs[];
22extern struct platform_device *s3c24xx_uart_src[];
23
24extern struct platform_device s3c_device_timer[];
25
26extern struct platform_device s3c_device_usb;
27extern struct platform_device s3c_device_lcd;
28extern struct platform_device s3c_device_wdt;
29extern struct platform_device s3c_device_i2c;
30extern struct platform_device s3c_device_iis;
31extern struct platform_device s3c_device_rtc;
32extern struct platform_device s3c_device_adc;
33extern struct platform_device s3c_device_sdi;
34extern struct platform_device s3c_device_hsmmc;
35
36extern struct platform_device s3c_device_spi0;
37extern struct platform_device s3c_device_spi1;
38
39extern struct platform_device s3c_device_nand;
40
41extern struct platform_device s3c_device_usbgadget;
42
43/* s3c2440 specific devices */
44
45#ifdef CONFIG_CPU_S3C2440
46
47extern struct platform_device s3c_device_camif;
48
49#endif
diff --git a/arch/arm/plat-s3c24xx/include/plat/pll.h b/arch/arm/plat-s3c24xx/include/plat/pll.h
new file mode 100644
index 000000000000..7ea8bffa7a9c
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/include/plat/pll.h
@@ -0,0 +1,37 @@
1/* linux/arch/arm/plat-s3c24xx/include/plat/pll.h
2 *
3 * Copyright 2008 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 * http://armlinux.simtec.co.uk/
6 *
7 * S3C24xx - common pll registers and code
8 */
9
10#define S3C24XX_PLLCON_MDIVSHIFT 12
11#define S3C24XX_PLLCON_PDIVSHIFT 4
12#define S3C24XX_PLLCON_SDIVSHIFT 0
13#define S3C24XX_PLLCON_MDIVMASK ((1<<(1+(19-12)))-1)
14#define S3C24XX_PLLCON_PDIVMASK ((1<<5)-1)
15#define S3C24XX_PLLCON_SDIVMASK 3
16
17#include <asm/div64.h>
18
19static inline unsigned int
20s3c24xx_get_pll(unsigned int pllval, unsigned int baseclk)
21{
22 unsigned int mdiv, pdiv, sdiv;
23 uint64_t fvco;
24
25 mdiv = pllval >> S3C24XX_PLLCON_MDIVSHIFT;
26 pdiv = pllval >> S3C24XX_PLLCON_PDIVSHIFT;
27 sdiv = pllval >> S3C24XX_PLLCON_SDIVSHIFT;
28
29 mdiv &= S3C24XX_PLLCON_MDIVMASK;
30 pdiv &= S3C24XX_PLLCON_PDIVMASK;
31 sdiv &= S3C24XX_PLLCON_SDIVMASK;
32
33 fvco = (uint64_t)baseclk * (mdiv + 8);
34 do_div(fvco, (pdiv + 2) << sdiv);
35
36 return (unsigned int)fvco;
37}
diff --git a/arch/arm/plat-s3c24xx/include/plat/s3c2400.h b/arch/arm/plat-s3c24xx/include/plat/s3c2400.h
index 3a5a16821af8..b3feaea5c70b 100644
--- a/arch/arm/plat-s3c24xx/include/plat/s3c2400.h
+++ b/arch/arm/plat-s3c24xx/include/plat/s3c2400.h
@@ -17,7 +17,7 @@
17 17
18extern int s3c2400_init(void); 18extern int s3c2400_init(void);
19 19
20extern void s3c2400_map_io(struct map_desc *mach_desc, int size); 20extern void s3c2400_map_io(void);
21 21
22extern void s3c2400_init_uarts(struct s3c2410_uartcfg *cfg, int no); 22extern void s3c2400_init_uarts(struct s3c2410_uartcfg *cfg, int no);
23 23
diff --git a/arch/arm/plat-s3c24xx/include/plat/s3c2410.h b/arch/arm/plat-s3c24xx/include/plat/s3c2410.h
index 3cd1ec677b3f..a9ac9e29759e 100644
--- a/arch/arm/plat-s3c24xx/include/plat/s3c2410.h
+++ b/arch/arm/plat-s3c24xx/include/plat/s3c2410.h
@@ -15,7 +15,7 @@
15 15
16extern int s3c2410_init(void); 16extern int s3c2410_init(void);
17 17
18extern void s3c2410_map_io(struct map_desc *mach_desc, int size); 18extern void s3c2410_map_io(void);
19 19
20extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no); 20extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no);
21 21
diff --git a/arch/arm/plat-s3c24xx/include/plat/s3c2412.h b/arch/arm/plat-s3c24xx/include/plat/s3c2412.h
index 3ec97685e781..bb15d3b68be5 100644
--- a/arch/arm/plat-s3c24xx/include/plat/s3c2412.h
+++ b/arch/arm/plat-s3c24xx/include/plat/s3c2412.h
@@ -14,7 +14,7 @@
14 14
15extern int s3c2412_init(void); 15extern int s3c2412_init(void);
16 16
17extern void s3c2412_map_io(struct map_desc *mach_desc, int size); 17extern void s3c2412_map_io(void);
18 18
19extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no); 19extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no);
20 20
diff --git a/arch/arm/plat-s3c24xx/include/plat/s3c2443.h b/arch/arm/plat-s3c24xx/include/plat/s3c2443.h
index 11d83b5c84e6..815b107ed890 100644
--- a/arch/arm/plat-s3c24xx/include/plat/s3c2443.h
+++ b/arch/arm/plat-s3c24xx/include/plat/s3c2443.h
@@ -16,7 +16,7 @@ struct s3c2410_uartcfg;
16 16
17extern int s3c2443_init(void); 17extern int s3c2443_init(void);
18 18
19extern void s3c2443_map_io(struct map_desc *mach_desc, int size); 19extern void s3c2443_map_io(void);
20 20
21extern void s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no); 21extern void s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no);
22 22
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index 963f7a4f26f2..0192ecdc1442 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -62,6 +62,7 @@
62 62
63#include <asm/mach/irq.h> 63#include <asm/mach/irq.h>
64 64
65#include <plat/regs-irqtype.h>
65#include <mach/regs-irq.h> 66#include <mach/regs-irq.h>
66#include <mach/regs-gpio.h> 67#include <mach/regs-gpio.h>
67 68
diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c
index 8efb57ad5019..bc37cf49f973 100644
--- a/arch/arm/plat-s3c24xx/pm.c
+++ b/arch/arm/plat-s3c24xx/pm.c
@@ -76,11 +76,13 @@ static struct sleep_save core_save[] = {
76 SAVE_ITEM(S3C2410_BANKCON4), 76 SAVE_ITEM(S3C2410_BANKCON4),
77 SAVE_ITEM(S3C2410_BANKCON5), 77 SAVE_ITEM(S3C2410_BANKCON5),
78 78
79#ifndef CONFIG_CPU_FREQ
79 SAVE_ITEM(S3C2410_CLKDIVN), 80 SAVE_ITEM(S3C2410_CLKDIVN),
80 SAVE_ITEM(S3C2410_MPLLCON), 81 SAVE_ITEM(S3C2410_MPLLCON),
82 SAVE_ITEM(S3C2410_REFRESH),
83#endif
81 SAVE_ITEM(S3C2410_UPLLCON), 84 SAVE_ITEM(S3C2410_UPLLCON),
82 SAVE_ITEM(S3C2410_CLKSLOW), 85 SAVE_ITEM(S3C2410_CLKSLOW),
83 SAVE_ITEM(S3C2410_REFRESH),
84}; 86};
85 87
86static struct gpio_sleep { 88static struct gpio_sleep {
diff --git a/arch/arm/plat-s3c24xx/pwm-clock.c b/arch/arm/plat-s3c24xx/pwm-clock.c
deleted file mode 100644
index 3fad68a1e6bc..000000000000
--- a/arch/arm/plat-s3c24xx/pwm-clock.c
+++ /dev/null
@@ -1,437 +0,0 @@
1/* linux/arch/arm/plat-s3c24xx/pwm-clock.c
2 *
3 * Copyright (c) 2007 Simtec Electronics
4 * Copyright (c) 2007, 2008 Ben Dooks
5 * Ben Dooks <ben-linux@fluff.org>
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
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/list.h>
16#include <linux/errno.h>
17#include <linux/clk.h>
18#include <linux/err.h>
19#include <linux/io.h>
20
21#include <mach/hardware.h>
22#include <asm/irq.h>
23
24#include <mach/regs-clock.h>
25#include <mach/regs-gpio.h>
26
27#include <plat/clock.h>
28#include <plat/cpu.h>
29
30#include <plat/regs-timer.h>
31
32/* Each of the timers 0 through 5 go through the following
33 * clock tree, with the inputs depending on the timers.
34 *
35 * pclk ---- [ prescaler 0 ] -+---> timer 0
36 * +---> timer 1
37 *
38 * pclk ---- [ prescaler 1 ] -+---> timer 2
39 * +---> timer 3
40 * \---> timer 4
41 *
42 * Which are fed into the timers as so:
43 *
44 * prescaled 0 ---- [ div 2,4,8,16 ] ---\
45 * [mux] -> timer 0
46 * tclk 0 ------------------------------/
47 *
48 * prescaled 0 ---- [ div 2,4,8,16 ] ---\
49 * [mux] -> timer 1
50 * tclk 0 ------------------------------/
51 *
52 *
53 * prescaled 1 ---- [ div 2,4,8,16 ] ---\
54 * [mux] -> timer 2
55 * tclk 1 ------------------------------/
56 *
57 * prescaled 1 ---- [ div 2,4,8,16 ] ---\
58 * [mux] -> timer 3
59 * tclk 1 ------------------------------/
60 *
61 * prescaled 1 ---- [ div 2,4,8, 16 ] --\
62 * [mux] -> timer 4
63 * tclk 1 ------------------------------/
64 *
65 * Since the mux and the divider are tied together in the
66 * same register space, it is impossible to set the parent
67 * and the rate at the same time. To avoid this, we add an
68 * intermediate 'prescaled-and-divided' clock to select
69 * as the parent for the timer input clock called tdiv.
70 *
71 * prescaled clk --> pwm-tdiv ---\
72 * [ mux ] --> timer X
73 * tclk -------------------------/
74*/
75
76static unsigned long clk_pwm_scaler_getrate(struct clk *clk)
77{
78 unsigned long tcfg0 = __raw_readl(S3C2410_TCFG0);
79
80 if (clk->id == 1) {
81 tcfg0 &= S3C2410_TCFG_PRESCALER1_MASK;
82 tcfg0 >>= S3C2410_TCFG_PRESCALER1_SHIFT;
83 } else {
84 tcfg0 &= S3C2410_TCFG_PRESCALER0_MASK;
85 }
86
87 return clk_get_rate(clk->parent) / (tcfg0 + 1);
88}
89
90/* TODO - add set rate calls. */
91
92static struct clk clk_timer_scaler[] = {
93 [0] = {
94 .name = "pwm-scaler0",
95 .id = -1,
96 .get_rate = clk_pwm_scaler_getrate,
97 },
98 [1] = {
99 .name = "pwm-scaler1",
100 .id = -1,
101 .get_rate = clk_pwm_scaler_getrate,
102 },
103};
104
105static struct clk clk_timer_tclk[] = {
106 [0] = {
107 .name = "pwm-tclk0",
108 .id = -1,
109 },
110 [1] = {
111 .name = "pwm-tclk1",
112 .id = -1,
113 },
114};
115
116struct pwm_tdiv_clk {
117 struct clk clk;
118 unsigned int divisor;
119};
120
121static inline struct pwm_tdiv_clk *to_tdiv(struct clk *clk)
122{
123 return container_of(clk, struct pwm_tdiv_clk, clk);
124}
125
126static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
127{
128 return 1 << (1 + tcfg1);
129}
130
131static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk)
132{
133 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
134 unsigned int divisor;
135
136 tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
137 tcfg1 &= S3C2410_TCFG1_MUX_MASK;
138
139 if (tcfg1 == S3C2410_TCFG1_MUX_TCLK)
140 divisor = to_tdiv(clk)->divisor;
141 else
142 divisor = tcfg_to_divisor(tcfg1);
143
144 return clk_get_rate(clk->parent) / divisor;
145}
146
147static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk,
148 unsigned long rate)
149{
150 unsigned long parent_rate;
151 unsigned long divisor;
152
153 parent_rate = clk_get_rate(clk->parent);
154 divisor = parent_rate / rate;
155
156 if (divisor <= 2)
157 divisor = 2;
158 else if (divisor <= 4)
159 divisor = 4;
160 else if (divisor <= 8)
161 divisor = 8;
162 else
163 divisor = 16;
164
165 return parent_rate / divisor;
166}
167
168static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk)
169{
170 unsigned long bits;
171
172 switch (divclk->divisor) {
173 case 2:
174 bits = S3C2410_TCFG1_MUX_DIV2;
175 break;
176 case 4:
177 bits = S3C2410_TCFG1_MUX_DIV4;
178 break;
179 case 8:
180 bits = S3C2410_TCFG1_MUX_DIV8;
181 break;
182 case 16:
183 default:
184 bits = S3C2410_TCFG1_MUX_DIV16;
185 break;
186 }
187
188 return bits;
189}
190
191static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk)
192{
193 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
194 unsigned long bits = clk_pwm_tdiv_bits(divclk);
195 unsigned long flags;
196 unsigned long shift = S3C2410_TCFG1_SHIFT(divclk->clk.id);
197
198 local_irq_save(flags);
199
200 tcfg1 = __raw_readl(S3C2410_TCFG1);
201 tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
202 tcfg1 |= bits << shift;
203 __raw_writel(tcfg1, S3C2410_TCFG1);
204
205 local_irq_restore(flags);
206}
207
208static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate)
209{
210 struct pwm_tdiv_clk *divclk = to_tdiv(clk);
211 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
212 unsigned long parent_rate = clk_get_rate(clk->parent);
213 unsigned long divisor;
214
215 tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
216 tcfg1 &= S3C2410_TCFG1_MUX_MASK;
217
218 rate = clk_round_rate(clk, rate);
219 divisor = parent_rate / rate;
220
221 if (divisor > 16)
222 return -EINVAL;
223
224 divclk->divisor = divisor;
225
226 /* Update the current MUX settings if we are currently
227 * selected as the clock source for this clock. */
228
229 if (tcfg1 != S3C2410_TCFG1_MUX_TCLK)
230 clk_pwm_tdiv_update(divclk);
231
232 return 0;
233}
234
235static struct pwm_tdiv_clk clk_timer_tdiv[] = {
236 [0] = {
237 .clk = {
238 .name = "pwm-tdiv",
239 .parent = &clk_timer_scaler[0],
240 .get_rate = clk_pwm_tdiv_get_rate,
241 .set_rate = clk_pwm_tdiv_set_rate,
242 .round_rate = clk_pwm_tdiv_round_rate,
243 },
244 },
245 [1] = {
246 .clk = {
247 .name = "pwm-tdiv",
248 .parent = &clk_timer_scaler[0],
249 .get_rate = clk_pwm_tdiv_get_rate,
250 .set_rate = clk_pwm_tdiv_set_rate,
251 .round_rate = clk_pwm_tdiv_round_rate,
252 }
253 },
254 [2] = {
255 .clk = {
256 .name = "pwm-tdiv",
257 .parent = &clk_timer_scaler[1],
258 .get_rate = clk_pwm_tdiv_get_rate,
259 .set_rate = clk_pwm_tdiv_set_rate,
260 .round_rate = clk_pwm_tdiv_round_rate,
261 },
262 },
263 [3] = {
264 .clk = {
265 .name = "pwm-tdiv",
266 .parent = &clk_timer_scaler[1],
267 .get_rate = clk_pwm_tdiv_get_rate,
268 .set_rate = clk_pwm_tdiv_set_rate,
269 .round_rate = clk_pwm_tdiv_round_rate,
270 },
271 },
272 [4] = {
273 .clk = {
274 .name = "pwm-tdiv",
275 .parent = &clk_timer_scaler[1],
276 .get_rate = clk_pwm_tdiv_get_rate,
277 .set_rate = clk_pwm_tdiv_set_rate,
278 .round_rate = clk_pwm_tdiv_round_rate,
279 },
280 },
281};
282
283static int __init clk_pwm_tdiv_register(unsigned int id)
284{
285 struct pwm_tdiv_clk *divclk = &clk_timer_tdiv[id];
286 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
287
288 tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
289 tcfg1 &= S3C2410_TCFG1_MUX_MASK;
290
291 divclk->clk.id = id;
292 divclk->divisor = tcfg_to_divisor(tcfg1);
293
294 return s3c24xx_register_clock(&divclk->clk);
295}
296
297static inline struct clk *s3c24xx_pwmclk_tclk(unsigned int id)
298{
299 return (id >= 2) ? &clk_timer_tclk[1] : &clk_timer_tclk[0];
300}
301
302static inline struct clk *s3c24xx_pwmclk_tdiv(unsigned int id)
303{
304 return &clk_timer_tdiv[id].clk;
305}
306
307static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent)
308{
309 unsigned int id = clk->id;
310 unsigned long tcfg1;
311 unsigned long flags;
312 unsigned long bits;
313 unsigned long shift = S3C2410_TCFG1_SHIFT(id);
314
315 if (parent == s3c24xx_pwmclk_tclk(id))
316 bits = S3C2410_TCFG1_MUX_TCLK << shift;
317 else if (parent == s3c24xx_pwmclk_tdiv(id))
318 bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift;
319 else
320 return -EINVAL;
321
322 clk->parent = parent;
323
324 local_irq_save(flags);
325
326 tcfg1 = __raw_readl(S3C2410_TCFG1);
327 tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
328 __raw_writel(tcfg1 | bits, S3C2410_TCFG1);
329
330 local_irq_restore(flags);
331
332 return 0;
333}
334
335static struct clk clk_tin[] = {
336 [0] = {
337 .name = "pwm-tin",
338 .id = 0,
339 .set_parent = clk_pwm_tin_set_parent,
340 },
341 [1] = {
342 .name = "pwm-tin",
343 .id = 1,
344 .set_parent = clk_pwm_tin_set_parent,
345 },
346 [2] = {
347 .name = "pwm-tin",
348 .id = 2,
349 .set_parent = clk_pwm_tin_set_parent,
350 },
351 [3] = {
352 .name = "pwm-tin",
353 .id = 3,
354 .set_parent = clk_pwm_tin_set_parent,
355 },
356 [4] = {
357 .name = "pwm-tin",
358 .id = 4,
359 .set_parent = clk_pwm_tin_set_parent,
360 },
361};
362
363static __init int clk_pwm_tin_register(struct clk *pwm)
364{
365 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
366 unsigned int id = pwm->id;
367
368 struct clk *parent;
369 int ret;
370
371 ret = s3c24xx_register_clock(pwm);
372 if (ret < 0)
373 return ret;
374
375 tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
376 tcfg1 &= S3C2410_TCFG1_MUX_MASK;
377
378 if (tcfg1 == S3C2410_TCFG1_MUX_TCLK)
379 parent = s3c24xx_pwmclk_tclk(id);
380 else
381 parent = s3c24xx_pwmclk_tdiv(id);
382
383 return clk_set_parent(pwm, parent);
384}
385
386static __init int s3c24xx_pwmclk_init(void)
387{
388 struct clk *clk_timers;
389 unsigned int clk;
390 int ret;
391
392 clk_timers = clk_get(NULL, "timers");
393 if (IS_ERR(clk_timers)) {
394 printk(KERN_ERR "%s: no parent clock\n", __func__);
395 return -EINVAL;
396 }
397
398 for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++) {
399 clk_timer_scaler[clk].parent = clk_timers;
400 ret = s3c24xx_register_clock(&clk_timer_scaler[clk]);
401 if (ret < 0) {
402 printk(KERN_ERR "error adding pwm scaler%d clock\n", clk);
403 goto err;
404 }
405 }
406
407 for (clk = 0; clk < ARRAY_SIZE(clk_timer_tclk); clk++) {
408 ret = s3c24xx_register_clock(&clk_timer_tclk[clk]);
409 if (ret < 0) {
410 printk(KERN_ERR "error adding pww tclk%d\n", clk);
411 goto err;
412 }
413 }
414
415 for (clk = 0; clk < ARRAY_SIZE(clk_timer_tdiv); clk++) {
416 ret = clk_pwm_tdiv_register(clk);
417 if (ret < 0) {
418 printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk);
419 goto err;
420 }
421 }
422
423 for (clk = 0; clk < ARRAY_SIZE(clk_tin); clk++) {
424 ret = clk_pwm_tin_register(&clk_tin[clk]);
425 if (ret < 0) {
426 printk(KERN_ERR "error adding pwm%d tin clock\n", clk);
427 goto err;
428 }
429 }
430
431 return 0;
432
433 err:
434 return ret;
435}
436
437arch_initcall(s3c24xx_pwmclk_init);
diff --git a/arch/arm/plat-s3c24xx/s3c2410-clock.c b/arch/arm/plat-s3c24xx/s3c2410-clock.c
new file mode 100644
index 000000000000..4e07943c1e29
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/s3c2410-clock.c
@@ -0,0 +1,276 @@
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_disable[] = {
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 clkp = init_clocks_disable;
253 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
254
255 ret = s3c24xx_register_clock(clkp);
256 if (ret < 0) {
257 printk(KERN_ERR "Failed to register clock %s (%d)\n",
258 clkp->name, ret);
259 }
260
261 s3c2410_clkcon_enable(clkp, 0);
262 }
263
264 /* show the clock-slow value */
265
266 xtal = clk_get(NULL, "xtal");
267
268 printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
269 print_mhz(clk_get_rate(xtal) /
270 ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
271 (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
272 (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
273 (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
274
275 return 0;
276}
diff --git a/arch/arm/plat-s3c24xx/s3c244x-clock.c b/arch/arm/plat-s3c24xx/s3c244x-clock.c
index 7c09773ff9fc..dde41f171aff 100644
--- a/arch/arm/plat-s3c24xx/s3c244x-clock.c
+++ b/arch/arm/plat-s3c24xx/s3c244x-clock.c
@@ -31,7 +31,6 @@
31#include <linux/sysdev.h> 31#include <linux/sysdev.h>
32#include <linux/interrupt.h> 32#include <linux/interrupt.h>
33#include <linux/ioport.h> 33#include <linux/ioport.h>
34#include <linux/mutex.h>
35#include <linux/clk.h> 34#include <linux/clk.h>
36#include <linux/io.h> 35#include <linux/io.h>
37 36
@@ -102,13 +101,13 @@ static int s3c244x_clk_add(struct sys_device *sysdev)
102 if (clk_get_rate(clock_upll) > (94 * MHZ)) { 101 if (clk_get_rate(clock_upll) > (94 * MHZ)) {
103 clk_usb_bus.rate = clk_get_rate(clock_upll) / 2; 102 clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
104 103
105 mutex_lock(&clocks_mutex); 104 spin_lock(&clocks_lock);
106 105
107 clkdivn = __raw_readl(S3C2410_CLKDIVN); 106 clkdivn = __raw_readl(S3C2410_CLKDIVN);
108 clkdivn |= S3C2440_CLKDIVN_UCLK; 107 clkdivn |= S3C2440_CLKDIVN_UCLK;
109 __raw_writel(clkdivn, S3C2410_CLKDIVN); 108 __raw_writel(clkdivn, S3C2410_CLKDIVN);
110 109
111 mutex_unlock(&clocks_mutex); 110 spin_unlock(&clocks_lock);
112 } 111 }
113 112
114 return 0; 113 return 0;
diff --git a/arch/arm/plat-s3c24xx/s3c244x.c b/arch/arm/plat-s3c24xx/s3c244x.c
index c0344fac4a94..494368403055 100644
--- a/arch/arm/plat-s3c24xx/s3c244x.c
+++ b/arch/arm/plat-s3c24xx/s3c244x.c
@@ -29,6 +29,8 @@
29#include <mach/hardware.h> 29#include <mach/hardware.h>
30#include <asm/irq.h> 30#include <asm/irq.h>
31 31
32#include <plat/cpu-freq.h>
33
32#include <mach/regs-clock.h> 34#include <mach/regs-clock.h>
33#include <plat/regs-serial.h> 35#include <plat/regs-serial.h>
34#include <mach/regs-gpio.h> 36#include <mach/regs-gpio.h>
@@ -42,6 +44,7 @@
42#include <plat/devs.h> 44#include <plat/devs.h>
43#include <plat/cpu.h> 45#include <plat/cpu.h>
44#include <plat/pm.h> 46#include <plat/pm.h>
47#include <plat/pll.h>
45 48
46static struct map_desc s3c244x_iodesc[] __initdata = { 49static struct map_desc s3c244x_iodesc[] __initdata = {
47 IODESC_ENT(CLKPWR), 50 IODESC_ENT(CLKPWR),
@@ -56,12 +59,11 @@ void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
56 s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no); 59 s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
57} 60}
58 61
59void __init s3c244x_map_io(struct map_desc *mach_desc, int size) 62void __init s3c244x_map_io(void)
60{ 63{
61 /* register our io-tables */ 64 /* register our io-tables */
62 65
63 iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc)); 66 iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
64 iotable_init(mach_desc, size);
65 67
66 /* rename any peripherals used differing from the s3c2410 */ 68 /* rename any peripherals used differing from the s3c2410 */
67 69
@@ -71,17 +73,20 @@ void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
71 s3c_device_usbgadget.name = "s3c2440-usbgadget"; 73 s3c_device_usbgadget.name = "s3c2440-usbgadget";
72} 74}
73 75
74void __init s3c244x_init_clocks(int xtal) 76void __init_or_cpufreq s3c244x_setup_clocks(void)
75{ 77{
78 struct clk *xtal_clk;
76 unsigned long clkdiv; 79 unsigned long clkdiv;
77 unsigned long camdiv; 80 unsigned long camdiv;
81 unsigned long xtal;
78 unsigned long hclk, fclk, pclk; 82 unsigned long hclk, fclk, pclk;
79 int hdiv = 1; 83 int hdiv = 1;
80 84
81 /* now we've got our machine bits initialised, work out what 85 xtal_clk = clk_get(NULL, "xtal");
82 * clocks we've got */ 86 xtal = clk_get_rate(xtal_clk);
87 clk_put(xtal_clk);
83 88
84 fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2; 89 fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
85 90
86 clkdiv = __raw_readl(S3C2410_CLKDIVN); 91 clkdiv = __raw_readl(S3C2410_CLKDIVN);
87 camdiv = __raw_readl(S3C2440_CAMDIVN); 92 camdiv = __raw_readl(S3C2440_CAMDIVN);
@@ -107,18 +112,24 @@ void __init s3c244x_init_clocks(int xtal)
107 } 112 }
108 113
109 hclk = fclk / hdiv; 114 hclk = fclk / hdiv;
110 pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1); 115 pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN) ? 2 : 1);
111 116
112 /* print brief summary of clocks, etc */ 117 /* print brief summary of clocks, etc */
113 118
114 printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", 119 printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
115 print_mhz(fclk), print_mhz(hclk), print_mhz(pclk)); 120 print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
116 121
122 s3c24xx_setup_clocks(fclk, hclk, pclk);
123}
124
125void __init s3c244x_init_clocks(int xtal)
126{
117 /* initialise the clocks here, to allow other things like the 127 /* initialise the clocks here, to allow other things like the
118 * console to use them, and to add new ones after the initialisation 128 * console to use them, and to add new ones after the initialisation
119 */ 129 */
120 130
121 s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); 131 s3c24xx_register_baseclocks(xtal);
132 s3c244x_setup_clocks();
122 s3c2410_baseclk_add(); 133 s3c2410_baseclk_add();
123} 134}
124 135
diff --git a/arch/arm/plat-s3c24xx/s3c244x.h b/arch/arm/plat-s3c24xx/s3c244x.h
index f8ed17676a35..6aab5eaae2b4 100644
--- a/arch/arm/plat-s3c24xx/s3c244x.h
+++ b/arch/arm/plat-s3c24xx/s3c244x.h
@@ -12,7 +12,7 @@
12 12
13#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442) 13#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
14 14
15extern void s3c244x_map_io(struct map_desc *mach_desc, int size); 15extern void s3c244x_map_io(void);
16 16
17extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no); 17extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no);
18 18
diff --git a/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c b/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
new file mode 100644
index 000000000000..8b403cbb53d2
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
@@ -0,0 +1,37 @@
1/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
2 *
3 * Copyright (c) 2008 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 *
7 * S3C24XX SPI - gpio configuration for bus 0 on gpe11,12,13
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License.
12*/
13
14#include <linux/kernel.h>
15
16#include <mach/hardware.h>
17
18#include <mach/spi.h>
19#include <mach/regs-gpio.h>
20
21void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi,
22 int enable)
23{
24 if (enable) {
25 s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_SPICLK0);
26 s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_SPIMOSI0);
27 s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_SPIMISO0);
28 s3c2410_gpio_pullup(S3C2410_GPE11, 0);
29 s3c2410_gpio_pullup(S3C2410_GPE13, 0);
30 } else {
31 s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPIO_INPUT);
32 s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPIO_INPUT);
33 s3c2410_gpio_pullup(S3C2410_GPE11, 1);
34 s3c2410_gpio_pullup(S3C2410_GPE12, 1);
35 s3c2410_gpio_pullup(S3C2410_GPE13, 1);
36 }
37}
diff --git a/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c b/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
new file mode 100644
index 000000000000..8fccd4e549f0
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
@@ -0,0 +1,37 @@
1/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpg5_6_7.c
2 *
3 * Copyright (c) 2008 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 *
7 * S3C24XX SPI - gpio configuration for bus 1 on gpg5,6,7
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License.
12*/
13
14#include <linux/kernel.h>
15
16#include <mach/hardware.h>
17
18#include <mach/spi.h>
19#include <mach/regs-gpio.h>
20
21void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi,
22 int enable)
23{
24 if (enable) {
25 s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_SPICLK1);
26 s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_SPIMOSI1);
27 s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPG5_SPIMISO1);
28 s3c2410_gpio_pullup(S3C2410_GPG5, 0);
29 s3c2410_gpio_pullup(S3C2410_GPG6, 0);
30 } else {
31 s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPIO_INPUT);
32 s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPIO_INPUT);
33 s3c2410_gpio_pullup(S3C2410_GPG5, 1);
34 s3c2410_gpio_pullup(S3C2410_GPG6, 1);
35 s3c2410_gpio_pullup(S3C2410_GPG7, 1);
36 }
37}
diff --git a/arch/arm/plat-s3c24xx/time.c b/arch/arm/plat-s3c24xx/time.c
deleted file mode 100644
index c51916236ac0..000000000000
--- a/arch/arm/plat-s3c24xx/time.c
+++ /dev/null
@@ -1,260 +0,0 @@
1/* linux/arch/arm/plat-s3c24xx/time.c
2 *
3 * Copyright (C) 2003-2005 Simtec Electronics
4 * Ben Dooks, <ben@simtec.co.uk>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
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
21#include <linux/kernel.h>
22#include <linux/sched.h>
23#include <linux/init.h>
24#include <linux/interrupt.h>
25#include <linux/irq.h>
26#include <linux/err.h>
27#include <linux/clk.h>
28#include <linux/io.h>
29
30#include <asm/system.h>
31#include <asm/leds.h>
32#include <asm/mach-types.h>
33
34#include <asm/irq.h>
35#include <mach/map.h>
36#include <plat/regs-timer.h>
37#include <mach/regs-irq.h>
38#include <asm/mach/time.h>
39
40#include <plat/clock.h>
41#include <plat/cpu.h>
42
43static unsigned long timer_startval;
44static unsigned long timer_usec_ticks;
45
46#define TIMER_USEC_SHIFT 16
47
48/* we use the shifted arithmetic to work out the ratio of timer ticks
49 * to usecs, as often the peripheral clock is not a nice even multiple
50 * of 1MHz.
51 *
52 * shift of 14 and 15 are too low for the 12MHz, 16 seems to be ok
53 * for the current HZ value of 200 without producing overflows.
54 *
55 * Original patch by Dimitry Andric, updated by Ben Dooks
56*/
57
58
59/* timer_mask_usec_ticks
60 *
61 * given a clock and divisor, make the value to pass into timer_ticks_to_usec
62 * to scale the ticks into usecs
63*/
64
65static inline unsigned long
66timer_mask_usec_ticks(unsigned long scaler, unsigned long pclk)
67{
68 unsigned long den = pclk / 1000;
69
70 return ((1000 << TIMER_USEC_SHIFT) * scaler + (den >> 1)) / den;
71}
72
73/* timer_ticks_to_usec
74 *
75 * convert timer ticks to usec.
76*/
77
78static inline unsigned long timer_ticks_to_usec(unsigned long ticks)
79{
80 unsigned long res;
81
82 res = ticks * timer_usec_ticks;
83 res += 1 << (TIMER_USEC_SHIFT - 4); /* round up slightly */
84
85 return res >> TIMER_USEC_SHIFT;
86}
87
88/***
89 * Returns microsecond since last clock interrupt. Note that interrupts
90 * will have been disabled by do_gettimeoffset()
91 * IRQs are disabled before entering here from do_gettimeofday()
92 */
93
94#define SRCPND_TIMER4 (1<<(IRQ_TIMER4 - IRQ_EINT0))
95
96static unsigned long s3c2410_gettimeoffset (void)
97{
98 unsigned long tdone;
99 unsigned long irqpend;
100 unsigned long tval;
101
102 /* work out how many ticks have gone since last timer interrupt */
103
104 tval = __raw_readl(S3C2410_TCNTO(4));
105 tdone = timer_startval - tval;
106
107 /* check to see if there is an interrupt pending */
108
109 irqpend = __raw_readl(S3C2410_SRCPND);
110 if (irqpend & SRCPND_TIMER4) {
111 /* re-read the timer, and try and fix up for the missed
112 * interrupt. Note, the interrupt may go off before the
113 * timer has re-loaded from wrapping.
114 */
115
116 tval = __raw_readl(S3C2410_TCNTO(4));
117 tdone = timer_startval - tval;
118
119 if (tval != 0)
120 tdone += timer_startval;
121 }
122
123 return timer_ticks_to_usec(tdone);
124}
125
126
127/*
128 * IRQ handler for the timer
129 */
130static irqreturn_t
131s3c2410_timer_interrupt(int irq, void *dev_id)
132{
133 timer_tick();
134 return IRQ_HANDLED;
135}
136
137static struct irqaction s3c2410_timer_irq = {
138 .name = "S3C2410 Timer Tick",
139 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
140 .handler = s3c2410_timer_interrupt,
141};
142
143#define use_tclk1_12() ( \
144 machine_is_bast() || \
145 machine_is_vr1000() || \
146 machine_is_anubis() || \
147 machine_is_osiris() )
148
149/*
150 * Set up timer interrupt, and return the current time in seconds.
151 *
152 * Currently we only use timer4, as it is the only timer which has no
153 * other function that can be exploited externally
154 */
155static void s3c2410_timer_setup (void)
156{
157 unsigned long tcon;
158 unsigned long tcnt;
159 unsigned long tcfg1;
160 unsigned long tcfg0;
161
162 tcnt = 0xffff; /* default value for tcnt */
163
164 /* read the current timer configuration bits */
165
166 tcon = __raw_readl(S3C2410_TCON);
167 tcfg1 = __raw_readl(S3C2410_TCFG1);
168 tcfg0 = __raw_readl(S3C2410_TCFG0);
169
170 /* configure the system for whichever machine is in use */
171
172 if (use_tclk1_12()) {
173 /* timer is at 12MHz, scaler is 1 */
174 timer_usec_ticks = timer_mask_usec_ticks(1, 12000000);
175 tcnt = 12000000 / HZ;
176
177 tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
178 tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1;
179 } else {
180 unsigned long pclk;
181 struct clk *clk;
182
183 /* for the h1940 (and others), we use the pclk from the core
184 * to generate the timer values. since values around 50 to
185 * 70MHz are not values we can directly generate the timer
186 * value from, we need to pre-scale and divide before using it.
187 *
188 * for instance, using 50.7MHz and dividing by 6 gives 8.45MHz
189 * (8.45 ticks per usec)
190 */
191
192 /* this is used as default if no other timer can be found */
193
194 clk = clk_get(NULL, "timers");
195 if (IS_ERR(clk))
196 panic("failed to get clock for system timer");
197
198 clk_enable(clk);
199
200 pclk = clk_get_rate(clk);
201
202 /* configure clock tick */
203
204 timer_usec_ticks = timer_mask_usec_ticks(6, pclk);
205
206 tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
207 tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
208
209 tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
210 tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT;
211
212 tcnt = (pclk / 6) / HZ;
213 }
214
215 /* timers reload after counting zero, so reduce the count by 1 */
216
217 tcnt--;
218
219 printk("timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n",
220 tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks);
221
222 /* check to see if timer is within 16bit range... */
223 if (tcnt > 0xffff) {
224 panic("setup_timer: HZ is too small, cannot configure timer!");
225 return;
226 }
227
228 __raw_writel(tcfg1, S3C2410_TCFG1);
229 __raw_writel(tcfg0, S3C2410_TCFG0);
230
231 timer_startval = tcnt;
232 __raw_writel(tcnt, S3C2410_TCNTB(4));
233
234 /* ensure timer is stopped... */
235
236 tcon &= ~(7<<20);
237 tcon |= S3C2410_TCON_T4RELOAD;
238 tcon |= S3C2410_TCON_T4MANUALUPD;
239
240 __raw_writel(tcon, S3C2410_TCON);
241 __raw_writel(tcnt, S3C2410_TCNTB(4));
242 __raw_writel(tcnt, S3C2410_TCMPB(4));
243
244 /* start the timer running */
245 tcon |= S3C2410_TCON_T4START;
246 tcon &= ~S3C2410_TCON_T4MANUALUPD;
247 __raw_writel(tcon, S3C2410_TCON);
248}
249
250static void __init s3c2410_timer_init (void)
251{
252 s3c2410_timer_setup();
253 setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
254}
255
256struct sys_timer s3c24xx_timer = {
257 .init = s3c2410_timer_init,
258 .offset = s3c2410_gettimeoffset,
259 .resume = s3c2410_timer_setup
260};