summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c2410
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2006-06-18 23:06:41 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-06-18 23:06:41 +0100
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 970f98dadff..0c334136db7 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -70,6 +70,18 @@ config ARCH_S3C2440
help
Say Y here if you are using the SMDK2440.
+config SMDK2440_CPU2440
+ bool "SMDK2440 with S3C2440 cpu module"
+ depends on ARCH_S3C2440
+ default y if ARCH_S3C2440
+ select CPU_S3C2440
+
+config SMDK2440_CPU2442
+ bool "SMDM2440 with S3C2442 cpu module"
+ depends on ARCH_S3C2440
+ select CPU_S3C2442
+
+
config MACH_VR1000
bool "Thorcom VR1000"
select CPU_S3C2410
@@ -109,12 +121,26 @@ config CPU_S3C2410
Support for S3C2410 and S3C2410A family from the S3C24XX line
of Samsung Mobile CPUs.
+config CPU_S3C244X
+ bool
+ depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
+ help
+ Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems.
+
config CPU_S3C2440
bool
depends on ARCH_S3C2410
+ select CPU_S3C244X
help
Support for S3C2440 Samsung Mobile CPU based systems.
+config CPU_S3C2442
+ bool
+ depends on ARCH_S3C2420
+ select CPU_S3C244X
+ help
+ Support for S3C2442 Samsung Mobile CPU based systems.
+
comment "S3C2410 Boot"
config S3C2410_BOOT_WATCHDOG
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 3e5712db6b5..5e09355cd4f 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -24,6 +24,11 @@ obj-$(CONFIG_S3C2410_DMA) += dma.o
obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
+# S3C244X support
+
+obj-$(CONFIG_CPU_S3C244X) += s3c244x.o
+obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o
+
# S3C2440 support
obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o
@@ -31,6 +36,11 @@ obj-$(CONFIG_CPU_S3C2440) += s3c2440-irq.o
obj-$(CONFIG_CPU_S3C2440) += s3c2440-clock.o
obj-$(CONFIG_CPU_S3C2440) += s3c2410-gpio.o
+# S3C2442 support
+
+obj-$(CONFIG_CPU_S3C2442) += s3c2442.o
+obj-$(CONFIG_CPU_S3C2442) += s3c2442-clock.o
+
# bast extras
obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index 6de713ad319..99d174612b5 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)
clkcon &= ~clocks;
/* ensure none of the special function bits set */
- clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
+ clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER | 3);
__raw_writel(clkcon, S3C2410_CLKCON);
}
diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c
index acc58adfbd2..52842e6e86e 100644
--- a/arch/arm/mach-s3c2410/cpu.c
+++ b/arch/arm/mach-s3c2410/cpu.c
@@ -44,7 +44,9 @@
#include "clock.h"
#include "s3c2400.h"
#include "s3c2410.h"
+#include "s3c244x.h"
#include "s3c2440.h"
+#include "s3c2442.h"
struct cpu_table {
unsigned long idcode;
@@ -61,6 +63,7 @@ struct cpu_table {
static const char name_s3c2400[] = "S3C2400";
static const char name_s3c2410[] = "S3C2410";
static const char name_s3c2440[] = "S3C2440";
+static const char name_s3c2442[] = "S3C2442";
static const char name_s3c2410a[] = "S3C2410A";
static const char name_s3c2440a[] = "S3C2440A";
@@ -86,22 +89,31 @@ static struct cpu_table cpu_ids[] __initdata = {
{
.idcode = 0x32440000,
.idmask = 0xffffffff,
- .map_io = s3c2440_map_io,
- .init_clocks = s3c2440_init_clocks,
- .init_uarts = s3c2440_init_uarts,
+ .map_io = s3c244x_map_io,
+ .init_clocks = s3c244x_init_clocks,
+ .init_uarts = s3c244x_init_uarts,
.init = s3c2440_init,
.name = name_s3c2440
},
{
.idcode = 0x32440001,
.idmask = 0xffffffff,
- .map_io = s3c2440_map_io,
- .init_clocks = s3c2440_init_clocks,
- .init_uarts = s3c2440_init_uarts,
+ .map_io = s3c244x_map_io,
+ .init_clocks = s3c244x_init_clocks,
+ .init_uarts = s3c244x_init_uarts,
.init = s3c2440_init,
.name = name_s3c2440a
},
{
+ .idcode = 0x32440aaa,
+ .idmask = 0xffffffff,
+ .map_io = s3c244x_map_io,
+ .init_clocks = s3c244x_init_clocks,
+ .init_uarts = s3c244x_init_uarts,
+ .init = s3c2442_init,
+ .name = name_s3c2442
+ },
+ {
.idcode = 0x0, /* S3C2400 doesn't have an idcode */
.idmask = 0xffffffff,
.map_io = s3c2400_map_io,
diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h
index 0c776acb063..40862899b2f 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;
/* system device classes */
extern struct sysdev_class s3c2440_sysclass;
+extern struct sysdev_class s3c2442_sysclass;
diff --git a/arch/arm/mach-s3c2410/s3c2440-irq.c b/arch/arm/mach-s3c2410/s3c2440-irq.c
index 278d0044c85..acfe3870727 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 = {
.ack = s3c_irq_wdtac97_ack,
};
-/* camera irq */
-
-static void s3c_irq_demux_cam(unsigned int irq,
- struct irqdesc *desc,
- struct pt_regs *regs)
-{
- unsigned int subsrc, submsk;
- struct irqdesc *mydesc;
-
- /* read the current pending interrupts, and the mask
- * for what it is available */
-
- subsrc = __raw_readl(S3C2410_SUBSRCPND);
- submsk = __raw_readl(S3C2410_INTSUBMSK);
-
- subsrc &= ~submsk;
- subsrc >>= 11;
- subsrc &= 3;
-
- if (subsrc != 0) {
- if (subsrc & 1) {
- mydesc = irq_desc + IRQ_S3C2440_CAM_C;
- desc_handle_irq(IRQ_S3C2440_CAM_C, mydesc, regs);
- }
- if (subsrc & 2) {
- mydesc = irq_desc + IRQ_S3C2440_CAM_P;
- desc_handle_irq(IRQ_S3C2440_CAM_P, mydesc, regs);
- }
- }
-}
-
-#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
-
-static void
-s3c_irq_cam_mask(unsigned int irqno)
-{
- s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11);
-}
-
-static void
-s3c_irq_cam_unmask(unsigned int irqno)
-{
- s3c_irqsub_unmask(irqno, INTMSK_CAM);
-}
-
-static void
-s3c_irq_cam_ack(unsigned int irqno)
-{
- s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11);
-}
-
-static struct irqchip s3c_irq_cam = {
- .mask = s3c_irq_cam_mask,
- .unmask = s3c_irq_cam_unmask,
- .ack = s3c_irq_cam_ack,
-};
-
static int s3c2440_irq_add(struct sys_device *sysdev)
{
unsigned int irqno;
printk("S3C2440: IRQ Support\n");
- set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip);
- set_irq_handler(IRQ_NFCON, do_level_IRQ);
- set_irq_flags(IRQ_NFCON, IRQF_VALID);
-
/* add new chained handler for wdt, ac7 */
set_irq_chip(IRQ_WDT, &s3c_irq_level_chip);
@@ -179,18 +118,6 @@ static int s3c2440_irq_add(struct sys_device *sysdev)
set_irq_flags(irqno, IRQF_VALID);
}
- /* add chained handler for camera */
-
- set_irq_chip(IRQ_CAM, &s3c_irq_level_chip);
- set_irq_handler(IRQ_CAM, do_level_IRQ);
- set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam);
-
- for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) {
- set_irq_chip(irqno, &s3c_irq_cam);
- set_irq_handler(irqno, do_level_IRQ);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
return 0;
}
@@ -198,10 +125,10 @@ static struct sysdev_driver s3c2440_irq_driver = {
.add = s3c2440_irq_add,
};
-static int s3c24xx_irq_driver(void)
+static int s3c2440_irq_init(void)
{
return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver);
}
-arch_initcall(s3c24xx_irq_driver);
+arch_initcall(s3c2440_irq_init);
diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c
index 54681740f9f..0ab50f44f31 100644
--- a/arch/arm/mach-s3c2410/s3c2440.c
+++ b/arch/arm/mach-s3c2410/s3c2440.c
@@ -1,6 +1,6 @@
/* linux/arch/arm/mach-s3c2410/s3c2440.c
*
- * Copyright (c) 2004-2005 Simtec Electronics
+ * Copyright (c) 2004-2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* Samsung S3C2440 Mobile CPU support
@@ -8,16 +8,6 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
- * Modifications:
- * 24-Aug-2004 BJD Start of s3c2440 support
- * 12-Oct-2004 BJD Moved clock info out to clock.c
- * 01-Nov-2004 BJD Fixed clock build code
- * 09-Nov-2004 BJD Added sysdev for power management
- * 04-Nov-2004 BJD New serial registration
- * 15-Nov-2004 BJD Rename the i2c device for the s3c2440
- * 14-Jan-2005 BJD Moved clock init code into seperate function
- * 14-Jan-2005 BJD Removed un-used clock bits
*/
#include <linux/kernel.h>
@@ -50,144 +40,20 @@
#include "cpu.h"
#include "pm.h"
-
-static struct map_desc s3c2440_iodesc[] __initdata = {
- IODESC_ENT(USBHOST),
- IODESC_ENT(CLKPWR),
- IODESC_ENT(LCD),
- IODESC_ENT(TIMER),
- IODESC_ENT(ADC),
- IODESC_ENT(WATCHDOG),
-};
-
-/* uart initialisation */
-
-void __init s3c2440_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
- s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
-}
-
-#ifdef CONFIG_PM
-
-static struct sleep_save s3c2440_sleep[] = {
- SAVE_ITEM(S3C2440_DSC0),
- SAVE_ITEM(S3C2440_DSC1),
- SAVE_ITEM(S3C2440_GPJDAT),
- SAVE_ITEM(S3C2440_GPJCON),
- SAVE_ITEM(S3C2440_GPJUP)
-};
-
-static int s3c2440_suspend(struct sys_device *dev, pm_message_t state)
-{
- s3c2410_pm_do_save(s3c2440_sleep, ARRAY_SIZE(s3c2440_sleep));
- return 0;
-}
-
-static int s3c2440_resume(struct sys_device *dev)
-{
- s3c2410_pm_do_restore(s3c2440_sleep, ARRAY_SIZE(s3c2440_sleep));
- return 0;
-}
-
-#else
-#define s3c2440_suspend NULL
-#define s3c2440_resume NULL
-#endif
-
-struct sysdev_class s3c2440_sysclass = {
- set_kset_name("s3c2440-core"),
- .suspend = s3c2440_suspend,
- .resume = s3c2440_resume
-};
-
static struct sys_device s3c2440_sysdev = {
.cls = &s3c2440_sysclass,
};
-void __init s3c2440_map_io(struct map_desc *mach_desc, int size)
+int __init s3c2440_init(void)
{
- /* register our io-tables */
-
- iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc));
- iotable_init(mach_desc, size);
-
- /* rename any peripherals used differing from the s3c2410 */
-
- s3c_device_i2c.name = "s3c2440-i2c";
- s3c_device_nand.name = "s3c2440-nand";
+ printk("S3C2440: Initialising architecture\n");
/* change irq for watchdog */
s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT;
-}
-void __init s3c2440_init_clocks(int xtal)
-{
- unsigned long clkdiv;
- unsigned long camdiv;
- unsigned long hclk, fclk, pclk;
- int hdiv = 1;
-
- /* now we've got our machine bits initialised, work out what
- * clocks we've got */
-
- fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
-
- clkdiv = __raw_readl(S3C2410_CLKDIVN);
- camdiv = __raw_readl(S3C2440_CAMDIVN);
-
- /* work out clock scalings */
-
- switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
- case S3C2440_CLKDIVN_HDIVN_1:
- hdiv = 1;
- break;
-
- case S3C2440_CLKDIVN_HDIVN_2:
- hdiv = 2;
- break;
-
- case S3C2440_CLKDIVN_HDIVN_4_8:
- hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
- break;
-
- case S3C2440_CLKDIVN_HDIVN_3_6:
- hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
- break;
- }
-
- hclk = fclk / hdiv;
- pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
-
- /* print brief summary of clocks, etc */
-
- printk("S3C2440: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
- print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
-
- /* initialise the clocks here, to allow other things like the
- * console to use them, and to add new ones after the initialisation
- */
-
- s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
-}
-
-/* need to register class before we actually register the device, and
- * we also need to ensure that it has been initialised before any of the
- * drivers even try to use it (even if not on an s3c2440 based system)
- * as a driver which may support both 2410 and 2440 may try and use it.
-*/
-
-static int __init s3c2440_core_init(void)
-{
- return sysdev_class_register(&s3c2440_sysclass);
-}
-
-core_initcall(s3c2440_core_init);
-
-int __init s3c2440_init(void)
-{
- printk("S3C2440: Initialising architecture\n");
+ /* register our system device for everything else */
return sysdev_register(&s3c2440_sysdev);
}
diff --git a/arch/arm/mach-s3c2410/s3c2442-clock.c b/arch/arm/mach-s3c2410/s3c2442-clock.c
new file mode 100644
index 00000000000..5b7b301eb52
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2442-clock.c
@@ -0,0 +1,171 @@
+/* linux/arch/arm/mach-s3c2410/s3c2442-clock.c
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2442 Clock support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+
+#include <asm/hardware.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-clock.h>
+
+#include "clock.h"
+#include "cpu.h"
+
+/* S3C2442 extended clock support */
+
+static unsigned long s3c2442_camif_upll_round(struct clk *clk,
+ unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ int div;
+
+ if (rate > parent_rate)
+ return parent_rate;
+
+ div = parent_rate / rate;
+
+ if (div == 3)
+ return parent_rate / 3;
+
+ /* note, we remove the +/- 1 calculations for the divisor */
+
+ div /= 2;
+
+ if (div < 1)
+ div = 1;
+ else if (div > 16)
+ div = 16;
+
+ return parent_rate / (div * 2);
+}
+
+static int s3c2442_camif_upll_setrate(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
+
+ rate = s3c2442_camif_upll_round(clk, rate);
+
+ camdivn &= ~S3C2442_CAMDIVN_CAMCLK_DIV3;
+
+ if (rate == parent_rate) {
+ camdivn &= ~S3C2440_CAMDIVN_CAMCLK_SEL;
+ } else if ((parent_rate / rate) == 3) {
+ camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL;
+ camdivn |= S3C2442_CAMDIVN_CAMCLK_DIV3;
+ } else {
+ camdivn &= ~S3C2440_CAMDIVN_CAMCLK_MASK;
+ camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL;
+ camdivn |= (((parent_rate / rate) / 2) - 1);
+ }
+
+ __raw_writel(camdivn, S3C2440_CAMDIVN);
+
+ return 0;
+}
+
+/* Extra S3C2442 clocks */
+
+static struct clk s3c2442_clk_cam = {
+ .name = "camif",
+ .id = -1,
+ .enable = s3c24xx_clkcon_enable,
+ .ctrlbit = S3C2440_CLKCON_CAMERA,
+};
+
+static struct clk s3c2442_clk_cam_upll = {
+ .name = "camif-upll",
+ .id = -1,
+ .set_rate = s3c2442_camif_upll_setrate,
+ .round_rate = s3c2442_camif_upll_round,
+};
+
+static int s3c2442_clk_add(struct sys_device *sysdev)
+{
+ unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
+ unsigned long clkdivn;
+ struct clk *clk_h;
+ struct clk *clk_p;
+ struct clk *clk_upll;
+
+ printk("S3C2442: Clock Support, DVS %s\n",
+ (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
+
+ clk_p = clk_get(NULL, "pclk");
+ clk_h = clk_get(NULL, "hclk");
+ clk_upll = clk_get(NULL, "upll");
+
+ if (IS_ERR(clk_p) || IS_ERR(clk_h) || IS_ERR(clk_upll)) {
+ printk(KERN_ERR "S3C2442: Failed to get parent clocks\n");
+ return -EINVAL;
+ }
+
+ /* check rate of UPLL, and if it is near 96MHz, then change
+ * to using half the UPLL rate for the system */
+
+ if (clk_get_rate(clk_upll) > (94 * MHZ)) {
+ clk_usb_bus.rate = clk_get_rate(clk_upll) / 2;
+
+ mutex_lock(&clocks_mutex);
+
+ clkdivn = __raw_readl(S3C2410_CLKDIVN);
+ clkdivn |= S3C2440_CLKDIVN_UCLK;
+ __raw_writel(clkdivn, S3C2410_CLKDIVN);
+
+ mutex_unlock(&clocks_mutex);
+ }
+
+ s3c2442_clk_cam.parent = clk_h;
+ s3c2442_clk_cam_upll.parent = clk_upll;
+
+ s3c24xx_register_clock(&s3c2442_clk_cam);
+ s3c24xx_register_clock(&s3c2442_clk_cam_upll);
+
+ clk_disable(&s3c2442_clk_cam);
+
+ return 0;
+}
+
+static struct sysdev_driver s3c2442_clk_driver = {
+ .add = s3c2442_clk_add,
+};
+
+static __init int s3c2442_clk_init(void)
+{
+ return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_clk_driver);
+}
+
+arch_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 00000000000..debae243055
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2442.c
@@ -0,0 +1,52 @@
+/* linux/arch/arm/mach-s3c2410/s3c2440.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C2442 Mobile CPU support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/clk.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-gpioj.h>
+#include <asm/arch/regs-dsc.h>
+
+#include "s3c2442.h"
+#include "clock.h"
+#include "devs.h"
+#include "cpu.h"
+#include "pm.h"
+
+static struct sys_device s3c2442_sysdev = {
+ .cls = &s3c2442_sysclass,
+};
+
+int __init s3c2442_init(void)
+{
+ printk("S3C2442: Initialising architecture\n");
+
+ return sysdev_register(&s3c2442_sysdev);
+}
diff --git a/arch/arm/mach-s3c2410/s3c2442.h b/arch/arm/mach-s3c2410/s3c2442.h
new file mode 100644
index 00000000000..0ae37d24866
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2442.h
@@ -0,0 +1,17 @@
+/* arch/arm/mach-s3c2410/s3c2442.h
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Header file for s3c2442 cpu support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifdef CONFIG_CPU_S3C2442
+extern int s3c2442_init(void);
+#else
+#define s3c2442_init NULL
+#endif
diff --git a/arch/arm/mach-s3c2410/s3c244x-irq.c b/arch/arm/mach-s3c2410/s3c244x-irq.c
new file mode 100644
index 00000000000..2aadca1ce7e
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c244x-irq.c
@@ -0,0 +1,142 @@
+/* linux/arch/arm/mach-s3c2410/s3c2440-irq.c
+ *
+ * Copyright (c) 2003,2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Changelog:
+ * 25-Jul-2005 BJD Split from irq.c
+ *
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/ptrace.h>
+#include <linux/sysdev.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/mach/irq.h>
+
+#include <asm/arch/regs-irq.h>
+#include <asm/arch/regs-gpio.h>
+
+#include "cpu.h"
+#include "pm.h"
+#include "irq.h"
+
+/* camera irq */
+
+static void s3c_irq_demux_cam(unsigned int irq,
+ struct irqdesc *desc,
+ struct pt_regs *regs)
+{
+ unsigned int subsrc, submsk;
+ struct irqdesc *mydesc;
+
+ /* read the current pending interrupts, and the mask
+ * for what it is available */
+
+ subsrc = __raw_readl(S3C2410_SUBSRCPND);
+ submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+ subsrc &= ~submsk;
+ subsrc >>= 11;
+ subsrc &= 3;
+
+ if (subsrc != 0) {
+ if (subsrc & 1) {
+ mydesc = irq_desc + IRQ_S3C2440_CAM_C;
+ desc_handle_irq(IRQ_S3C2440_CAM_C, mydesc, regs);
+ }
+ if (subsrc & 2) {
+ mydesc = irq_desc + IRQ_S3C2440_CAM_P;
+ desc_handle_irq(IRQ_S3C2440_CAM_P, mydesc, regs);
+ }
+ }
+}
+
+#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
+
+static void
+s3c_irq_cam_mask(unsigned int irqno)
+{
+ s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11);
+}
+
+static void
+s3c_irq_cam_unmask(unsigned int irqno)
+{
+ s3c_irqsub_unmask(irqno, INTMSK_CAM);
+}
+
+static void
+s3c_irq_cam_ack(unsigned int irqno)
+{
+ s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11);
+}
+
+static struct irqchip s3c_irq_cam = {
+ .mask = s3c_irq_cam_mask,
+ .unmask = s3c_irq_cam_unmask,
+ .ack = s3c_irq_cam_ack,
+};
+
+static int s3c244x_irq_add(struct sys_device *sysdev)
+{
+ unsigned int irqno;
+
+ set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip);
+ set_irq_handler(IRQ_NFCON, do_level_IRQ);
+ set_irq_flags(IRQ_NFCON, IRQF_VALID);
+
+ /* add chained handler for camera */
+
+ set_irq_chip(IRQ_CAM, &s3c_irq_level_chip);
+ set_irq_handler(IRQ_CAM, do_level_IRQ);
+ set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam);
+
+ for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) {
+ set_irq_chip(irqno, &s3c_irq_cam);
+ set_irq_handler(irqno, do_level_IRQ);
+ set_irq_flags(irqno, IRQF_VALID);
+ }
+
+ return 0;
+}
+
+static struct sysdev_driver s3c244x_irq_driver = {
+ .add = s3c244x_irq_add,
+};
+
+static int s3c2440_irq_init(void)
+{
+ return sysdev_driver_register(&s3c2440_sysclass, &s3c244x_irq_driver);
+}
+
+arch_initcall(s3c2440_irq_init);
+
+
+static int s3c2442_irq_init(void)
+{
+ return sysdev_driver_register(&s3c2442_sysclass, &s3c244x_irq_driver);
+}
+
+arch_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 00000000000..96852a7000d
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c244x.c
@@ -0,0 +1,182 @@
+/* linux/arch/arm/mach-s3c2410/s3c244x.c
+ *
+ * Copyright (c) 2004-2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C2440 and S3C2442 Mobile CPU support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/clk.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-gpioj.h>
+#include <asm/arch/regs-dsc.h>
+
+#include "s3c2440.h"
+#include "s3c244x.h"
+#include "clock.h"
+#include "devs.h"
+#include "cpu.h"
+#include "pm.h"
+
+static struct map_desc s3c244x_iodesc[] __initdata = {
+ IODESC_ENT(CLKPWR),
+ IODESC_ENT(TIMER),
+ IODESC_ENT(WATCHDOG),
+ IODESC_ENT(LCD),
+ IODESC_ENT(ADC),
+ IODESC_ENT(USBHOST),
+};
+
+/* uart initialisation */
+
+void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+ s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
+}
+
+void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
+{
+ /* register our io-tables */
+
+ iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
+ iotable_init(mach_desc, size);
+
+ /* rename any peripherals used differing from the s3c2410 */
+
+ s3c_device_i2c.name = "s3c2440-i2c";
+ s3c_device_nand.name = "s3c2440-nand";
+}
+
+void __init s3c244x_init_clocks(int xtal)
+{
+ unsigned long clkdiv;
+ unsigned long camdiv;
+ unsigned long hclk, fclk, pclk;
+ int hdiv = 1;
+
+ /* now we've got our machine bits initialised, work out what
+ * clocks we've got */
+
+ fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
+
+ clkdiv = __raw_readl(S3C2410_CLKDIVN);
+ camdiv = __raw_readl(S3C2440_CAMDIVN);
+
+ /* work out clock scalings */
+
+ switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
+ case S3C2440_CLKDIVN_HDIVN_1:
+ hdiv = 1;
+ break;
+
+ case S3C2440_CLKDIVN_HDIVN_2:
+ hdiv = 2;
+ break;
+
+ case S3C2440_CLKDIVN_HDIVN_4_8:
+ hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
+ break;
+
+ case S3C2440_CLKDIVN_HDIVN_3_6:
+ hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
+ break;
+ }
+
+ hclk = fclk / hdiv;
+ pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
+
+ /* print brief summary of clocks, etc */
+
+ printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
+ print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
+
+ /* initialise the clocks here, to allow other things like the
+ * console to use them, and to add new ones after the initialisation
+ */
+
+ s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+}
+
+#ifdef CONFIG_PM
+
+static struct sleep_save s3c244x_sleep[] = {
+ SAVE_ITEM(S3C2440_DSC0),
+ SAVE_ITEM(S3C2440_DSC1),
+ SAVE_ITEM(S3C2440_GPJDAT),
+ SAVE_ITEM(S3C2440_GPJCON),
+ SAVE_ITEM(S3C2440_GPJUP)
+};
+
+static int s3c244x_suspend(struct sys_device *dev, pm_message_t state)
+{
+ s3c2410_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
+ return 0;
+}
+
+static int s3c244x_resume(struct sys_device *dev)
+{
+ s3c2410_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
+ return 0;
+}
+
+#else
+#define s3c244x_suspend NULL
+#define s3c244x_resume NULL
+#endif
+
+/* Since the S3C2442 and S3C2440 share items, put both sysclasses here */
+
+struct sysdev_class s3c2440_sysclass = {
+ set_kset_name("s3c2440-core"),
+ .suspend = s3c244x_suspend,
+ .resume = s3c244x_resume
+};
+
+struct sysdev_class s3c2442_sysclass = {
+ set_kset_name("s3c2442-core"),
+ .suspend = s3c244x_suspend,
+ .resume = s3c244x_resume
+};
+
+/* need to register class before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2440 based system)
+ * as a driver which may support both 2410 and 2440 may try and use it.
+*/
+
+static int __init s3c2440_core_init(void)
+{
+ return sysdev_class_register(&s3c2440_sysclass);
+}
+
+core_initcall(s3c2440_core_init);
+
+static int __init s3c2442_core_init(void)
+{
+ return sysdev_class_register(&s3c2442_sysclass);
+}
+
+core_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 00000000000..3e7f5f75134
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c244x.h
@@ -0,0 +1,25 @@
+/* arch/arm/mach-s3c2410/s3c2440.h
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Header file for S3C2440 and S3C2442 cpu support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
+
+extern void s3c244x_map_io(struct map_desc *mach_desc, int size);
+
+extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no);
+
+extern void s3c244x_init_clocks(int xtal);
+
+#else
+#define s3c244x_init_clocks NULL
+#define s3c244x_init_uarts NULL
+#define s3c244x_map_io NULL
+#endif