1 /* linux/arch/arm/mach-s3c2410/s3c2440.c
3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
6 * Samsung S3C2440 Mobile CPU support
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.
13 * 24-Aug-2004 BJD Start of s3c2440 support
14 * 12-Oct-2004 BJD Moved clock info out to clock.c
15 * 01-Nov-2004 BJD Fixed clock build code
16 * 09-Nov-2004 BJD Added sysdev for power management
17 * 04-Nov-2004 BJD New serial registration
18 * 15-Nov-2004 BJD Rename the i2c device for the s3c2440
21 #include <linux/kernel.h>
22 #include <linux/types.h>
23 #include <linux/interrupt.h>
24 #include <linux/list.h>
25 #include <linux/timer.h>
26 #include <linux/init.h>
27 #include <linux/device.h>
28 #include <linux/sysdev.h>
30 #include <asm/mach/arch.h>
31 #include <asm/mach/map.h>
32 #include <asm/mach/irq.h>
34 #include <asm/hardware.h>
37 #include <asm/hardware/clock.h>
39 #include <asm/arch/regs-clock.h>
40 #include <asm/arch/regs-serial.h>
41 #include <asm/arch/regs-gpio.h>
42 #include <asm/arch/regs-gpioj.h>
43 #include <asm/arch/regs-dsc.h>
51 int s3c2440_clock_tick_rate = 12*1000*1000; /* current timers at 12MHz */
54 unsigned long s3c2440_hdiv;
56 static struct map_desc s3c2440_iodesc[] __initdata = {
64 static struct resource s3c_uart0_resource[] = {
66 .start = S3C2410_PA_UART0,
67 .end = S3C2410_PA_UART0 + 0x3fff,
68 .flags = IORESOURCE_MEM,
71 .start = IRQ_S3CUART_RX0,
72 .end = IRQ_S3CUART_ERR0,
73 .flags = IORESOURCE_IRQ,
78 static struct resource s3c_uart1_resource[] = {
80 .start = S3C2410_PA_UART1,
81 .end = S3C2410_PA_UART1 + 0x3fff,
82 .flags = IORESOURCE_MEM,
85 .start = IRQ_S3CUART_RX1,
86 .end = IRQ_S3CUART_ERR1,
87 .flags = IORESOURCE_IRQ,
91 static struct resource s3c_uart2_resource[] = {
93 .start = S3C2410_PA_UART2,
94 .end = S3C2410_PA_UART2 + 0x3fff,
95 .flags = IORESOURCE_MEM,
98 .start = IRQ_S3CUART_RX2,
99 .end = IRQ_S3CUART_ERR2,
100 .flags = IORESOURCE_IRQ,
104 /* our uart devices */
106 static struct platform_device s3c_uart0 = {
107 .name = "s3c2440-uart",
109 .num_resources = ARRAY_SIZE(s3c_uart0_resource),
110 .resource = s3c_uart0_resource,
114 static struct platform_device s3c_uart1 = {
115 .name = "s3c2440-uart",
117 .num_resources = ARRAY_SIZE(s3c_uart1_resource),
118 .resource = s3c_uart1_resource,
121 static struct platform_device s3c_uart2 = {
122 .name = "s3c2440-uart",
124 .num_resources = ARRAY_SIZE(s3c_uart2_resource),
125 .resource = s3c_uart2_resource,
128 static struct platform_device *uart_devices[] __initdata = {
134 /* uart initialisation */
136 static int __initdata s3c2440_uart_count;
138 void __init s3c2440_init_uarts(struct s3c2410_uartcfg *cfg, int no)
140 struct platform_device *platdev;
143 for (uart = 0; uart < no; uart++, cfg++) {
144 platdev = uart_devices[cfg->hwport];
146 s3c24xx_uart_devs[uart] = platdev;
147 platdev->dev.platform_data = cfg;
150 s3c2440_uart_count = uart;
153 /* s3c2440 specific clock sources */
155 static struct clk s3c2440_clk_cam = {
157 .enable = s3c2410_clkcon_enable,
158 .ctrlbit = S3C2440_CLKCON_CAMERA
161 static struct clk s3c2440_clk_ac97 = {
163 .enable = s3c2410_clkcon_enable,
164 .ctrlbit = S3C2440_CLKCON_CAMERA
169 struct sleep_save s3c2440_sleep[] = {
170 SAVE_ITEM(S3C2440_DSC0),
171 SAVE_ITEM(S3C2440_DSC1),
172 SAVE_ITEM(S3C2440_GPJDAT),
173 SAVE_ITEM(S3C2440_GPJCON),
174 SAVE_ITEM(S3C2440_GPJUP)
177 static int s3c2440_suspend(struct sys_device *dev, u32 state)
179 s3c2410_pm_do_save(s3c2440_sleep, ARRAY_SIZE(s3c2440_sleep));
183 static int s3c2440_resume(struct sys_device *dev)
185 s3c2410_pm_do_restore(s3c2440_sleep, ARRAY_SIZE(s3c2440_sleep));
190 #define s3c2440_suspend NULL
191 #define s3c2440_resume NULL
194 static struct sysdev_class s3c2440_sysclass = {
195 set_kset_name("s3c2440-core"),
196 .suspend = s3c2440_suspend,
197 .resume = s3c2440_resume
200 static struct sys_device s3c2440_sysdev = {
201 .cls = &s3c2440_sysclass,
204 void __init s3c2440_map_io(struct map_desc *mach_desc, int size)
206 unsigned long clkdiv;
207 unsigned long camdiv;
209 /* register our io-tables */
211 iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc));
212 iotable_init(mach_desc, size);
214 /* now we've got our machine bits initialised, work out what
215 * clocks we've got */
217 s3c24xx_fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON),
220 clkdiv = __raw_readl(S3C2410_CLKDIVN);
221 camdiv = __raw_readl(S3C2440_CAMDIVN);
223 /* work out clock scalings */
225 switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
226 case S3C2440_CLKDIVN_HDIVN_1:
230 case S3C2440_CLKDIVN_HDIVN_2:
234 case S3C2440_CLKDIVN_HDIVN_4_8:
235 s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
238 case S3C2440_CLKDIVN_HDIVN_3_6:
239 s3c2440_hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
243 s3c24xx_hclk = s3c24xx_fclk / s3c2440_hdiv;
244 s3c24xx_pclk = s3c24xx_hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
246 /* print brieft summary of clocks, etc */
248 printk("S3C2440: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
249 print_mhz(s3c24xx_fclk), print_mhz(s3c24xx_hclk),
250 print_mhz(s3c24xx_pclk));
252 /* initialise the clocks here, to allow other things like the
253 * console to use them, and to add new ones after the initialisation
256 s3c2410_init_clocks();
258 /* add s3c2440 specific clocks */
260 s3c2440_clk_cam.parent = clk_get(NULL, "hclk");
261 s3c2440_clk_ac97.parent = clk_get(NULL, "pclk");
263 s3c2410_register_clock(&s3c2440_clk_ac97);
264 s3c2410_register_clock(&s3c2440_clk_cam);
266 clk_disable(&s3c2440_clk_ac97);
267 clk_disable(&s3c2440_clk_cam);
269 /* rename any peripherals used differing from the s3c2410 */
271 s3c_device_i2c.name = "s3c2440-i2c";
274 int __init s3c2440_init(void)
278 printk("S3C2440: Initialising architecture\n");
280 ret = sysdev_class_register(&s3c2440_sysclass);
282 ret = sysdev_register(&s3c2440_sysdev);
285 printk(KERN_ERR "failed to register sysdev for s3c2440\n");
288 ret = platform_add_devices(s3c24xx_uart_devs, s3c2440_uart_count);