aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c2410
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2006-06-18 18:06:41 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-06-18 18:06:41 -0400
commit96ce2385dd2817da549910001a69ac0a2762a1b9 (patch)
tree18ec36e9e1e8a6b7c19aacb53c256fdb941c4ecd /arch/arm/mach-s3c2410
parent66a9b49a370baac75d90b7da9a2445997a8a9438 (diff)
[ARM] 3559/1: S3C2442: core and serial port
Patch from Ben Dooks Core support for the Samsung S3C2442, and the serial port driver update to allow the serial port blocks to be used. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-s3c2410')
-rw-r--r--arch/arm/mach-s3c2410/Kconfig26
-rw-r--r--arch/arm/mach-s3c2410/Makefile10
-rw-r--r--arch/arm/mach-s3c2410/clock.c2
-rw-r--r--arch/arm/mach-s3c2410/cpu.c24
-rw-r--r--arch/arm/mach-s3c2410/cpu.h1
-rw-r--r--arch/arm/mach-s3c2410/s3c2440-irq.c77
-rw-r--r--arch/arm/mach-s3c2410/s3c2440.c142
-rw-r--r--arch/arm/mach-s3c2410/s3c2442-clock.c171
-rw-r--r--arch/arm/mach-s3c2410/s3c2442.c52
-rw-r--r--arch/arm/mach-s3c2410/s3c2442.h17
-rw-r--r--arch/arm/mach-s3c2410/s3c244x-irq.c142
-rw-r--r--arch/arm/mach-s3c2410/s3c244x.c182
-rw-r--r--arch/arm/mach-s3c2410/s3c244x.h25
13 files changed, 651 insertions, 220 deletions
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index 970f98dadffc..0c334136db7c 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -70,6 +70,18 @@ config ARCH_S3C2440
70 help 70 help
71 Say Y here if you are using the SMDK2440. 71 Say Y here if you are using the SMDK2440.
72 72
73config SMDK2440_CPU2440
74 bool "SMDK2440 with S3C2440 cpu module"
75 depends on ARCH_S3C2440
76 default y if ARCH_S3C2440
77 select CPU_S3C2440
78
79config SMDK2440_CPU2442
80 bool "SMDM2440 with S3C2442 cpu module"
81 depends on ARCH_S3C2440
82 select CPU_S3C2442
83
84
73config MACH_VR1000 85config MACH_VR1000
74 bool "Thorcom VR1000" 86 bool "Thorcom VR1000"
75 select CPU_S3C2410 87 select CPU_S3C2410
@@ -109,12 +121,26 @@ config CPU_S3C2410
109 Support for S3C2410 and S3C2410A family from the S3C24XX line 121 Support for S3C2410 and S3C2410A family from the S3C24XX line
110 of Samsung Mobile CPUs. 122 of Samsung Mobile CPUs.
111 123
124config CPU_S3C244X
125 bool
126 depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
127 help
128 Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems.
129
112config CPU_S3C2440 130config CPU_S3C2440
113 bool 131 bool
114 depends on ARCH_S3C2410 132 depends on ARCH_S3C2410
133 select CPU_S3C244X
115 help 134 help
116 Support for S3C2440 Samsung Mobile CPU based systems. 135 Support for S3C2440 Samsung Mobile CPU based systems.
117 136
137config CPU_S3C2442
138 bool
139 depends on ARCH_S3C2420
140 select CPU_S3C244X
141 help
142 Support for S3C2442 Samsung Mobile CPU based systems.
143
118comment "S3C2410 Boot" 144comment "S3C2410 Boot"
119 145
120config S3C2410_BOOT_WATCHDOG 146config S3C2410_BOOT_WATCHDOG
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 3e5712db6b52..5e09355cd4f4 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -24,6 +24,11 @@ obj-$(CONFIG_S3C2410_DMA) += dma.o
24obj-$(CONFIG_PM) += pm.o sleep.o 24obj-$(CONFIG_PM) += pm.o sleep.o
25obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o 25obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
26 26
27# S3C244X support
28
29obj-$(CONFIG_CPU_S3C244X) += s3c244x.o
30obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o
31
27# S3C2440 support 32# S3C2440 support
28 33
29obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o 34obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o
@@ -31,6 +36,11 @@ obj-$(CONFIG_CPU_S3C2440) += s3c2440-irq.o
31obj-$(CONFIG_CPU_S3C2440) += s3c2440-clock.o 36obj-$(CONFIG_CPU_S3C2440) += s3c2440-clock.o
32obj-$(CONFIG_CPU_S3C2440) += s3c2410-gpio.o 37obj-$(CONFIG_CPU_S3C2440) += s3c2410-gpio.o
33 38
39# S3C2442 support
40
41obj-$(CONFIG_CPU_S3C2442) += s3c2442.o
42obj-$(CONFIG_CPU_S3C2442) += s3c2442-clock.o
43
34# bast extras 44# bast extras
35 45
36obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o 46obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index 6de713ad319a..99d174612b53 100644
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -70,7 +70,7 @@ void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable)
70 clkcon &= ~clocks; 70 clkcon &= ~clocks;
71 71
72 /* ensure none of the special function bits set */ 72 /* ensure none of the special function bits set */
73 clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER); 73 clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER | 3);
74 74
75 __raw_writel(clkcon, S3C2410_CLKCON); 75 __raw_writel(clkcon, S3C2410_CLKCON);
76} 76}
diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c
index acc58adfbd21..52842e6e86e6 100644
--- a/arch/arm/mach-s3c2410/cpu.c
+++ b/arch/arm/mach-s3c2410/cpu.c
@@ -44,7 +44,9 @@
44#include "clock.h" 44#include "clock.h"
45#include "s3c2400.h" 45#include "s3c2400.h"
46#include "s3c2410.h" 46#include "s3c2410.h"
47#include "s3c244x.h"
47#include "s3c2440.h" 48#include "s3c2440.h"
49#include "s3c2442.h"
48 50
49struct cpu_table { 51struct cpu_table {
50 unsigned long idcode; 52 unsigned long idcode;
@@ -61,6 +63,7 @@ struct cpu_table {
61static const char name_s3c2400[] = "S3C2400"; 63static const char name_s3c2400[] = "S3C2400";
62static const char name_s3c2410[] = "S3C2410"; 64static const char name_s3c2410[] = "S3C2410";
63static const char name_s3c2440[] = "S3C2440"; 65static const char name_s3c2440[] = "S3C2440";
66static const char name_s3c2442[] = "S3C2442";
64static const char name_s3c2410a[] = "S3C2410A"; 67static const char name_s3c2410a[] = "S3C2410A";
65static const char name_s3c2440a[] = "S3C2440A"; 68static const char name_s3c2440a[] = "S3C2440A";
66 69
@@ -86,22 +89,31 @@ static struct cpu_table cpu_ids[] __initdata = {
86 { 89 {
87 .idcode = 0x32440000, 90 .idcode = 0x32440000,
88 .idmask = 0xffffffff, 91 .idmask = 0xffffffff,
89 .map_io = s3c2440_map_io, 92 .map_io = s3c244x_map_io,
90 .init_clocks = s3c2440_init_clocks, 93 .init_clocks = s3c244x_init_clocks,
91 .init_uarts = s3c2440_init_uarts, 94 .init_uarts = s3c244x_init_uarts,
92 .init = s3c2440_init, 95 .init = s3c2440_init,
93 .name = name_s3c2440 96 .name = name_s3c2440
94 }, 97 },
95 { 98 {
96 .idcode = 0x32440001, 99 .idcode = 0x32440001,
97 .idmask = 0xffffffff, 100 .idmask = 0xffffffff,
98 .map_io = s3c2440_map_io, 101 .map_io = s3c244x_map_io,
99 .init_clocks = s3c2440_init_clocks, 102 .init_clocks = s3c244x_init_clocks,
100 .init_uarts = s3c2440_init_uarts, 103 .init_uarts = s3c244x_init_uarts,
101 .init = s3c2440_init, 104 .init = s3c2440_init,
102 .name = name_s3c2440a 105 .name = name_s3c2440a
103 }, 106 },
104 { 107 {
108 .idcode = 0x32440aaa,
109 .idmask = 0xffffffff,
110 .map_io = s3c244x_map_io,
111 .init_clocks = s3c244x_init_clocks,
112 .init_uarts = s3c244x_init_uarts,
113 .init = s3c2442_init,
114 .name = name_s3c2442
115 },
116 {
105 .idcode = 0x0, /* S3C2400 doesn't have an idcode */ 117 .idcode = 0x0, /* S3C2400 doesn't have an idcode */
106 .idmask = 0xffffffff, 118 .idmask = 0xffffffff,
107 .map_io = s3c2400_map_io, 119 .map_io = s3c2400_map_io,
diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h
index 0c776acb063a..40862899b2f1 100644
--- a/arch/arm/mach-s3c2410/cpu.h
+++ b/arch/arm/mach-s3c2410/cpu.h
@@ -74,3 +74,4 @@ extern struct sys_timer s3c24xx_timer;
74/* system device classes */ 74/* system device classes */
75 75
76extern struct sysdev_class s3c2440_sysclass; 76extern struct sysdev_class s3c2440_sysclass;
77extern struct sysdev_class s3c2442_sysclass;
diff --git a/arch/arm/mach-s3c2410/s3c2440-irq.c b/arch/arm/mach-s3c2410/s3c2440-irq.c
index 278d0044c85d..acfe3870727b 100644
--- a/arch/arm/mach-s3c2410/s3c2440-irq.c
+++ b/arch/arm/mach-s3c2410/s3c2440-irq.c
@@ -100,73 +100,12 @@ static struct irqchip s3c_irq_wdtac97 = {
100 .ack = s3c_irq_wdtac97_ack, 100 .ack = s3c_irq_wdtac97_ack,
101}; 101};
102 102
103/* camera irq */
104
105static void s3c_irq_demux_cam(unsigned int irq,
106 struct irqdesc *desc,
107 struct pt_regs *regs)
108{
109 unsigned int subsrc, submsk;
110 struct irqdesc *mydesc;
111
112 /* read the current pending interrupts, and the mask
113 * for what it is available */
114
115 subsrc = __raw_readl(S3C2410_SUBSRCPND);
116 submsk = __raw_readl(S3C2410_INTSUBMSK);
117
118 subsrc &= ~submsk;
119 subsrc >>= 11;
120 subsrc &= 3;
121
122 if (subsrc != 0) {
123 if (subsrc & 1) {
124 mydesc = irq_desc + IRQ_S3C2440_CAM_C;
125 desc_handle_irq(IRQ_S3C2440_CAM_C, mydesc, regs);
126 }
127 if (subsrc & 2) {
128 mydesc = irq_desc + IRQ_S3C2440_CAM_P;
129 desc_handle_irq(IRQ_S3C2440_CAM_P, mydesc, regs);
130 }
131 }
132}
133
134#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
135
136static void
137s3c_irq_cam_mask(unsigned int irqno)
138{
139 s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11);
140}
141
142static void
143s3c_irq_cam_unmask(unsigned int irqno)
144{
145 s3c_irqsub_unmask(irqno, INTMSK_CAM);
146}
147
148static void
149s3c_irq_cam_ack(unsigned int irqno)
150{
151 s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11);
152}
153
154static struct irqchip s3c_irq_cam = {
155 .mask = s3c_irq_cam_mask,
156 .unmask = s3c_irq_cam_unmask,
157 .ack = s3c_irq_cam_ack,
158};
159
160static int s3c2440_irq_add(struct sys_device *sysdev) 103static int s3c2440_irq_add(struct sys_device *sysdev)
161{ 104{
162 unsigned int irqno; 105 unsigned int irqno;
163 106
164 printk("S3C2440: IRQ Support\n"); 107 printk("S3C2440: IRQ Support\n");
165 108
166 set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip);
167 set_irq_handler(IRQ_NFCON, do_level_IRQ);
168 set_irq_flags(IRQ_NFCON, IRQF_VALID);
169
170 /* add new chained handler for wdt, ac7 */ 109 /* add new chained handler for wdt, ac7 */
171 110
172 set_irq_chip(IRQ_WDT, &s3c_irq_level_chip); 111 set_irq_chip(IRQ_WDT, &s3c_irq_level_chip);
@@ -179,18 +118,6 @@ static int s3c2440_irq_add(struct sys_device *sysdev)
179 set_irq_flags(irqno, IRQF_VALID); 118 set_irq_flags(irqno, IRQF_VALID);
180 } 119 }
181 120
182 /* add chained handler for camera */
183
184 set_irq_chip(IRQ_CAM, &s3c_irq_level_chip);
185 set_irq_handler(IRQ_CAM, do_level_IRQ);
186 set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam);
187
188 for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) {
189 set_irq_chip(irqno, &s3c_irq_cam);
190 set_irq_handler(irqno, do_level_IRQ);
191 set_irq_flags(irqno, IRQF_VALID);
192 }
193
194 return 0; 121 return 0;
195} 122}
196 123
@@ -198,10 +125,10 @@ static struct sysdev_driver s3c2440_irq_driver = {
198 .add = s3c2440_irq_add, 125 .add = s3c2440_irq_add,
199}; 126};
200 127
201static int s3c24xx_irq_driver(void) 128static int s3c2440_irq_init(void)
202{ 129{
203 return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver); 130 return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver);
204} 131}
205 132
206arch_initcall(s3c24xx_irq_driver); 133arch_initcall(s3c2440_irq_init);
207 134
diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c
index 54681740f9f1..0ab50f44f318 100644
--- a/arch/arm/mach-s3c2410/s3c2440.c
+++ b/arch/arm/mach-s3c2410/s3c2440.c
@@ -1,6 +1,6 @@
1/* linux/arch/arm/mach-s3c2410/s3c2440.c 1/* linux/arch/arm/mach-s3c2410/s3c2440.c
2 * 2 *
3 * Copyright (c) 2004-2005 Simtec Electronics 3 * Copyright (c) 2004-2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * 5 *
6 * Samsung S3C2440 Mobile CPU support 6 * Samsung S3C2440 Mobile CPU support
@@ -8,16 +8,6 @@
8 * This program is free software; you can redistribute it and/or modify 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 9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation. 10 * published by the Free Software Foundation.
11 *
12 * Modifications:
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
19 * 14-Jan-2005 BJD Moved clock init code into seperate function
20 * 14-Jan-2005 BJD Removed un-used clock bits
21*/ 11*/
22 12
23#include <linux/kernel.h> 13#include <linux/kernel.h>
@@ -50,144 +40,20 @@
50#include "cpu.h" 40#include "cpu.h"
51#include "pm.h" 41#include "pm.h"
52 42
53
54static struct map_desc s3c2440_iodesc[] __initdata = {
55 IODESC_ENT(USBHOST),
56 IODESC_ENT(CLKPWR),
57 IODESC_ENT(LCD),
58 IODESC_ENT(TIMER),
59 IODESC_ENT(ADC),
60 IODESC_ENT(WATCHDOG),
61};
62
63/* uart initialisation */
64
65void __init s3c2440_init_uarts(struct s3c2410_uartcfg *cfg, int no)
66{
67 s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
68}
69
70#ifdef CONFIG_PM
71
72static struct sleep_save s3c2440_sleep[] = {
73 SAVE_ITEM(S3C2440_DSC0),
74 SAVE_ITEM(S3C2440_DSC1),
75 SAVE_ITEM(S3C2440_GPJDAT),
76 SAVE_ITEM(S3C2440_GPJCON),
77 SAVE_ITEM(S3C2440_GPJUP)
78};
79
80static int s3c2440_suspend(struct sys_device *dev, pm_message_t state)
81{
82 s3c2410_pm_do_save(s3c2440_sleep, ARRAY_SIZE(s3c2440_sleep));
83 return 0;
84}
85
86static int s3c2440_resume(struct sys_device *dev)
87{
88 s3c2410_pm_do_restore(s3c2440_sleep, ARRAY_SIZE(s3c2440_sleep));
89 return 0;
90}
91
92#else
93#define s3c2440_suspend NULL
94#define s3c2440_resume NULL
95#endif
96
97struct sysdev_class s3c2440_sysclass = {
98 set_kset_name("s3c2440-core"),
99 .suspend = s3c2440_suspend,
100 .resume = s3c2440_resume
101};
102
103static struct sys_device s3c2440_sysdev = { 43static struct sys_device s3c2440_sysdev = {
104 .cls = &s3c2440_sysclass, 44 .cls = &s3c2440_sysclass,
105}; 45};
106 46
107void __init s3c2440_map_io(struct map_desc *mach_desc, int size) 47int __init s3c2440_init(void)
108{ 48{
109 /* register our io-tables */ 49 printk("S3C2440: Initialising architecture\n");
110
111 iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc));
112 iotable_init(mach_desc, size);
113
114 /* rename any peripherals used differing from the s3c2410 */
115
116 s3c_device_i2c.name = "s3c2440-i2c";
117 s3c_device_nand.name = "s3c2440-nand";
118 50
119 /* change irq for watchdog */ 51 /* change irq for watchdog */
120 52
121 s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT; 53 s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
122 s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT; 54 s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT;
123}
124 55
125void __init s3c2440_init_clocks(int xtal) 56 /* register our system device for everything else */
126{
127 unsigned long clkdiv;
128 unsigned long camdiv;
129 unsigned long hclk, fclk, pclk;
130 int hdiv = 1;
131
132 /* now we've got our machine bits initialised, work out what
133 * clocks we've got */
134
135 fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
136
137 clkdiv = __raw_readl(S3C2410_CLKDIVN);
138 camdiv = __raw_readl(S3C2440_CAMDIVN);
139
140 /* work out clock scalings */
141
142 switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
143 case S3C2440_CLKDIVN_HDIVN_1:
144 hdiv = 1;
145 break;
146
147 case S3C2440_CLKDIVN_HDIVN_2:
148 hdiv = 2;
149 break;
150
151 case S3C2440_CLKDIVN_HDIVN_4_8:
152 hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
153 break;
154
155 case S3C2440_CLKDIVN_HDIVN_3_6:
156 hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
157 break;
158 }
159
160 hclk = fclk / hdiv;
161 pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
162
163 /* print brief summary of clocks, etc */
164
165 printk("S3C2440: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
166 print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
167
168 /* initialise the clocks here, to allow other things like the
169 * console to use them, and to add new ones after the initialisation
170 */
171
172 s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
173}
174
175/* need to register class before we actually register the device, and
176 * we also need to ensure that it has been initialised before any of the
177 * drivers even try to use it (even if not on an s3c2440 based system)
178 * as a driver which may support both 2410 and 2440 may try and use it.
179*/
180
181static int __init s3c2440_core_init(void)
182{
183 return sysdev_class_register(&s3c2440_sysclass);
184}
185
186core_initcall(s3c2440_core_init);
187
188int __init s3c2440_init(void)
189{
190 printk("S3C2440: Initialising architecture\n");
191 57
192 return sysdev_register(&s3c2440_sysdev); 58 return sysdev_register(&s3c2440_sysdev);
193} 59}
diff --git a/arch/arm/mach-s3c2410/s3c2442-clock.c b/arch/arm/mach-s3c2410/s3c2442-clock.c
new file mode 100644
index 000000000000..5b7b301eb522
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2442-clock.c
@@ -0,0 +1,171 @@
1/* linux/arch/arm/mach-s3c2410/s3c2442-clock.c
2 *
3 * Copyright (c) 2004-2005 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 *
7 * S3C2442 Clock support
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, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22*/
23
24#include <linux/init.h>
25#include <linux/module.h>
26#include <linux/kernel.h>
27#include <linux/list.h>
28#include <linux/errno.h>
29#include <linux/err.h>
30#include <linux/device.h>
31#include <linux/sysdev.h>
32#include <linux/interrupt.h>
33#include <linux/ioport.h>
34#include <linux/mutex.h>
35#include <linux/clk.h>
36
37#include <asm/hardware.h>
38#include <asm/atomic.h>
39#include <asm/irq.h>
40#include <asm/io.h>
41
42#include <asm/arch/regs-clock.h>
43
44#include "clock.h"
45#include "cpu.h"
46
47/* S3C2442 extended clock support */
48
49static unsigned long s3c2442_camif_upll_round(struct clk *clk,
50 unsigned long rate)
51{
52 unsigned long parent_rate = clk_get_rate(clk->parent);
53 int div;
54
55 if (rate > parent_rate)
56 return parent_rate;
57
58 div = parent_rate / rate;
59
60 if (div == 3)
61 return parent_rate / 3;
62
63 /* note, we remove the +/- 1 calculations for the divisor */
64
65 div /= 2;
66
67 if (div < 1)
68 div = 1;
69 else if (div > 16)
70 div = 16;
71
72 return parent_rate / (div * 2);
73}
74
75static int s3c2442_camif_upll_setrate(struct clk *clk, unsigned long rate)
76{
77 unsigned long parent_rate = clk_get_rate(clk->parent);
78 unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
79
80 rate = s3c2442_camif_upll_round(clk, rate);
81
82 camdivn &= ~S3C2442_CAMDIVN_CAMCLK_DIV3;
83
84 if (rate == parent_rate) {
85 camdivn &= ~S3C2440_CAMDIVN_CAMCLK_SEL;
86 } else if ((parent_rate / rate) == 3) {
87 camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL;
88 camdivn |= S3C2442_CAMDIVN_CAMCLK_DIV3;
89 } else {
90 camdivn &= ~S3C2440_CAMDIVN_CAMCLK_MASK;
91 camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL;
92 camdivn |= (((parent_rate / rate) / 2) - 1);
93 }
94
95 __raw_writel(camdivn, S3C2440_CAMDIVN);
96
97 return 0;
98}
99
100/* Extra S3C2442 clocks */
101
102static struct clk s3c2442_clk_cam = {
103 .name = "camif",
104 .id = -1,
105 .enable = s3c24xx_clkcon_enable,
106 .ctrlbit = S3C2440_CLKCON_CAMERA,
107};
108
109static struct clk s3c2442_clk_cam_upll = {
110 .name = "camif-upll",
111 .id = -1,
112 .set_rate = s3c2442_camif_upll_setrate,
113 .round_rate = s3c2442_camif_upll_round,
114};
115
116static int s3c2442_clk_add(struct sys_device *sysdev)
117{
118 unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
119 unsigned long clkdivn;
120 struct clk *clk_h;
121 struct clk *clk_p;
122 struct clk *clk_upll;
123
124 printk("S3C2442: Clock Support, DVS %s\n",
125 (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
126
127 clk_p = clk_get(NULL, "pclk");
128 clk_h = clk_get(NULL, "hclk");
129 clk_upll = clk_get(NULL, "upll");
130
131 if (IS_ERR(clk_p) || IS_ERR(clk_h) || IS_ERR(clk_upll)) {
132 printk(KERN_ERR "S3C2442: Failed to get parent clocks\n");
133 return -EINVAL;
134 }
135
136 /* check rate of UPLL, and if it is near 96MHz, then change
137 * to using half the UPLL rate for the system */
138
139 if (clk_get_rate(clk_upll) > (94 * MHZ)) {
140 clk_usb_bus.rate = clk_get_rate(clk_upll) / 2;
141
142 mutex_lock(&clocks_mutex);
143
144 clkdivn = __raw_readl(S3C2410_CLKDIVN);
145 clkdivn |= S3C2440_CLKDIVN_UCLK;
146 __raw_writel(clkdivn, S3C2410_CLKDIVN);
147
148 mutex_unlock(&clocks_mutex);
149 }
150
151 s3c2442_clk_cam.parent = clk_h;
152 s3c2442_clk_cam_upll.parent = clk_upll;
153
154 s3c24xx_register_clock(&s3c2442_clk_cam);
155 s3c24xx_register_clock(&s3c2442_clk_cam_upll);
156
157 clk_disable(&s3c2442_clk_cam);
158
159 return 0;
160}
161
162static struct sysdev_driver s3c2442_clk_driver = {
163 .add = s3c2442_clk_add,
164};
165
166static __init int s3c2442_clk_init(void)
167{
168 return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_clk_driver);
169}
170
171arch_initcall(s3c2442_clk_init);
diff --git a/arch/arm/mach-s3c2410/s3c2442.c b/arch/arm/mach-s3c2410/s3c2442.c
new file mode 100644
index 000000000000..debae2430557
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2442.c
@@ -0,0 +1,52 @@
1/* linux/arch/arm/mach-s3c2410/s3c2440.c
2 *
3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Samsung S3C2442 Mobile 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#include <linux/kernel.h>
14#include <linux/types.h>
15#include <linux/interrupt.h>
16#include <linux/list.h>
17#include <linux/timer.h>
18#include <linux/init.h>
19#include <linux/platform_device.h>
20#include <linux/sysdev.h>
21#include <linux/clk.h>
22
23#include <asm/mach/arch.h>
24#include <asm/mach/map.h>
25#include <asm/mach/irq.h>
26
27#include <asm/hardware.h>
28#include <asm/io.h>
29#include <asm/irq.h>
30
31#include <asm/arch/regs-clock.h>
32#include <asm/arch/regs-serial.h>
33#include <asm/arch/regs-gpio.h>
34#include <asm/arch/regs-gpioj.h>
35#include <asm/arch/regs-dsc.h>
36
37#include "s3c2442.h"
38#include "clock.h"
39#include "devs.h"
40#include "cpu.h"
41#include "pm.h"
42
43static struct sys_device s3c2442_sysdev = {
44 .cls = &s3c2442_sysclass,
45};
46
47int __init s3c2442_init(void)
48{
49 printk("S3C2442: Initialising architecture\n");
50
51 return sysdev_register(&s3c2442_sysdev);
52}
diff --git a/arch/arm/mach-s3c2410/s3c2442.h b/arch/arm/mach-s3c2410/s3c2442.h
new file mode 100644
index 000000000000..0ae37d24866c
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2442.h
@@ -0,0 +1,17 @@
1/* arch/arm/mach-s3c2410/s3c2442.h
2 *
3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Header file for s3c2442 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#ifdef CONFIG_CPU_S3C2442
14extern int s3c2442_init(void);
15#else
16#define s3c2442_init NULL
17#endif
diff --git a/arch/arm/mach-s3c2410/s3c244x-irq.c b/arch/arm/mach-s3c2410/s3c244x-irq.c
new file mode 100644
index 000000000000..2aadca1ce7eb
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c244x-irq.c
@@ -0,0 +1,142 @@
1/* linux/arch/arm/mach-s3c2410/s3c2440-irq.c
2 *
3 * Copyright (c) 2003,2004 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 * Changelog:
21 * 25-Jul-2005 BJD Split from irq.c
22 *
23*/
24
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/interrupt.h>
28#include <linux/ioport.h>
29#include <linux/ptrace.h>
30#include <linux/sysdev.h>
31
32#include <asm/hardware.h>
33#include <asm/irq.h>
34#include <asm/io.h>
35
36#include <asm/mach/irq.h>
37
38#include <asm/arch/regs-irq.h>
39#include <asm/arch/regs-gpio.h>
40
41#include "cpu.h"
42#include "pm.h"
43#include "irq.h"
44
45/* camera irq */
46
47static void s3c_irq_demux_cam(unsigned int irq,
48 struct irqdesc *desc,
49 struct pt_regs *regs)
50{
51 unsigned int subsrc, submsk;
52 struct irqdesc *mydesc;
53
54 /* read the current pending interrupts, and the mask
55 * for what it is available */
56
57 subsrc = __raw_readl(S3C2410_SUBSRCPND);
58 submsk = __raw_readl(S3C2410_INTSUBMSK);
59
60 subsrc &= ~submsk;
61 subsrc >>= 11;
62 subsrc &= 3;
63
64 if (subsrc != 0) {
65 if (subsrc & 1) {
66 mydesc = irq_desc + IRQ_S3C2440_CAM_C;
67 desc_handle_irq(IRQ_S3C2440_CAM_C, mydesc, regs);
68 }
69 if (subsrc & 2) {
70 mydesc = irq_desc + IRQ_S3C2440_CAM_P;
71 desc_handle_irq(IRQ_S3C2440_CAM_P, mydesc, regs);
72 }
73 }
74}
75
76#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
77
78static void
79s3c_irq_cam_mask(unsigned int irqno)
80{
81 s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11);
82}
83
84static void
85s3c_irq_cam_unmask(unsigned int irqno)
86{
87 s3c_irqsub_unmask(irqno, INTMSK_CAM);
88}
89
90static void
91s3c_irq_cam_ack(unsigned int irqno)
92{
93 s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11);
94}
95
96static struct irqchip s3c_irq_cam = {
97 .mask = s3c_irq_cam_mask,
98 .unmask = s3c_irq_cam_unmask,
99 .ack = s3c_irq_cam_ack,
100};
101
102static int s3c244x_irq_add(struct sys_device *sysdev)
103{
104 unsigned int irqno;
105
106 set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip);
107 set_irq_handler(IRQ_NFCON, do_level_IRQ);
108 set_irq_flags(IRQ_NFCON, IRQF_VALID);
109
110 /* add chained handler for camera */
111
112 set_irq_chip(IRQ_CAM, &s3c_irq_level_chip);
113 set_irq_handler(IRQ_CAM, do_level_IRQ);
114 set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam);
115
116 for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) {
117 set_irq_chip(irqno, &s3c_irq_cam);
118 set_irq_handler(irqno, do_level_IRQ);
119 set_irq_flags(irqno, IRQF_VALID);
120 }
121
122 return 0;
123}
124
125static struct sysdev_driver s3c244x_irq_driver = {
126 .add = s3c244x_irq_add,
127};
128
129static int s3c2440_irq_init(void)
130{
131 return sysdev_driver_register(&s3c2440_sysclass, &s3c244x_irq_driver);
132}
133
134arch_initcall(s3c2440_irq_init);
135
136
137static int s3c2442_irq_init(void)
138{
139 return sysdev_driver_register(&s3c2442_sysclass, &s3c244x_irq_driver);
140}
141
142arch_initcall(s3c2442_irq_init);
diff --git a/arch/arm/mach-s3c2410/s3c244x.c b/arch/arm/mach-s3c2410/s3c244x.c
new file mode 100644
index 000000000000..96852a7000db
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c244x.c
@@ -0,0 +1,182 @@
1/* linux/arch/arm/mach-s3c2410/s3c244x.c
2 *
3 * Copyright (c) 2004-2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Samsung S3C2440 and S3C2442 Mobile 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#include <linux/kernel.h>
14#include <linux/types.h>
15#include <linux/interrupt.h>
16#include <linux/list.h>
17#include <linux/timer.h>
18#include <linux/init.h>
19#include <linux/platform_device.h>
20#include <linux/sysdev.h>
21#include <linux/clk.h>
22
23#include <asm/mach/arch.h>
24#include <asm/mach/map.h>
25#include <asm/mach/irq.h>
26
27#include <asm/hardware.h>
28#include <asm/io.h>
29#include <asm/irq.h>
30
31#include <asm/arch/regs-clock.h>
32#include <asm/arch/regs-serial.h>
33#include <asm/arch/regs-gpio.h>
34#include <asm/arch/regs-gpioj.h>
35#include <asm/arch/regs-dsc.h>
36
37#include "s3c2440.h"
38#include "s3c244x.h"
39#include "clock.h"
40#include "devs.h"
41#include "cpu.h"
42#include "pm.h"
43
44static struct map_desc s3c244x_iodesc[] __initdata = {
45 IODESC_ENT(CLKPWR),
46 IODESC_ENT(TIMER),
47 IODESC_ENT(WATCHDOG),
48 IODESC_ENT(LCD),
49 IODESC_ENT(ADC),
50 IODESC_ENT(USBHOST),
51};
52
53/* uart initialisation */
54
55void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
56{
57 s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
58}
59
60void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
61{
62 /* register our io-tables */
63
64 iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
65 iotable_init(mach_desc, size);
66
67 /* rename any peripherals used differing from the s3c2410 */
68
69 s3c_device_i2c.name = "s3c2440-i2c";
70 s3c_device_nand.name = "s3c2440-nand";
71}
72
73void __init s3c244x_init_clocks(int xtal)
74{
75 unsigned long clkdiv;
76 unsigned long camdiv;
77 unsigned long hclk, fclk, pclk;
78 int hdiv = 1;
79
80 /* now we've got our machine bits initialised, work out what
81 * clocks we've got */
82
83 fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
84
85 clkdiv = __raw_readl(S3C2410_CLKDIVN);
86 camdiv = __raw_readl(S3C2440_CAMDIVN);
87
88 /* work out clock scalings */
89
90 switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
91 case S3C2440_CLKDIVN_HDIVN_1:
92 hdiv = 1;
93 break;
94
95 case S3C2440_CLKDIVN_HDIVN_2:
96 hdiv = 2;
97 break;
98
99 case S3C2440_CLKDIVN_HDIVN_4_8:
100 hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
101 break;
102
103 case S3C2440_CLKDIVN_HDIVN_3_6:
104 hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
105 break;
106 }
107
108 hclk = fclk / hdiv;
109 pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
110
111 /* print brief summary of clocks, etc */
112
113 printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
114 print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
115
116 /* initialise the clocks here, to allow other things like the
117 * console to use them, and to add new ones after the initialisation
118 */
119
120 s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
121}
122
123#ifdef CONFIG_PM
124
125static struct sleep_save s3c244x_sleep[] = {
126 SAVE_ITEM(S3C2440_DSC0),
127 SAVE_ITEM(S3C2440_DSC1),
128 SAVE_ITEM(S3C2440_GPJDAT),
129 SAVE_ITEM(S3C2440_GPJCON),
130 SAVE_ITEM(S3C2440_GPJUP)
131};
132
133static int s3c244x_suspend(struct sys_device *dev, pm_message_t state)
134{
135 s3c2410_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
136 return 0;
137}
138
139static int s3c244x_resume(struct sys_device *dev)
140{
141 s3c2410_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
142 return 0;
143}
144
145#else
146#define s3c244x_suspend NULL
147#define s3c244x_resume NULL
148#endif
149
150/* Since the S3C2442 and S3C2440 share items, put both sysclasses here */
151
152struct sysdev_class s3c2440_sysclass = {
153 set_kset_name("s3c2440-core"),
154 .suspend = s3c244x_suspend,
155 .resume = s3c244x_resume
156};
157
158struct sysdev_class s3c2442_sysclass = {
159 set_kset_name("s3c2442-core"),
160 .suspend = s3c244x_suspend,
161 .resume = s3c244x_resume
162};
163
164/* need to register class before we actually register the device, and
165 * we also need to ensure that it has been initialised before any of the
166 * drivers even try to use it (even if not on an s3c2440 based system)
167 * as a driver which may support both 2410 and 2440 may try and use it.
168*/
169
170static int __init s3c2440_core_init(void)
171{
172 return sysdev_class_register(&s3c2440_sysclass);
173}
174
175core_initcall(s3c2440_core_init);
176
177static int __init s3c2442_core_init(void)
178{
179 return sysdev_class_register(&s3c2442_sysclass);
180}
181
182core_initcall(s3c2442_core_init);
diff --git a/arch/arm/mach-s3c2410/s3c244x.h b/arch/arm/mach-s3c2410/s3c244x.h
new file mode 100644
index 000000000000..3e7f5f75134d
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c244x.h
@@ -0,0 +1,25 @@
1/* arch/arm/mach-s3c2410/s3c2440.h
2 *
3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Header file for S3C2440 and S3C2442 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#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
14
15extern void s3c244x_map_io(struct map_desc *mach_desc, int size);
16
17extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no);
18
19extern void s3c244x_init_clocks(int xtal);
20
21#else
22#define s3c244x_init_clocks NULL
23#define s3c244x_init_uarts NULL
24#define s3c244x_map_io NULL
25#endif