aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c2440
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s3c2440')
-rw-r--r--arch/arm/mach-s3c2440/Kconfig90
-rw-r--r--arch/arm/mach-s3c2440/Makefile15
-rw-r--r--arch/arm/mach-s3c2440/clock.c6
-rw-r--r--arch/arm/mach-s3c2440/dma.c2
-rw-r--r--arch/arm/mach-s3c2440/dsc.c2
-rw-r--r--arch/arm/mach-s3c2440/include/mach/gta02.h84
-rw-r--r--arch/arm/mach-s3c2440/irq.c2
-rw-r--r--arch/arm/mach-s3c2440/mach-anubis.c31
-rw-r--r--arch/arm/mach-s3c2440/mach-at2440evb.c16
-rw-r--r--arch/arm/mach-s3c2440/mach-gta02.c647
-rw-r--r--arch/arm/mach-s3c2440/mach-mini2440.c48
-rw-r--r--arch/arm/mach-s3c2440/mach-nexcoder.c4
-rw-r--r--arch/arm/mach-s3c2440/mach-osiris-dvs.c194
-rw-r--r--arch/arm/mach-s3c2440/mach-osiris.c49
-rw-r--r--arch/arm/mach-s3c2440/mach-rx3715.c13
-rw-r--r--arch/arm/mach-s3c2440/mach-smdk2440.c6
-rw-r--r--arch/arm/mach-s3c2440/s3c2440-cpufreq.c311
-rw-r--r--arch/arm/mach-s3c2440/s3c2440-pll-12000000.c97
-rw-r--r--arch/arm/mach-s3c2440/s3c2440-pll-16934400.c127
-rw-r--r--arch/arm/mach-s3c2440/s3c2440.c2
-rw-r--r--arch/arm/mach-s3c2440/s3c2442.c165
-rw-r--r--arch/arm/mach-s3c2440/s3c244x-clock.c138
-rw-r--r--arch/arm/mach-s3c2440/s3c244x-irq.c142
-rw-r--r--arch/arm/mach-s3c2440/s3c244x.c195
24 files changed, 2312 insertions, 74 deletions
diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig
index a8b69d77571b..7f465265cf04 100644
--- a/arch/arm/mach-s3c2440/Kconfig
+++ b/arch/arm/mach-s3c2440/Kconfig
@@ -1,5 +1,3 @@
1# arch/arm/mach-s3c2440/Kconfig
2#
3# Copyright 2007 Simtec Electronics 1# Copyright 2007 Simtec Electronics
4# 2#
5# Licensed under GPLv2 3# Licensed under GPLv2
@@ -17,14 +15,67 @@ config CPU_S3C2440
17 help 15 help
18 Support for S3C2440 Samsung Mobile CPU based systems. 16 Support for S3C2440 Samsung Mobile CPU based systems.
19 17
18config CPU_S3C2442
19 bool
20 depends on ARCH_S3C2410
21 select CPU_ARM920T
22 select S3C2410_CLOCK
23 select S3C2410_GPIO
24 select S3C2410_PM if PM
25 select CPU_S3C244X
26 select CPU_LLSERIAL_S3C2440
27 help
28 Support for S3C2442 Samsung Mobile CPU based systems.
29
30config CPU_S3C244X
31 bool
32 depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
33 help
34 Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems.
35
36
37
38config S3C2440_CPUFREQ
39 bool "S3C2440/S3C2442 CPU Frequency scaling support"
40 depends on CPU_FREQ_S3C24XX && (CPU_S3C2440 || CPU_S3C2442)
41 select S3C2410_CPUFREQ_UTILS
42 default y
43 help
44 CPU Frequency scaling support for S3C2440 and S3C2442 SoC CPUs.
45
46config S3C2440_XTAL_12000000
47 bool
48 help
49 Indicate that the build needs to support 12MHz system
50 crystal.
51
52config S3C2440_XTAL_16934400
53 bool
54 help
55 Indicate that the build needs to support 16.9344MHz system
56 crystal.
57
58config S3C2440_PLL_12000000
59 bool
60 depends on S3C2440_CPUFREQ && S3C2440_XTAL_12000000
61 default y if CPU_FREQ_S3C24XX_PLL
62 help
63 PLL tables for S3C2440 or S3C2442 CPUs with 12MHz crystals.
64
65config S3C2440_PLL_16934400
66 bool
67 depends on S3C2440_CPUFREQ && S3C2440_XTAL_16934400
68 default y if CPU_FREQ_S3C24XX_PLL
69 help
70 PLL tables for S3C2440 or S3C2442 CPUs with 16.934MHz crystals.
71
20config S3C2440_DMA 72config S3C2440_DMA
21 bool 73 bool
22 depends on ARCH_S3C2410 && CPU_S3C24405B 74 depends on ARCH_S3C2410 && CPU_S3C24405B
23 help 75 help
24 Support for S3C2440 specific DMA code5A 76 Support for S3C2440 specific DMA code5A
25 77
26 78menu "S3C2440 and S3C2442 Machines"
27menu "S3C2440 Machines"
28 79
29config MACH_ANUBIS 80config MACH_ANUBIS
30 bool "Simtec Electronics ANUBIS" 81 bool "Simtec Electronics ANUBIS"
@@ -39,6 +90,18 @@ config MACH_ANUBIS
39 Say Y here if you are using the Simtec Electronics ANUBIS 90 Say Y here if you are using the Simtec Electronics ANUBIS
40 development system 91 development system
41 92
93config MACH_NEO1973_GTA02
94 bool "Openmoko GTA02 / Freerunner phone"
95 select CPU_S3C2442
96 select MFD_PCF50633
97 select PCF50633_GPIO
98 select I2C
99 select POWER_SUPPLY
100 select MACH_NEO1973
101 select S3C2410_PWM
102 help
103 Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone
104
42config MACH_OSIRIS 105config MACH_OSIRIS
43 bool "Simtec IM2440D20 (OSIRIS) module" 106 bool "Simtec IM2440D20 (OSIRIS) module"
44 select CPU_S3C2440 107 select CPU_S3C2440
@@ -53,6 +116,19 @@ config MACH_OSIRIS
53 Say Y here if you are using the Simtec IM2440D20 module, also 116 Say Y here if you are using the Simtec IM2440D20 module, also
54 known as the Osiris. 117 known as the Osiris.
55 118
119config MACH_OSIRIS_DVS
120 tristate "Simtec IM2440D20 (OSIRIS) Dynamic Voltage Scaling driver"
121 depends on MACH_OSIRIS
122 select TPS65010
123 help
124 Say Y/M here if you want to have dynamic voltage scaling support
125 on the Simtec IM2440D20 (OSIRIS) module via the TPS65011.
126
127 The DVS driver alters the voltage supplied to the ARM core
128 depending on the frequency it is running at. The driver itself
129 does not do any of the frequency alteration, which is left up
130 to the cpufreq driver.
131
56config MACH_RX3715 132config MACH_RX3715
57 bool "HP iPAQ rx3715" 133 bool "HP iPAQ rx3715"
58 select CPU_S3C2440 134 select CPU_S3C2440
@@ -83,11 +159,14 @@ config MACH_NEXCODER_2440
83 159
84config SMDK2440_CPU2440 160config SMDK2440_CPU2440
85 bool "SMDK2440 with S3C2440 CPU module" 161 bool "SMDK2440 with S3C2440 CPU module"
86 depends on ARCH_S3C2440
87 default y if ARCH_S3C2440 162 default y if ARCH_S3C2440
88 select S3C2440_XTAL_16934400 163 select S3C2440_XTAL_16934400
89 select CPU_S3C2440 164 select CPU_S3C2440
90 165
166config SMDK2440_CPU2442
167 bool "SMDM2440 with S3C2442 CPU module"
168 select CPU_S3C2442
169
91config MACH_AT2440EVB 170config MACH_AT2440EVB
92 bool "Avantech AT2440EVB development board" 171 bool "Avantech AT2440EVB development board"
93 select CPU_S3C2440 172 select CPU_S3C2440
@@ -109,4 +188,3 @@ config MACH_MINI2440
109 available via various sources. It can come with a 3.5" or 7" touch LCD. 188 available via various sources. It can come with a 3.5" or 7" touch LCD.
110 189
111endmenu 190endmenu
112
diff --git a/arch/arm/mach-s3c2440/Makefile b/arch/arm/mach-s3c2440/Makefile
index bfadcf684a2a..c85ba32d8956 100644
--- a/arch/arm/mach-s3c2440/Makefile
+++ b/arch/arm/mach-s3c2440/Makefile
@@ -10,10 +10,20 @@ obj-n :=
10obj- := 10obj- :=
11 11
12obj-$(CONFIG_CPU_S3C2440) += s3c2440.o dsc.o 12obj-$(CONFIG_CPU_S3C2440) += s3c2440.o dsc.o
13obj-$(CONFIG_CPU_S3C2442) += s3c2442.o
14
13obj-$(CONFIG_CPU_S3C2440) += irq.o 15obj-$(CONFIG_CPU_S3C2440) += irq.o
14obj-$(CONFIG_CPU_S3C2440) += clock.o 16obj-$(CONFIG_CPU_S3C2440) += clock.o
15obj-$(CONFIG_S3C2440_DMA) += dma.o 17obj-$(CONFIG_S3C2440_DMA) += dma.o
16 18
19obj-$(CONFIG_CPU_S3C244X) += s3c244x.o
20obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o
21obj-$(CONFIG_CPU_S3C244X) += s3c244x-clock.o
22obj-$(CONFIG_S3C2440_CPUFREQ) += s3c2440-cpufreq.o
23
24obj-$(CONFIG_S3C2440_PLL_12000000) += s3c2440-pll-12000000.o
25obj-$(CONFIG_S3C2440_PLL_16934400) += s3c2440-pll-16934400.o
26
17# Machine support 27# Machine support
18 28
19obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o 29obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o
@@ -23,3 +33,8 @@ obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o
23obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o 33obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o
24obj-$(CONFIG_MACH_AT2440EVB) += mach-at2440evb.o 34obj-$(CONFIG_MACH_AT2440EVB) += mach-at2440evb.o
25obj-$(CONFIG_MACH_MINI2440) += mach-mini2440.o 35obj-$(CONFIG_MACH_MINI2440) += mach-mini2440.o
36obj-$(CONFIG_MACH_NEO1973_GTA02) += mach-gta02.o
37
38# extra machine support
39
40obj-$(CONFIG_MACH_OSIRIS_DVS) += mach-osiris-dvs.o
diff --git a/arch/arm/mach-s3c2440/clock.c b/arch/arm/mach-s3c2440/clock.c
index d1c29b2537cd..3dc2426e2345 100644
--- a/arch/arm/mach-s3c2440/clock.c
+++ b/arch/arm/mach-s3c2440/clock.c
@@ -98,8 +98,10 @@ static struct clk s3c2440_clk_cam = {
98static struct clk s3c2440_clk_cam_upll = { 98static struct clk s3c2440_clk_cam_upll = {
99 .name = "camif-upll", 99 .name = "camif-upll",
100 .id = -1, 100 .id = -1,
101 .set_rate = s3c2440_camif_upll_setrate, 101 .ops = &(struct clk_ops) {
102 .round_rate = s3c2440_camif_upll_round, 102 .set_rate = s3c2440_camif_upll_setrate,
103 .round_rate = s3c2440_camif_upll_round,
104 },
103}; 105};
104 106
105static struct clk s3c2440_clk_ac97 = { 107static struct clk s3c2440_clk_ac97 = {
diff --git a/arch/arm/mach-s3c2440/dma.c b/arch/arm/mach-s3c2440/dma.c
index e08e081430f0..3b0529f54e9c 100644
--- a/arch/arm/mach-s3c2440/dma.c
+++ b/arch/arm/mach-s3c2440/dma.c
@@ -20,7 +20,7 @@
20#include <mach/map.h> 20#include <mach/map.h>
21#include <mach/dma.h> 21#include <mach/dma.h>
22 22
23#include <plat/dma-plat.h> 23#include <plat/dma-s3c24xx.h>
24#include <plat/cpu.h> 24#include <plat/cpu.h>
25 25
26#include <plat/regs-serial.h> 26#include <plat/regs-serial.h>
diff --git a/arch/arm/mach-s3c2440/dsc.c b/arch/arm/mach-s3c2440/dsc.c
index 554044272771..9ea66e31f626 100644
--- a/arch/arm/mach-s3c2440/dsc.c
+++ b/arch/arm/mach-s3c2440/dsc.c
@@ -28,7 +28,7 @@
28#include <mach/regs-dsc.h> 28#include <mach/regs-dsc.h>
29 29
30#include <plat/cpu.h> 30#include <plat/cpu.h>
31#include <plat/s3c2440.h> 31#include <plat/s3c244x.h>
32 32
33int s3c2440_set_dsc(unsigned int pin, unsigned int value) 33int s3c2440_set_dsc(unsigned int pin, unsigned int value)
34{ 34{
diff --git a/arch/arm/mach-s3c2440/include/mach/gta02.h b/arch/arm/mach-s3c2440/include/mach/gta02.h
new file mode 100644
index 000000000000..953331d8d56a
--- /dev/null
+++ b/arch/arm/mach-s3c2440/include/mach/gta02.h
@@ -0,0 +1,84 @@
1#ifndef _GTA02_H
2#define _GTA02_H
3
4#include <mach/regs-gpio.h>
5
6/* Different hardware revisions, passed in ATAG_REVISION by u-boot */
7#define GTA02v1_SYSTEM_REV 0x00000310
8#define GTA02v2_SYSTEM_REV 0x00000320
9#define GTA02v3_SYSTEM_REV 0x00000330
10#define GTA02v4_SYSTEM_REV 0x00000340
11#define GTA02v5_SYSTEM_REV 0x00000350
12/* since A7 is basically same as A6, we use A6 PCB ID */
13#define GTA02v6_SYSTEM_REV 0x00000360
14
15#define GTA02_GPIO_n3DL_GSM S3C2410_GPA(13) /* v1 + v2 + v3 only */
16
17#define GTA02_GPIO_PWR_LED1 S3C2410_GPB(0)
18#define GTA02_GPIO_PWR_LED2 S3C2410_GPB(1)
19#define GTA02_GPIO_AUX_LED S3C2410_GPB(2)
20#define GTA02_GPIO_VIBRATOR_ON S3C2410_GPB(3)
21#define GTA02_GPIO_MODEM_RST S3C2410_GPB(5)
22#define GTA02_GPIO_BT_EN S3C2410_GPB(6)
23#define GTA02_GPIO_MODEM_ON S3C2410_GPB(7)
24#define GTA02_GPIO_EXTINT8 S3C2410_GPB(8)
25#define GTA02_GPIO_USB_PULLUP S3C2410_GPB(9)
26
27#define GTA02_GPIO_PIO5 S3C2410_GPC(5) /* v3 + v4 only */
28
29#define GTA02v3_GPIO_nG1_CS S3C2410_GPD(12) /* v3 + v4 only */
30#define GTA02v3_GPIO_nG2_CS S3C2410_GPD(13) /* v3 + v4 only */
31#define GTA02v5_GPIO_HDQ S3C2410_GPD(14) /* v5 + */
32
33#define GTA02_GPIO_nG1_INT S3C2410_GPF(0)
34#define GTA02_GPIO_IO1 S3C2410_GPF(1)
35#define GTA02_GPIO_PIO_2 S3C2410_GPF(2) /* v2 + v3 + v4 only */
36#define GTA02_GPIO_JACK_INSERT S3C2410_GPF(4)
37#define GTA02_GPIO_WLAN_GPIO1 S3C2410_GPF(5) /* v2 + v3 + v4 only */
38#define GTA02_GPIO_AUX_KEY S3C2410_GPF(6)
39#define GTA02_GPIO_HOLD_KEY S3C2410_GPF(7)
40
41#define GTA02_GPIO_3D_IRQ S3C2410_GPG(4)
42#define GTA02v2_GPIO_nG2_INT S3C2410_GPG(8) /* v2 + v3 + v4 only */
43#define GTA02v3_GPIO_nUSB_OC S3C2410_GPG(9) /* v3 + v4 only */
44#define GTA02v3_GPIO_nUSB_FLT S3C2410_GPG(10) /* v3 + v4 only */
45#define GTA02v3_GPIO_nGSM_OC S3C2410_GPG(11) /* v3 + v4 only */
46
47#define GTA02_GPIO_AMP_SHUT S3C2440_GPJ1 /* v2 + v3 + v4 only */
48#define GTA02v1_GPIO_WLAN_GPIO10 S3C2440_GPJ2
49#define GTA02_GPIO_HP_IN S3C2440_GPJ2 /* v2 + v3 + v4 only */
50#define GTA02_GPIO_INT0 S3C2440_GPJ3 /* v2 + v3 + v4 only */
51#define GTA02_GPIO_nGSM_EN S3C2440_GPJ4
52#define GTA02_GPIO_3D_RESET S3C2440_GPJ5
53#define GTA02_GPIO_nDL_GSM S3C2440_GPJ6 /* v4 + v5 only */
54#define GTA02_GPIO_WLAN_GPIO0 S3C2440_GPJ7
55#define GTA02v1_GPIO_BAT_ID S3C2440_GPJ8
56#define GTA02_GPIO_KEEPACT S3C2440_GPJ8
57#define GTA02v1_GPIO_HP_IN S3C2440_GPJ10
58#define GTA02_CHIP_PWD S3C2440_GPJ11 /* v2 + v3 + v4 only */
59#define GTA02_GPIO_nWLAN_RESET S3C2440_GPJ12 /* v2 + v3 + v4 only */
60
61#define GTA02_IRQ_GSENSOR_1 IRQ_EINT0
62#define GTA02_IRQ_MODEM IRQ_EINT1
63#define GTA02_IRQ_PIO_2 IRQ_EINT2 /* v2 + v3 + v4 only */
64#define GTA02_IRQ_nJACK_INSERT IRQ_EINT4
65#define GTA02_IRQ_WLAN_GPIO1 IRQ_EINT5
66#define GTA02_IRQ_AUX IRQ_EINT6
67#define GTA02_IRQ_nHOLD IRQ_EINT7
68#define GTA02_IRQ_PCF50633 IRQ_EINT9
69#define GTA02_IRQ_3D IRQ_EINT12
70#define GTA02_IRQ_GSENSOR_2 IRQ_EINT16 /* v2 + v3 + v4 only */
71#define GTA02v3_IRQ_nUSB_OC IRQ_EINT17 /* v3 + v4 only */
72#define GTA02v3_IRQ_nUSB_FLT IRQ_EINT18 /* v3 + v4 only */
73#define GTA02v3_IRQ_nGSM_OC IRQ_EINT19 /* v3 + v4 only */
74
75/* returns 00 000 on GTA02 A5 and earlier, A6 returns 01 001 */
76#define GTA02_PCB_ID1_0 S3C2410_GPC(13)
77#define GTA02_PCB_ID1_1 S3C2410_GPC(15)
78#define GTA02_PCB_ID1_2 S3C2410_GPD(0)
79#define GTA02_PCB_ID2_0 S3C2410_GPD(3)
80#define GTA02_PCB_ID2_1 S3C2410_GPD(4)
81
82int gta02_get_pcb_revision(void);
83
84#endif /* _GTA02_H */
diff --git a/arch/arm/mach-s3c2440/irq.c b/arch/arm/mach-s3c2440/irq.c
index 63c5ab65727f..0c049b95c378 100644
--- a/arch/arm/mach-s3c2440/irq.c
+++ b/arch/arm/mach-s3c2440/irq.c
@@ -1,6 +1,6 @@
1/* linux/arch/arm/mach-s3c2440/irq.c 1/* linux/arch/arm/mach-s3c2440/irq.c
2 * 2 *
3 * Copyright (c) 2003,2004 Simtec Electronics 3 * Copyright (c) 2003-2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
diff --git a/arch/arm/mach-s3c2440/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c
index 68f3870991bf..b73f78a9da5c 100644
--- a/arch/arm/mach-s3c2440/mach-anubis.c
+++ b/arch/arm/mach-s3c2440/mach-anubis.c
@@ -1,6 +1,6 @@
1/* linux/arch/arm/mach-s3c2440/mach-anubis.c 1/* linux/arch/arm/mach-s3c2440/mach-anubis.c
2 * 2 *
3 * Copyright (c) 2003-2005,2008 Simtec Electronics 3 * Copyright 2003-2009 Simtec Electronics
4 * http://armlinux.simtec.co.uk/ 4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk> 5 * Ben Dooks <ben@simtec.co.uk>
6 * 6 *
@@ -53,8 +53,9 @@
53#include <plat/clock.h> 53#include <plat/clock.h>
54#include <plat/devs.h> 54#include <plat/devs.h>
55#include <plat/cpu.h> 55#include <plat/cpu.h>
56#include <plat/audio-simtec.h>
56 57
57#define COPYRIGHT ", (c) 2005 Simtec Electronics" 58#define COPYRIGHT ", Copyright 2005-2009 Simtec Electronics"
58 59
59static struct map_desc anubis_iodesc[] __initdata = { 60static struct map_desc anubis_iodesc[] __initdata = {
60 /* ISA IO areas */ 61 /* ISA IO areas */
@@ -138,7 +139,7 @@ static int external_map[] = { 2 };
138static int chip0_map[] = { 0 }; 139static int chip0_map[] = { 0 };
139static int chip1_map[] = { 1 }; 140static int chip1_map[] = { 1 };
140 141
141static struct mtd_partition anubis_default_nand_part[] = { 142static struct mtd_partition __initdata anubis_default_nand_part[] = {
142 [0] = { 143 [0] = {
143 .name = "Boot Agent", 144 .name = "Boot Agent",
144 .size = SZ_16K, 145 .size = SZ_16K,
@@ -161,7 +162,7 @@ static struct mtd_partition anubis_default_nand_part[] = {
161 } 162 }
162}; 163};
163 164
164static struct mtd_partition anubis_default_nand_part_large[] = { 165static struct mtd_partition __initdata anubis_default_nand_part_large[] = {
165 [0] = { 166 [0] = {
166 .name = "Boot Agent", 167 .name = "Boot Agent",
167 .size = SZ_128K, 168 .size = SZ_128K,
@@ -191,7 +192,7 @@ static struct mtd_partition anubis_default_nand_part_large[] = {
191 * socket. 192 * socket.
192*/ 193*/
193 194
194static struct s3c2410_nand_set anubis_nand_sets[] = { 195static struct s3c2410_nand_set __initdata anubis_nand_sets[] = {
195 [1] = { 196 [1] = {
196 .name = "External", 197 .name = "External",
197 .nr_chips = 1, 198 .nr_chips = 1,
@@ -233,7 +234,7 @@ static void anubis_nand_select(struct s3c2410_nand_set *set, int slot)
233 __raw_writeb(tmp, ANUBIS_VA_CTRL1); 234 __raw_writeb(tmp, ANUBIS_VA_CTRL1);
234} 235}
235 236
236static struct s3c2410_platform_nand anubis_nand_info = { 237static struct s3c2410_platform_nand __initdata anubis_nand_info = {
237 .tacls = 25, 238 .tacls = 25,
238 .twrph0 = 55, 239 .twrph0 = 55,
239 .twrph1 = 40, 240 .twrph1 = 40,
@@ -408,7 +409,7 @@ static struct platform_device anubis_device_sm501 = {
408/* Standard Anubis devices */ 409/* Standard Anubis devices */
409 410
410static struct platform_device *anubis_devices[] __initdata = { 411static struct platform_device *anubis_devices[] __initdata = {
411 &s3c_device_usb, 412 &s3c_device_ohci,
412 &s3c_device_wdt, 413 &s3c_device_wdt,
413 &s3c_device_adc, 414 &s3c_device_adc,
414 &s3c_device_i2c0, 415 &s3c_device_i2c0,
@@ -437,6 +438,17 @@ static struct i2c_board_info anubis_i2c_devs[] __initdata = {
437 } 438 }
438}; 439};
439 440
441/* Audio setup */
442static struct s3c24xx_audio_simtec_pdata __initdata anubis_audio = {
443 .have_mic = 1,
444 .have_lout = 1,
445 .output_cdclk = 1,
446 .use_mpllin = 1,
447 .amp_gpio = S3C2410_GPB(2),
448 .amp_gain[0] = S3C2410_GPD(10),
449 .amp_gain[1] = S3C2410_GPD(11),
450};
451
440static void __init anubis_map_io(void) 452static void __init anubis_map_io(void)
441{ 453{
442 /* initialise the clocks */ 454 /* initialise the clocks */
@@ -454,8 +466,6 @@ static void __init anubis_map_io(void)
454 466
455 s3c24xx_register_clocks(anubis_clocks, ARRAY_SIZE(anubis_clocks)); 467 s3c24xx_register_clocks(anubis_clocks, ARRAY_SIZE(anubis_clocks));
456 468
457 s3c_device_nand.dev.platform_data = &anubis_nand_info;
458
459 s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc)); 469 s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc));
460 s3c24xx_init_clocks(0); 470 s3c24xx_init_clocks(0);
461 s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs)); 471 s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs));
@@ -476,6 +486,9 @@ static void __init anubis_map_io(void)
476static void __init anubis_init(void) 486static void __init anubis_init(void)
477{ 487{
478 s3c_i2c0_set_platdata(NULL); 488 s3c_i2c0_set_platdata(NULL);
489 s3c_nand_set_platdata(&anubis_nand_info);
490 simtec_audio_add(NULL, false, &anubis_audio);
491
479 platform_add_devices(anubis_devices, ARRAY_SIZE(anubis_devices)); 492 platform_add_devices(anubis_devices, ARRAY_SIZE(anubis_devices));
480 493
481 i2c_register_board_info(0, anubis_i2c_devs, 494 i2c_register_board_info(0, anubis_i2c_devs,
diff --git a/arch/arm/mach-s3c2440/mach-at2440evb.c b/arch/arm/mach-s3c2440/mach-at2440evb.c
index dfc7010935da..84725791e6bf 100644
--- a/arch/arm/mach-s3c2440/mach-at2440evb.c
+++ b/arch/arm/mach-s3c2440/mach-at2440evb.c
@@ -96,7 +96,7 @@ static struct s3c2410_uartcfg at2440evb_uartcfgs[] __initdata = {
96 96
97/* NAND Flash on AT2440EVB board */ 97/* NAND Flash on AT2440EVB board */
98 98
99static struct mtd_partition at2440evb_default_nand_part[] = { 99static struct mtd_partition __initdata at2440evb_default_nand_part[] = {
100 [0] = { 100 [0] = {
101 .name = "Boot Agent", 101 .name = "Boot Agent",
102 .size = SZ_256K, 102 .size = SZ_256K,
@@ -114,7 +114,7 @@ static struct mtd_partition at2440evb_default_nand_part[] = {
114 }, 114 },
115}; 115};
116 116
117static struct s3c2410_nand_set at2440evb_nand_sets[] = { 117static struct s3c2410_nand_set __initdata at2440evb_nand_sets[] = {
118 [0] = { 118 [0] = {
119 .name = "nand", 119 .name = "nand",
120 .nr_chips = 1, 120 .nr_chips = 1,
@@ -123,7 +123,7 @@ static struct s3c2410_nand_set at2440evb_nand_sets[] = {
123 }, 123 },
124}; 124};
125 125
126static struct s3c2410_platform_nand at2440evb_nand_info = { 126static struct s3c2410_platform_nand __initdata at2440evb_nand_info = {
127 .tacls = 25, 127 .tacls = 25,
128 .twrph0 = 55, 128 .twrph0 = 55,
129 .twrph1 = 40, 129 .twrph1 = 40,
@@ -165,7 +165,7 @@ static struct platform_device at2440evb_device_eth = {
165 }, 165 },
166}; 166};
167 167
168static struct s3c24xx_mci_pdata at2440evb_mci_pdata = { 168static struct s3c24xx_mci_pdata at2440evb_mci_pdata __initdata = {
169 .gpio_detect = S3C2410_GPG(10), 169 .gpio_detect = S3C2410_GPG(10),
170}; 170};
171 171
@@ -203,7 +203,7 @@ static struct s3c2410fb_mach_info at2440evb_fb_info __initdata = {
203}; 203};
204 204
205static struct platform_device *at2440evb_devices[] __initdata = { 205static struct platform_device *at2440evb_devices[] __initdata = {
206 &s3c_device_usb, 206 &s3c_device_ohci,
207 &s3c_device_wdt, 207 &s3c_device_wdt,
208 &s3c_device_adc, 208 &s3c_device_adc,
209 &s3c_device_i2c0, 209 &s3c_device_i2c0,
@@ -216,10 +216,6 @@ static struct platform_device *at2440evb_devices[] __initdata = {
216 216
217static void __init at2440evb_map_io(void) 217static void __init at2440evb_map_io(void)
218{ 218{
219 s3c_device_nand.dev.platform_data = &at2440evb_nand_info;
220 s3c_device_sdi.name = "s3c2440-sdi";
221 s3c_device_sdi.dev.platform_data = &at2440evb_mci_pdata;
222
223 s3c24xx_init_io(at2440evb_iodesc, ARRAY_SIZE(at2440evb_iodesc)); 219 s3c24xx_init_io(at2440evb_iodesc, ARRAY_SIZE(at2440evb_iodesc));
224 s3c24xx_init_clocks(16934400); 220 s3c24xx_init_clocks(16934400);
225 s3c24xx_init_uarts(at2440evb_uartcfgs, ARRAY_SIZE(at2440evb_uartcfgs)); 221 s3c24xx_init_uarts(at2440evb_uartcfgs, ARRAY_SIZE(at2440evb_uartcfgs));
@@ -228,6 +224,8 @@ static void __init at2440evb_map_io(void)
228static void __init at2440evb_init(void) 224static void __init at2440evb_init(void)
229{ 225{
230 s3c24xx_fb_set_platdata(&at2440evb_fb_info); 226 s3c24xx_fb_set_platdata(&at2440evb_fb_info);
227 s3c24xx_mci_set_platdata(&at2440evb_mci_pdata);
228 s3c_nand_set_platdata(&at2440evb_nand_info);
231 s3c_i2c0_set_platdata(NULL); 229 s3c_i2c0_set_platdata(NULL);
232 230
233 platform_add_devices(at2440evb_devices, ARRAY_SIZE(at2440evb_devices)); 231 platform_add_devices(at2440evb_devices, ARRAY_SIZE(at2440evb_devices));
diff --git a/arch/arm/mach-s3c2440/mach-gta02.c b/arch/arm/mach-s3c2440/mach-gta02.c
new file mode 100644
index 000000000000..45799c608d8f
--- /dev/null
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -0,0 +1,647 @@
1/*
2 * linux/arch/arm/mach-s3c2442/mach-gta02.c
3 *
4 * S3C2442 Machine Support for Openmoko GTA02 / FreeRunner.
5 *
6 * Copyright (C) 2006-2009 by Openmoko, Inc.
7 * Authors: Harald Welte <laforge@openmoko.org>
8 * Andy Green <andy@openmoko.org>
9 * Werner Almesberger <werner@openmoko.org>
10 * All rights reserved.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
26 *
27 */
28
29#include <linux/kernel.h>
30#include <linux/types.h>
31#include <linux/interrupt.h>
32#include <linux/list.h>
33#include <linux/delay.h>
34#include <linux/timer.h>
35#include <linux/init.h>
36#include <linux/gpio.h>
37#include <linux/workqueue.h>
38#include <linux/platform_device.h>
39#include <linux/serial_core.h>
40#include <linux/spi/spi.h>
41
42#include <linux/mmc/host.h>
43
44#include <linux/mtd/mtd.h>
45#include <linux/mtd/nand.h>
46#include <linux/mtd/nand_ecc.h>
47#include <linux/mtd/partitions.h>
48#include <linux/mtd/physmap.h>
49#include <linux/io.h>
50
51#include <linux/i2c.h>
52#include <linux/backlight.h>
53#include <linux/regulator/machine.h>
54
55#include <linux/mfd/pcf50633/core.h>
56#include <linux/mfd/pcf50633/mbc.h>
57#include <linux/mfd/pcf50633/adc.h>
58#include <linux/mfd/pcf50633/gpio.h>
59#include <linux/mfd/pcf50633/pmic.h>
60
61#include <asm/mach/arch.h>
62#include <asm/mach/map.h>
63#include <asm/mach/irq.h>
64
65#include <asm/irq.h>
66#include <asm/mach-types.h>
67
68#include <mach/regs-irq.h>
69#include <mach/regs-gpio.h>
70#include <mach/regs-gpioj.h>
71#include <mach/fb.h>
72
73#include <mach/spi.h>
74#include <mach/spi-gpio.h>
75#include <plat/usb-control.h>
76#include <mach/regs-mem.h>
77#include <mach/hardware.h>
78
79#include <mach/gta02.h>
80
81#include <plat/regs-serial.h>
82#include <plat/nand.h>
83#include <plat/devs.h>
84#include <plat/cpu.h>
85#include <plat/pm.h>
86#include <plat/udc.h>
87#include <plat/gpio-cfg.h>
88#include <plat/iic.h>
89
90static struct pcf50633 *gta02_pcf;
91
92/*
93 * This gets called every 1ms when we paniced.
94 */
95
96static long gta02_panic_blink(long count)
97{
98 long delay = 0;
99 static long last_blink;
100 static char led;
101
102 /* Fast blink: 200ms period. */
103 if (count - last_blink < 100)
104 return 0;
105
106 led ^= 1;
107 gpio_direction_output(GTA02_GPIO_AUX_LED, led);
108
109 last_blink = count;
110
111 return delay;
112}
113
114
115static struct map_desc gta02_iodesc[] __initdata = {
116 {
117 .virtual = 0xe0000000,
118 .pfn = __phys_to_pfn(S3C2410_CS3 + 0x01000000),
119 .length = SZ_1M,
120 .type = MT_DEVICE
121 },
122};
123
124#define UCON (S3C2410_UCON_DEFAULT | S3C2443_UCON_RXERR_IRQEN)
125#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
126#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
127
128static struct s3c2410_uartcfg gta02_uartcfgs[] = {
129 [0] = {
130 .hwport = 0,
131 .flags = 0,
132 .ucon = UCON,
133 .ulcon = ULCON,
134 .ufcon = UFCON,
135 },
136 [1] = {
137 .hwport = 1,
138 .flags = 0,
139 .ucon = UCON,
140 .ulcon = ULCON,
141 .ufcon = UFCON,
142 },
143 [2] = {
144 .hwport = 2,
145 .flags = 0,
146 .ucon = UCON,
147 .ulcon = ULCON,
148 .ufcon = UFCON,
149 },
150};
151
152#ifdef CONFIG_CHARGER_PCF50633
153/*
154 * On GTA02 the 1A charger features a 48K resistor to 0V on the ID pin.
155 * We use this to recognize that we can pull 1A from the USB socket.
156 *
157 * These constants are the measured pcf50633 ADC levels with the 1A
158 * charger / 48K resistor, and with no pulldown resistor.
159 */
160
161#define ADC_NOM_CHG_DETECT_1A 6
162#define ADC_NOM_CHG_DETECT_USB 43
163
164static void
165gta02_configure_pmu_for_charger(struct pcf50633 *pcf, void *unused, int res)
166{
167 int ma;
168
169 /* Interpret charger type */
170 if (res < ((ADC_NOM_CHG_DETECT_USB + ADC_NOM_CHG_DETECT_1A) / 2)) {
171
172 /*
173 * Sanity - stop GPO driving out now that we have a 1A charger
174 * GPO controls USB Host power generation on GTA02
175 */
176 pcf50633_gpio_set(pcf, PCF50633_GPO, 0);
177
178 ma = 1000;
179 } else
180 ma = 100;
181
182 pcf50633_mbc_usb_curlim_set(pcf, ma);
183}
184
185static struct delayed_work gta02_charger_work;
186static int gta02_usb_vbus_draw;
187
188static void gta02_charger_worker(struct work_struct *work)
189{
190 if (gta02_usb_vbus_draw) {
191 pcf50633_mbc_usb_curlim_set(gta02_pcf, gta02_usb_vbus_draw);
192 return;
193 }
194
195#ifdef CONFIG_PCF50633_ADC
196 pcf50633_adc_async_read(gta02_pcf,
197 PCF50633_ADCC1_MUX_ADCIN1,
198 PCF50633_ADCC1_AVERAGE_16,
199 gta02_configure_pmu_for_charger,
200 NULL);
201#else
202 /*
203 * If the PCF50633 ADC is disabled we fallback to a
204 * 100mA limit for safety.
205 */
206 pcf50633_mbc_usb_curlim_set(pcf, 100);
207#endif
208}
209
210#define GTA02_CHARGER_CONFIGURE_TIMEOUT ((3000 * HZ) / 1000)
211
212static void gta02_pmu_event_callback(struct pcf50633 *pcf, int irq)
213{
214 if (irq == PCF50633_IRQ_USBINS) {
215 schedule_delayed_work(&gta02_charger_work,
216 GTA02_CHARGER_CONFIGURE_TIMEOUT);
217
218 return;
219 }
220
221 if (irq == PCF50633_IRQ_USBREM) {
222 cancel_delayed_work_sync(&gta02_charger_work);
223 gta02_usb_vbus_draw = 0;
224 }
225}
226
227static void gta02_udc_vbus_draw(unsigned int ma)
228{
229 if (!gta02_pcf)
230 return;
231
232 gta02_usb_vbus_draw = ma;
233
234 schedule_delayed_work(&gta02_charger_work,
235 GTA02_CHARGER_CONFIGURE_TIMEOUT);
236}
237#else /* !CONFIG_CHARGER_PCF50633 */
238#define gta02_pmu_event_callback NULL
239#define gta02_udc_vbus_draw NULL
240#endif
241
242/*
243 * This is called when pc50633 is probed, unfortunately quite late in the
244 * day since it is an I2C bus device. Here we can belatedly define some
245 * platform devices with the advantage that we can mark the pcf50633 as the
246 * parent. This makes them get suspended and resumed with their parent
247 * the pcf50633 still around.
248 */
249
250static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf);
251
252
253static char *gta02_batteries[] = {
254 "battery",
255};
256
257struct pcf50633_platform_data gta02_pcf_pdata = {
258 .resumers = {
259 [0] = PCF50633_INT1_USBINS |
260 PCF50633_INT1_USBREM |
261 PCF50633_INT1_ALARM,
262 [1] = PCF50633_INT2_ONKEYF,
263 [2] = PCF50633_INT3_ONKEY1S,
264 [3] = PCF50633_INT4_LOWSYS |
265 PCF50633_INT4_LOWBAT |
266 PCF50633_INT4_HIGHTMP,
267 },
268
269 .batteries = gta02_batteries,
270 .num_batteries = ARRAY_SIZE(gta02_batteries),
271
272 .charger_reference_current_ma = 1000,
273
274 .reg_init_data = {
275 [PCF50633_REGULATOR_AUTO] = {
276 .constraints = {
277 .min_uV = 3300000,
278 .max_uV = 3300000,
279 .valid_modes_mask = REGULATOR_MODE_NORMAL,
280 .always_on = 1,
281 .apply_uV = 1,
282 .state_mem = {
283 .enabled = 1,
284 },
285 },
286 },
287 [PCF50633_REGULATOR_DOWN1] = {
288 .constraints = {
289 .min_uV = 1300000,
290 .max_uV = 1600000,
291 .valid_modes_mask = REGULATOR_MODE_NORMAL,
292 .always_on = 1,
293 .apply_uV = 1,
294 },
295 },
296 [PCF50633_REGULATOR_DOWN2] = {
297 .constraints = {
298 .min_uV = 1800000,
299 .max_uV = 1800000,
300 .valid_modes_mask = REGULATOR_MODE_NORMAL,
301 .apply_uV = 1,
302 .always_on = 1,
303 .state_mem = {
304 .enabled = 1,
305 },
306 },
307 },
308 [PCF50633_REGULATOR_HCLDO] = {
309 .constraints = {
310 .min_uV = 2000000,
311 .max_uV = 3300000,
312 .valid_modes_mask = REGULATOR_MODE_NORMAL,
313 .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
314 .always_on = 1,
315 },
316 },
317 [PCF50633_REGULATOR_LDO1] = {
318 .constraints = {
319 .min_uV = 3300000,
320 .max_uV = 3300000,
321 .valid_modes_mask = REGULATOR_MODE_NORMAL,
322 .apply_uV = 1,
323 .state_mem = {
324 .enabled = 0,
325 },
326 },
327 },
328 [PCF50633_REGULATOR_LDO2] = {
329 .constraints = {
330 .min_uV = 3300000,
331 .max_uV = 3300000,
332 .valid_modes_mask = REGULATOR_MODE_NORMAL,
333 .apply_uV = 1,
334 },
335 },
336 [PCF50633_REGULATOR_LDO3] = {
337 .constraints = {
338 .min_uV = 3000000,
339 .max_uV = 3000000,
340 .valid_modes_mask = REGULATOR_MODE_NORMAL,
341 .apply_uV = 1,
342 },
343 },
344 [PCF50633_REGULATOR_LDO4] = {
345 .constraints = {
346 .min_uV = 3200000,
347 .max_uV = 3200000,
348 .valid_modes_mask = REGULATOR_MODE_NORMAL,
349 .apply_uV = 1,
350 },
351 },
352 [PCF50633_REGULATOR_LDO5] = {
353 .constraints = {
354 .min_uV = 3000000,
355 .max_uV = 3000000,
356 .valid_modes_mask = REGULATOR_MODE_NORMAL,
357 .apply_uV = 1,
358 .state_mem = {
359 .enabled = 1,
360 },
361 },
362 },
363 [PCF50633_REGULATOR_LDO6] = {
364 .constraints = {
365 .min_uV = 3000000,
366 .max_uV = 3000000,
367 .valid_modes_mask = REGULATOR_MODE_NORMAL,
368 },
369 },
370 [PCF50633_REGULATOR_MEMLDO] = {
371 .constraints = {
372 .min_uV = 1800000,
373 .max_uV = 1800000,
374 .valid_modes_mask = REGULATOR_MODE_NORMAL,
375 .state_mem = {
376 .enabled = 1,
377 },
378 },
379 },
380
381 },
382 .probe_done = gta02_pmu_attach_child_devices,
383 .mbc_event_callback = gta02_pmu_event_callback,
384};
385
386
387/* NOR Flash. */
388
389#define GTA02_FLASH_BASE 0x18000000 /* GCS3 */
390#define GTA02_FLASH_SIZE 0x200000 /* 2MBytes */
391
392static struct physmap_flash_data gta02_nor_flash_data = {
393 .width = 2,
394};
395
396static struct resource gta02_nor_flash_resource = {
397 .start = GTA02_FLASH_BASE,
398 .end = GTA02_FLASH_BASE + GTA02_FLASH_SIZE - 1,
399 .flags = IORESOURCE_MEM,
400};
401
402static struct platform_device gta02_nor_flash = {
403 .name = "physmap-flash",
404 .id = 0,
405 .dev = {
406 .platform_data = &gta02_nor_flash_data,
407 },
408 .resource = &gta02_nor_flash_resource,
409 .num_resources = 1,
410};
411
412
413struct platform_device s3c24xx_pwm_device = {
414 .name = "s3c24xx_pwm",
415 .num_resources = 0,
416};
417
418static struct i2c_board_info gta02_i2c_devs[] __initdata = {
419 {
420 I2C_BOARD_INFO("pcf50633", 0x73),
421 .irq = GTA02_IRQ_PCF50633,
422 .platform_data = &gta02_pcf_pdata,
423 },
424 {
425 I2C_BOARD_INFO("wm8753", 0x1a),
426 },
427};
428
429static struct s3c2410_nand_set __initdata gta02_nand_sets[] = {
430 [0] = {
431 /*
432 * This name is also hard-coded in the boot loaders, so
433 * changing it would would require all users to upgrade
434 * their boot loaders, some of which are stored in a NOR
435 * that is considered to be immutable.
436 */
437 .name = "neo1973-nand",
438 .nr_chips = 1,
439 .flash_bbt = 1,
440 },
441};
442
443/*
444 * Choose a set of timings derived from S3C@2442B MCP54
445 * data sheet (K5D2G13ACM-D075 MCP Memory).
446 */
447
448static struct s3c2410_platform_nand __initdata gta02_nand_info = {
449 .tacls = 0,
450 .twrph0 = 25,
451 .twrph1 = 15,
452 .nr_sets = ARRAY_SIZE(gta02_nand_sets),
453 .sets = gta02_nand_sets,
454};
455
456
457static void gta02_udc_command(enum s3c2410_udc_cmd_e cmd)
458{
459 switch (cmd) {
460 case S3C2410_UDC_P_ENABLE:
461 pr_debug("%s S3C2410_UDC_P_ENABLE\n", __func__);
462 gpio_direction_output(GTA02_GPIO_USB_PULLUP, 1);
463 break;
464 case S3C2410_UDC_P_DISABLE:
465 pr_debug("%s S3C2410_UDC_P_DISABLE\n", __func__);
466 gpio_direction_output(GTA02_GPIO_USB_PULLUP, 0);
467 break;
468 case S3C2410_UDC_P_RESET:
469 pr_debug("%s S3C2410_UDC_P_RESET\n", __func__);
470 /* FIXME: Do something here. */
471 }
472}
473
474/* Get PMU to set USB current limit accordingly. */
475static struct s3c2410_udc_mach_info gta02_udc_cfg = {
476 .vbus_draw = gta02_udc_vbus_draw,
477 .udc_command = gta02_udc_command,
478
479};
480
481
482
483static void gta02_bl_set_intensity(int intensity)
484{
485 struct pcf50633 *pcf = gta02_pcf;
486 int old_intensity = pcf50633_reg_read(pcf, PCF50633_REG_LEDOUT);
487
488 /* We map 8-bit intensity to 6-bit intensity in hardware. */
489 intensity >>= 2;
490
491 /*
492 * This can happen during, eg, print of panic on blanked console,
493 * but we can't service i2c without interrupts active, so abort.
494 */
495 if (in_atomic()) {
496 printk(KERN_ERR "gta02_bl_set_intensity called while atomic\n");
497 return;
498 }
499
500 old_intensity = pcf50633_reg_read(pcf, PCF50633_REG_LEDOUT);
501 if (intensity == old_intensity)
502 return;
503
504 /* We can't do this anywhere else. */
505 pcf50633_reg_write(pcf, PCF50633_REG_LEDDIM, 5);
506
507 if (!(pcf50633_reg_read(pcf, PCF50633_REG_LEDENA) & 3))
508 old_intensity = 0;
509
510 /*
511 * The PCF50633 cannot handle LEDOUT = 0 (datasheet p60)
512 * if seen, you have to re-enable the LED unit.
513 */
514 if (!intensity || !old_intensity)
515 pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 0);
516
517 /* Illegal to set LEDOUT to 0. */
518 if (!intensity)
519 pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_LEDOUT, 0x3f, 2);
520 else
521 pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_LEDOUT, 0x3f,
522 intensity);
523
524 if (intensity)
525 pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 2);
526
527}
528
529static struct generic_bl_info gta02_bl_info = {
530 .name = "gta02-bl",
531 .max_intensity = 0xff,
532 .default_intensity = 0xff,
533 .set_bl_intensity = gta02_bl_set_intensity,
534};
535
536static struct platform_device gta02_bl_dev = {
537 .name = "generic-bl",
538 .id = 1,
539 .dev = {
540 .platform_data = &gta02_bl_info,
541 },
542};
543
544
545
546/* USB */
547static struct s3c2410_hcd_info gta02_usb_info __initdata = {
548 .port[0] = {
549 .flags = S3C_HCDFLG_USED,
550 },
551 .port[1] = {
552 .flags = 0,
553 },
554};
555
556
557static void __init gta02_map_io(void)
558{
559 s3c24xx_init_io(gta02_iodesc, ARRAY_SIZE(gta02_iodesc));
560 s3c24xx_init_clocks(12000000);
561 s3c24xx_init_uarts(gta02_uartcfgs, ARRAY_SIZE(gta02_uartcfgs));
562}
563
564
565/* These are the guys that don't need to be children of PMU. */
566
567static struct platform_device *gta02_devices[] __initdata = {
568 &s3c_device_ohci,
569 &s3c_device_wdt,
570 &s3c_device_sdi,
571 &s3c_device_usbgadget,
572 &s3c_device_nand,
573 &gta02_nor_flash,
574 &s3c24xx_pwm_device,
575 &s3c_device_iis,
576 &s3c_device_i2c0,
577};
578
579/* These guys DO need to be children of PMU. */
580
581static struct platform_device *gta02_devices_pmu_children[] = {
582 &gta02_bl_dev,
583};
584
585
586/*
587 * This is called when pc50633 is probed, quite late in the day since it is an
588 * I2C bus device. Here we can define platform devices with the advantage that
589 * we can mark the pcf50633 as the parent. This makes them get suspended and
590 * resumed with their parent the pcf50633 still around. All devices whose
591 * operation depends on something from pcf50633 must have this relationship
592 * made explicit like this, or suspend and resume will become an unreliable
593 * hellworld.
594 */
595
596static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf)
597{
598 int n;
599
600 /* Grab a copy of the now probed PMU pointer. */
601 gta02_pcf = pcf;
602
603 for (n = 0; n < ARRAY_SIZE(gta02_devices_pmu_children); n++)
604 gta02_devices_pmu_children[n]->dev.parent = pcf->dev;
605
606 platform_add_devices(gta02_devices_pmu_children,
607 ARRAY_SIZE(gta02_devices_pmu_children));
608}
609
610static void gta02_poweroff(void)
611{
612 pcf50633_reg_set_bit_mask(gta02_pcf, PCF50633_REG_OOCSHDWN, 1, 1);
613}
614
615static void __init gta02_machine_init(void)
616{
617 /* Set the panic callback to make AUX LED blink at ~5Hz. */
618 panic_blink = gta02_panic_blink;
619
620 s3c_pm_init();
621
622#ifdef CONFIG_CHARGER_PCF50633
623 INIT_DELAYED_WORK(&gta02_charger_work, gta02_charger_worker);
624#endif
625
626 s3c24xx_udc_set_platdata(&gta02_udc_cfg);
627 s3c_ohci_set_platdata(&gta02_usb_info);
628 s3c_nand_set_platdata(&gta02_nand_info);
629 s3c_i2c0_set_platdata(NULL);
630
631 i2c_register_board_info(0, gta02_i2c_devs, ARRAY_SIZE(gta02_i2c_devs));
632
633 platform_add_devices(gta02_devices, ARRAY_SIZE(gta02_devices));
634 pm_power_off = gta02_poweroff;
635}
636
637
638MACHINE_START(NEO1973_GTA02, "GTA02")
639 /* Maintainer: Nelson Castillo <arhuaco@freaks-unidos.net> */
640 .phys_io = S3C2410_PA_UART,
641 .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
642 .boot_params = S3C2410_SDRAM_PA + 0x100,
643 .map_io = gta02_map_io,
644 .init_irq = s3c24xx_init_irq,
645 .init_machine = gta02_machine_init,
646 .timer = &s3c24xx_timer,
647MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-mini2440.c b/arch/arm/mach-s3c2440/mach-mini2440.c
index 1c3382fefdd2..571b17683d96 100644
--- a/arch/arm/mach-s3c2440/mach-mini2440.c
+++ b/arch/arm/mach-s3c2440/mach-mini2440.c
@@ -288,7 +288,7 @@ static struct s3c2410_platform_nand mini2440_nand_info __initdata = {
288 288
289/* DM9000AEP 10/100 ethernet controller */ 289/* DM9000AEP 10/100 ethernet controller */
290 290
291static struct resource mini2440_dm9k_resource[] __initdata = { 291static struct resource mini2440_dm9k_resource[] = {
292 [0] = { 292 [0] = {
293 .start = MACH_MINI2440_DM9K_BASE, 293 .start = MACH_MINI2440_DM9K_BASE,
294 .end = MACH_MINI2440_DM9K_BASE + 3, 294 .end = MACH_MINI2440_DM9K_BASE + 3,
@@ -310,11 +310,11 @@ static struct resource mini2440_dm9k_resource[] __initdata = {
310 * The DM9000 has no eeprom, and it's MAC address is set by 310 * The DM9000 has no eeprom, and it's MAC address is set by
311 * the bootloader before starting the kernel. 311 * the bootloader before starting the kernel.
312 */ 312 */
313static struct dm9000_plat_data mini2440_dm9k_pdata __initdata = { 313static struct dm9000_plat_data mini2440_dm9k_pdata = {
314 .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM), 314 .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
315}; 315};
316 316
317static struct platform_device mini2440_device_eth __initdata = { 317static struct platform_device mini2440_device_eth = {
318 .name = "dm9000", 318 .name = "dm9000",
319 .id = -1, 319 .id = -1,
320 .num_resources = ARRAY_SIZE(mini2440_dm9k_resource), 320 .num_resources = ARRAY_SIZE(mini2440_dm9k_resource),
@@ -341,7 +341,7 @@ static struct platform_device mini2440_device_eth __initdata = {
341 * | | +----+ +----+ 341 * | | +----+ +----+
342 * ..... 342 * .....
343 */ 343 */
344static struct gpio_keys_button mini2440_buttons[] __initdata = { 344static struct gpio_keys_button mini2440_buttons[] = {
345 { 345 {
346 .gpio = S3C2410_GPG(0), /* K1 */ 346 .gpio = S3C2410_GPG(0), /* K1 */
347 .code = KEY_F1, 347 .code = KEY_F1,
@@ -384,12 +384,12 @@ static struct gpio_keys_button mini2440_buttons[] __initdata = {
384#endif 384#endif
385}; 385};
386 386
387static struct gpio_keys_platform_data mini2440_button_data __initdata = { 387static struct gpio_keys_platform_data mini2440_button_data = {
388 .buttons = mini2440_buttons, 388 .buttons = mini2440_buttons,
389 .nbuttons = ARRAY_SIZE(mini2440_buttons), 389 .nbuttons = ARRAY_SIZE(mini2440_buttons),
390}; 390};
391 391
392static struct platform_device mini2440_button_device __initdata = { 392static struct platform_device mini2440_button_device = {
393 .name = "gpio-keys", 393 .name = "gpio-keys",
394 .id = -1, 394 .id = -1,
395 .dev = { 395 .dev = {
@@ -399,41 +399,41 @@ static struct platform_device mini2440_button_device __initdata = {
399 399
400/* LEDS */ 400/* LEDS */
401 401
402static struct s3c24xx_led_platdata mini2440_led1_pdata __initdata = { 402static struct s3c24xx_led_platdata mini2440_led1_pdata = {
403 .name = "led1", 403 .name = "led1",
404 .gpio = S3C2410_GPB(5), 404 .gpio = S3C2410_GPB(5),
405 .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, 405 .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
406 .def_trigger = "heartbeat", 406 .def_trigger = "heartbeat",
407}; 407};
408 408
409static struct s3c24xx_led_platdata mini2440_led2_pdata __initdata = { 409static struct s3c24xx_led_platdata mini2440_led2_pdata = {
410 .name = "led2", 410 .name = "led2",
411 .gpio = S3C2410_GPB(6), 411 .gpio = S3C2410_GPB(6),
412 .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, 412 .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
413 .def_trigger = "nand-disk", 413 .def_trigger = "nand-disk",
414}; 414};
415 415
416static struct s3c24xx_led_platdata mini2440_led3_pdata __initdata = { 416static struct s3c24xx_led_platdata mini2440_led3_pdata = {
417 .name = "led3", 417 .name = "led3",
418 .gpio = S3C2410_GPB(7), 418 .gpio = S3C2410_GPB(7),
419 .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, 419 .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
420 .def_trigger = "mmc0", 420 .def_trigger = "mmc0",
421}; 421};
422 422
423static struct s3c24xx_led_platdata mini2440_led4_pdata __initdata = { 423static struct s3c24xx_led_platdata mini2440_led4_pdata = {
424 .name = "led4", 424 .name = "led4",
425 .gpio = S3C2410_GPB(8), 425 .gpio = S3C2410_GPB(8),
426 .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, 426 .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
427 .def_trigger = "", 427 .def_trigger = "",
428}; 428};
429 429
430static struct s3c24xx_led_platdata mini2440_led_backlight_pdata __initdata = { 430static struct s3c24xx_led_platdata mini2440_led_backlight_pdata = {
431 .name = "backlight", 431 .name = "backlight",
432 .gpio = S3C2410_GPG(4), 432 .gpio = S3C2410_GPG(4),
433 .def_trigger = "backlight", 433 .def_trigger = "backlight",
434}; 434};
435 435
436static struct platform_device mini2440_led1 __initdata = { 436static struct platform_device mini2440_led1 = {
437 .name = "s3c24xx_led", 437 .name = "s3c24xx_led",
438 .id = 1, 438 .id = 1,
439 .dev = { 439 .dev = {
@@ -441,7 +441,7 @@ static struct platform_device mini2440_led1 __initdata = {
441 }, 441 },
442}; 442};
443 443
444static struct platform_device mini2440_led2 __initdata = { 444static struct platform_device mini2440_led2 = {
445 .name = "s3c24xx_led", 445 .name = "s3c24xx_led",
446 .id = 2, 446 .id = 2,
447 .dev = { 447 .dev = {
@@ -449,7 +449,7 @@ static struct platform_device mini2440_led2 __initdata = {
449 }, 449 },
450}; 450};
451 451
452static struct platform_device mini2440_led3 __initdata = { 452static struct platform_device mini2440_led3 = {
453 .name = "s3c24xx_led", 453 .name = "s3c24xx_led",
454 .id = 3, 454 .id = 3,
455 .dev = { 455 .dev = {
@@ -457,7 +457,7 @@ static struct platform_device mini2440_led3 __initdata = {
457 }, 457 },
458}; 458};
459 459
460static struct platform_device mini2440_led4 __initdata = { 460static struct platform_device mini2440_led4 = {
461 .name = "s3c24xx_led", 461 .name = "s3c24xx_led",
462 .id = 4, 462 .id = 4,
463 .dev = { 463 .dev = {
@@ -465,7 +465,7 @@ static struct platform_device mini2440_led4 __initdata = {
465 }, 465 },
466}; 466};
467 467
468static struct platform_device mini2440_led_backlight __initdata = { 468static struct platform_device mini2440_led_backlight = {
469 .name = "s3c24xx_led", 469 .name = "s3c24xx_led",
470 .id = 5, 470 .id = 5,
471 .dev = { 471 .dev = {
@@ -475,14 +475,14 @@ static struct platform_device mini2440_led_backlight __initdata = {
475 475
476/* AUDIO */ 476/* AUDIO */
477 477
478static struct s3c24xx_uda134x_platform_data mini2440_audio_pins __initdata = { 478static struct s3c24xx_uda134x_platform_data mini2440_audio_pins = {
479 .l3_clk = S3C2410_GPB(4), 479 .l3_clk = S3C2410_GPB(4),
480 .l3_mode = S3C2410_GPB(2), 480 .l3_mode = S3C2410_GPB(2),
481 .l3_data = S3C2410_GPB(3), 481 .l3_data = S3C2410_GPB(3),
482 .model = UDA134X_UDA1341 482 .model = UDA134X_UDA1341
483}; 483};
484 484
485static struct platform_device mini2440_audio __initdata = { 485static struct platform_device mini2440_audio = {
486 .name = "s3c24xx_uda134x", 486 .name = "s3c24xx_uda134x",
487 .id = 0, 487 .id = 0,
488 .dev = { 488 .dev = {
@@ -506,9 +506,8 @@ static struct i2c_board_info mini2440_i2c_devs[] __initdata = {
506}; 506};
507 507
508static struct platform_device *mini2440_devices[] __initdata = { 508static struct platform_device *mini2440_devices[] __initdata = {
509 &s3c_device_usb, 509 &s3c_device_ohci,
510 &s3c_device_wdt, 510 &s3c_device_wdt,
511/* &s3c_device_adc,*/ /* ADC doesn't like living with touchscreen ! */
512 &s3c_device_i2c0, 511 &s3c_device_i2c0,
513 &s3c_device_rtc, 512 &s3c_device_rtc,
514 &s3c_device_usbgadget, 513 &s3c_device_usbgadget,
@@ -522,8 +521,6 @@ static struct platform_device *mini2440_devices[] __initdata = {
522 &s3c_device_sdi, 521 &s3c_device_sdi,
523 &s3c_device_iis, 522 &s3c_device_iis,
524 &mini2440_audio, 523 &mini2440_audio,
525/* &s3c_device_timer[0],*/ /* buzzer pwm, no API for it */
526 /* remaining devices are optional */
527}; 524};
528 525
529static void __init mini2440_map_io(void) 526static void __init mini2440_map_io(void)
@@ -531,9 +528,6 @@ static void __init mini2440_map_io(void)
531 s3c24xx_init_io(mini2440_iodesc, ARRAY_SIZE(mini2440_iodesc)); 528 s3c24xx_init_io(mini2440_iodesc, ARRAY_SIZE(mini2440_iodesc));
532 s3c24xx_init_clocks(12000000); 529 s3c24xx_init_clocks(12000000);
533 s3c24xx_init_uarts(mini2440_uartcfgs, ARRAY_SIZE(mini2440_uartcfgs)); 530 s3c24xx_init_uarts(mini2440_uartcfgs, ARRAY_SIZE(mini2440_uartcfgs));
534
535 s3c_device_nand.dev.platform_data = &mini2440_nand_info;
536 s3c_device_sdi.dev.platform_data = &mini2440_mmc_cfg;
537} 531}
538 532
539/* 533/*
@@ -677,8 +671,12 @@ static void __init mini2440_init(void)
677 printk("\n"); 671 printk("\n");
678 s3c24xx_fb_set_platdata(&mini2440_fb_info); 672 s3c24xx_fb_set_platdata(&mini2440_fb_info);
679 } 673 }
674
680 s3c24xx_udc_set_platdata(&mini2440_udc_cfg); 675 s3c24xx_udc_set_platdata(&mini2440_udc_cfg);
676 s3c24xx_mci_set_platdata(&mini2440_mmc_cfg);
677 s3c_nand_set_platdata(&mini2440_nand_info);
681 s3c_i2c0_set_platdata(NULL); 678 s3c_i2c0_set_platdata(NULL);
679
682 i2c_register_board_info(0, mini2440_i2c_devs, 680 i2c_register_board_info(0, mini2440_i2c_devs,
683 ARRAY_SIZE(mini2440_i2c_devs)); 681 ARRAY_SIZE(mini2440_i2c_devs));
684 682
diff --git a/arch/arm/mach-s3c2440/mach-nexcoder.c b/arch/arm/mach-s3c2440/mach-nexcoder.c
index d43edede590e..342041593f22 100644
--- a/arch/arm/mach-s3c2440/mach-nexcoder.c
+++ b/arch/arm/mach-s3c2440/mach-nexcoder.c
@@ -41,7 +41,7 @@
41#include <plat/iic.h> 41#include <plat/iic.h>
42 42
43#include <plat/s3c2410.h> 43#include <plat/s3c2410.h>
44#include <plat/s3c2440.h> 44#include <plat/s3c244x.h>
45#include <plat/clock.h> 45#include <plat/clock.h>
46#include <plat/devs.h> 46#include <plat/devs.h>
47#include <plat/cpu.h> 47#include <plat/cpu.h>
@@ -106,7 +106,7 @@ static struct platform_device nexcoder_device_nor = {
106/* Standard Nexcoder devices */ 106/* Standard Nexcoder devices */
107 107
108static struct platform_device *nexcoder_devices[] __initdata = { 108static struct platform_device *nexcoder_devices[] __initdata = {
109 &s3c_device_usb, 109 &s3c_device_ohci,
110 &s3c_device_lcd, 110 &s3c_device_lcd,
111 &s3c_device_wdt, 111 &s3c_device_wdt,
112 &s3c_device_i2c0, 112 &s3c_device_i2c0,
diff --git a/arch/arm/mach-s3c2440/mach-osiris-dvs.c b/arch/arm/mach-s3c2440/mach-osiris-dvs.c
new file mode 100644
index 000000000000..ad2792dfbee1
--- /dev/null
+++ b/arch/arm/mach-s3c2440/mach-osiris-dvs.c
@@ -0,0 +1,194 @@
1/* linux/arch/arm/mach-s3c2440/mach-osiris-dvs.c
2 *
3 * Copyright (c) 2009 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 *
7 * Simtec Osiris Dynamic Voltage Scaling 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 version 2 as
11 * published by the Free Software Foundation.
12*/
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/platform_device.h>
17#include <linux/cpufreq.h>
18#include <linux/gpio.h>
19
20#include <linux/i2c/tps65010.h>
21
22#include <plat/cpu-freq.h>
23
24#define OSIRIS_GPIO_DVS S3C2410_GPB(5)
25
26static bool dvs_en;
27
28static void osiris_dvs_tps_setdvs(bool on)
29{
30 unsigned vregs1 = 0, vdcdc2 = 0;
31
32 if (!on) {
33 vdcdc2 = TPS_VCORE_DISCH | TPS_LP_COREOFF;
34 vregs1 = TPS_LDO1_OFF; /* turn off in low-power mode */
35 }
36
37 dvs_en = on;
38 vdcdc2 |= TPS_VCORE_1_3V | TPS_VCORE_LP_1_0V;
39 vregs1 |= TPS_LDO2_ENABLE | TPS_LDO1_ENABLE;
40
41 tps65010_config_vregs1(vregs1);
42 tps65010_config_vdcdc2(vdcdc2);
43}
44
45static bool is_dvs(struct s3c_freq *f)
46{
47 /* at the moment, we assume ARMCLK = HCLK => DVS */
48 return f->armclk == f->hclk;
49}
50
51/* keep track of current state */
52static bool cur_dvs = false;
53
54static int osiris_dvs_notify(struct notifier_block *nb,
55 unsigned long val, void *data)
56{
57 struct cpufreq_freqs *cf = data;
58 struct s3c_cpufreq_freqs *freqs = to_s3c_cpufreq(cf);
59 bool old_dvs = is_dvs(&freqs->old);
60 bool new_dvs = is_dvs(&freqs->new);
61 int ret = 0;
62
63 if (!dvs_en)
64 return 0;
65
66 printk(KERN_DEBUG "%s: old %ld,%ld new %ld,%ld\n", __func__,
67 freqs->old.armclk, freqs->old.hclk,
68 freqs->new.armclk, freqs->new.hclk);
69
70 switch (val) {
71 case CPUFREQ_PRECHANGE:
72 if (old_dvs & !new_dvs ||
73 cur_dvs & !new_dvs) {
74 pr_debug("%s: exiting dvs\n", __func__);
75 cur_dvs = false;
76 gpio_set_value(OSIRIS_GPIO_DVS, 1);
77 }
78 break;
79 case CPUFREQ_POSTCHANGE:
80 if (!old_dvs & new_dvs ||
81 !cur_dvs & new_dvs) {
82 pr_debug("entering dvs\n");
83 cur_dvs = true;
84 gpio_set_value(OSIRIS_GPIO_DVS, 0);
85 }
86 break;
87 }
88
89 return ret;
90}
91
92static struct notifier_block osiris_dvs_nb = {
93 .notifier_call = osiris_dvs_notify,
94};
95
96static int __devinit osiris_dvs_probe(struct platform_device *pdev)
97{
98 int ret;
99
100 dev_info(&pdev->dev, "initialising\n");
101
102 ret = gpio_request(OSIRIS_GPIO_DVS, "osiris-dvs");
103 if (ret) {
104 dev_err(&pdev->dev, "cannot claim gpio\n");
105 goto err_nogpio;
106 }
107
108 /* start with dvs disabled */
109 gpio_direction_output(OSIRIS_GPIO_DVS, 1);
110
111 ret = cpufreq_register_notifier(&osiris_dvs_nb,
112 CPUFREQ_TRANSITION_NOTIFIER);
113 if (ret) {
114 dev_err(&pdev->dev, "failed to register with cpufreq\n");
115 goto err_nofreq;
116 }
117
118 osiris_dvs_tps_setdvs(true);
119
120 return 0;
121
122err_nofreq:
123 gpio_free(OSIRIS_GPIO_DVS);
124
125err_nogpio:
126 return ret;
127}
128
129static int __devexit osiris_dvs_remove(struct platform_device *pdev)
130{
131 dev_info(&pdev->dev, "exiting\n");
132
133 /* disable any current dvs */
134 gpio_set_value(OSIRIS_GPIO_DVS, 1);
135 osiris_dvs_tps_setdvs(false);
136
137 cpufreq_unregister_notifier(&osiris_dvs_nb,
138 CPUFREQ_TRANSITION_NOTIFIER);
139
140 gpio_free(OSIRIS_GPIO_DVS);
141
142 return 0;
143}
144
145/* the CONFIG_PM block is so small, it isn't worth actaully compiling it
146 * out if the configuration isn't set. */
147
148static int osiris_dvs_suspend(struct device *dev)
149{
150 gpio_set_value(OSIRIS_GPIO_DVS, 1);
151 osiris_dvs_tps_setdvs(false);
152 cur_dvs = false;
153
154 return 0;
155}
156
157static int osiris_dvs_resume(struct device *dev)
158{
159 osiris_dvs_tps_setdvs(true);
160 return 0;
161}
162
163static const struct dev_pm_ops osiris_dvs_pm = {
164 .suspend = osiris_dvs_suspend,
165 .resume = osiris_dvs_resume,
166};
167
168static struct platform_driver osiris_dvs_driver = {
169 .probe = osiris_dvs_probe,
170 .remove = __devexit_p(osiris_dvs_remove),
171 .driver = {
172 .name = "osiris-dvs",
173 .owner = THIS_MODULE,
174 .pm = &osiris_dvs_pm,
175 },
176};
177
178static int __init osiris_dvs_init(void)
179{
180 return platform_driver_register(&osiris_dvs_driver);
181}
182
183static void __exit osiris_dvs_exit(void)
184{
185 platform_driver_unregister(&osiris_dvs_driver);
186}
187
188module_init(osiris_dvs_init);
189module_exit(osiris_dvs_exit);
190
191MODULE_DESCRIPTION("Simtec OSIRIS DVS support");
192MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
193MODULE_LICENSE("GPL");
194MODULE_ALIAS("platform:osiris-dvs");
diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c
index 2105a41281a4..f35371db33f5 100644
--- a/arch/arm/mach-s3c2440/mach-osiris.c
+++ b/arch/arm/mach-s3c2440/mach-osiris.c
@@ -1,6 +1,6 @@
1/* linux/arch/arm/mach-s3c2440/mach-osiris.c 1/* linux/arch/arm/mach-s3c2440/mach-osiris.c
2 * 2 *
3 * Copyright (c) 2005,2008 Simtec Electronics 3 * Copyright (c) 2005-2008 Simtec Electronics
4 * http://armlinux.simtec.co.uk/ 4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk> 5 * Ben Dooks <ben@simtec.co.uk>
6 * 6 *
@@ -23,6 +23,8 @@
23#include <linux/i2c.h> 23#include <linux/i2c.h>
24#include <linux/io.h> 24#include <linux/io.h>
25 25
26#include <linux/i2c/tps65010.h>
27
26#include <asm/mach/arch.h> 28#include <asm/mach/arch.h>
27#include <asm/mach/map.h> 29#include <asm/mach/map.h>
28#include <asm/mach/irq.h> 30#include <asm/mach/irq.h>
@@ -148,7 +150,7 @@ static int external_map[] = { 2 };
148static int chip0_map[] = { 0 }; 150static int chip0_map[] = { 0 };
149static int chip1_map[] = { 1 }; 151static int chip1_map[] = { 1 };
150 152
151static struct mtd_partition osiris_default_nand_part[] = { 153static struct mtd_partition __initdata osiris_default_nand_part[] = {
152 [0] = { 154 [0] = {
153 .name = "Boot Agent", 155 .name = "Boot Agent",
154 .size = SZ_16K, 156 .size = SZ_16K,
@@ -171,7 +173,7 @@ static struct mtd_partition osiris_default_nand_part[] = {
171 } 173 }
172}; 174};
173 175
174static struct mtd_partition osiris_default_nand_part_large[] = { 176static struct mtd_partition __initdata osiris_default_nand_part_large[] = {
175 [0] = { 177 [0] = {
176 .name = "Boot Agent", 178 .name = "Boot Agent",
177 .size = SZ_128K, 179 .size = SZ_128K,
@@ -201,11 +203,12 @@ static struct mtd_partition osiris_default_nand_part_large[] = {
201 * socket. 203 * socket.
202*/ 204*/
203 205
204static struct s3c2410_nand_set osiris_nand_sets[] = { 206static struct s3c2410_nand_set __initdata osiris_nand_sets[] = {
205 [1] = { 207 [1] = {
206 .name = "External", 208 .name = "External",
207 .nr_chips = 1, 209 .nr_chips = 1,
208 .nr_map = external_map, 210 .nr_map = external_map,
211 .options = NAND_SCAN_SILENT_NODEV,
209 .nr_partitions = ARRAY_SIZE(osiris_default_nand_part), 212 .nr_partitions = ARRAY_SIZE(osiris_default_nand_part),
210 .partitions = osiris_default_nand_part, 213 .partitions = osiris_default_nand_part,
211 }, 214 },
@@ -220,6 +223,7 @@ static struct s3c2410_nand_set osiris_nand_sets[] = {
220 .name = "chip1", 223 .name = "chip1",
221 .nr_chips = 1, 224 .nr_chips = 1,
222 .nr_map = chip1_map, 225 .nr_map = chip1_map,
226 .options = NAND_SCAN_SILENT_NODEV,
223 .nr_partitions = ARRAY_SIZE(osiris_default_nand_part), 227 .nr_partitions = ARRAY_SIZE(osiris_default_nand_part),
224 .partitions = osiris_default_nand_part, 228 .partitions = osiris_default_nand_part,
225 }, 229 },
@@ -243,7 +247,7 @@ static void osiris_nand_select(struct s3c2410_nand_set *set, int slot)
243 __raw_writeb(tmp, OSIRIS_VA_CTRL0); 247 __raw_writeb(tmp, OSIRIS_VA_CTRL0);
244} 248}
245 249
246static struct s3c2410_platform_nand osiris_nand_info = { 250static struct s3c2410_platform_nand __initdata osiris_nand_info = {
247 .tacls = 25, 251 .tacls = 25,
248 .twrph0 = 60, 252 .twrph0 = 60,
249 .twrph1 = 60, 253 .twrph1 = 60,
@@ -326,12 +330,44 @@ static struct sys_device osiris_pm_sysdev = {
326 .cls = &osiris_pm_sysclass, 330 .cls = &osiris_pm_sysclass,
327}; 331};
328 332
333/* Link for DVS driver to TPS65011 */
334
335static void osiris_tps_release(struct device *dev)
336{
337 /* static device, do not need to release anything */
338}
339
340static struct platform_device osiris_tps_device = {
341 .name = "osiris-dvs",
342 .id = -1,
343 .dev.release = osiris_tps_release,
344};
345
346static int osiris_tps_setup(struct i2c_client *client, void *context)
347{
348 osiris_tps_device.dev.parent = &client->dev;
349 return platform_device_register(&osiris_tps_device);
350}
351
352static int osiris_tps_remove(struct i2c_client *client, void *context)
353{
354 platform_device_unregister(&osiris_tps_device);
355 return 0;
356}
357
358static struct tps65010_board osiris_tps_board = {
359 .base = -1, /* GPIO can go anywhere at the moment */
360 .setup = osiris_tps_setup,
361 .teardown = osiris_tps_remove,
362};
363
329/* I2C devices fitted. */ 364/* I2C devices fitted. */
330 365
331static struct i2c_board_info osiris_i2c_devs[] __initdata = { 366static struct i2c_board_info osiris_i2c_devs[] __initdata = {
332 { 367 {
333 I2C_BOARD_INFO("tps65011", 0x48), 368 I2C_BOARD_INFO("tps65011", 0x48),
334 .irq = IRQ_EINT20, 369 .irq = IRQ_EINT20,
370 .platform_data = &osiris_tps_board,
335 }, 371 },
336}; 372};
337 373
@@ -377,8 +413,6 @@ static void __init osiris_map_io(void)
377 413
378 s3c24xx_register_clocks(osiris_clocks, ARRAY_SIZE(osiris_clocks)); 414 s3c24xx_register_clocks(osiris_clocks, ARRAY_SIZE(osiris_clocks));
379 415
380 s3c_device_nand.dev.platform_data = &osiris_nand_info;
381
382 s3c24xx_init_io(osiris_iodesc, ARRAY_SIZE(osiris_iodesc)); 416 s3c24xx_init_io(osiris_iodesc, ARRAY_SIZE(osiris_iodesc));
383 s3c24xx_init_clocks(0); 417 s3c24xx_init_clocks(0);
384 s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs)); 418 s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs));
@@ -408,6 +442,7 @@ static void __init osiris_init(void)
408 sysdev_register(&osiris_pm_sysdev); 442 sysdev_register(&osiris_pm_sysdev);
409 443
410 s3c_i2c0_set_platdata(NULL); 444 s3c_i2c0_set_platdata(NULL);
445 s3c_nand_set_platdata(&osiris_nand_info);
411 446
412 s3c_cpufreq_setboard(&osiris_cpufreq); 447 s3c_cpufreq_setboard(&osiris_cpufreq);
413 448
diff --git a/arch/arm/mach-s3c2440/mach-rx3715.c b/arch/arm/mach-s3c2440/mach-rx3715.c
index bc8d8d1ebd1a..1e836e506f8b 100644
--- a/arch/arm/mach-s3c2440/mach-rx3715.c
+++ b/arch/arm/mach-s3c2440/mach-rx3715.c
@@ -1,6 +1,6 @@
1/* linux/arch/arm/mach-s3c2440/mach-rx3715.c 1/* linux/arch/arm/mach-s3c2440/mach-rx3715.c
2 * 2 *
3 * Copyright (c) 2003,2004 Simtec Electronics 3 * Copyright (c) 2003-2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * 5 *
6 * http://www.handhelds.org/projects/rx3715.html 6 * http://www.handhelds.org/projects/rx3715.html
@@ -149,7 +149,7 @@ static struct s3c2410fb_mach_info rx3715_fb_info __initdata = {
149 .gpdup_mask = 0xffffffff, 149 .gpdup_mask = 0xffffffff,
150}; 150};
151 151
152static struct mtd_partition rx3715_nand_part[] = { 152static struct mtd_partition __initdata rx3715_nand_part[] = {
153 [0] = { 153 [0] = {
154 .name = "Whole Flash", 154 .name = "Whole Flash",
155 .offset = 0, 155 .offset = 0,
@@ -158,7 +158,7 @@ static struct mtd_partition rx3715_nand_part[] = {
158 } 158 }
159}; 159};
160 160
161static struct s3c2410_nand_set rx3715_nand_sets[] = { 161static struct s3c2410_nand_set __initdata rx3715_nand_sets[] = {
162 [0] = { 162 [0] = {
163 .name = "Internal", 163 .name = "Internal",
164 .nr_chips = 1, 164 .nr_chips = 1,
@@ -167,7 +167,7 @@ static struct s3c2410_nand_set rx3715_nand_sets[] = {
167 }, 167 },
168}; 168};
169 169
170static struct s3c2410_platform_nand rx3715_nand_info = { 170static struct s3c2410_platform_nand __initdata rx3715_nand_info = {
171 .tacls = 25, 171 .tacls = 25,
172 .twrph0 = 50, 172 .twrph0 = 50,
173 .twrph1 = 15, 173 .twrph1 = 15,
@@ -176,7 +176,7 @@ static struct s3c2410_platform_nand rx3715_nand_info = {
176}; 176};
177 177
178static struct platform_device *rx3715_devices[] __initdata = { 178static struct platform_device *rx3715_devices[] __initdata = {
179 &s3c_device_usb, 179 &s3c_device_ohci,
180 &s3c_device_lcd, 180 &s3c_device_lcd,
181 &s3c_device_wdt, 181 &s3c_device_wdt,
182 &s3c_device_i2c0, 182 &s3c_device_i2c0,
@@ -186,8 +186,6 @@ static struct platform_device *rx3715_devices[] __initdata = {
186 186
187static void __init rx3715_map_io(void) 187static void __init rx3715_map_io(void)
188{ 188{
189 s3c_device_nand.dev.platform_data = &rx3715_nand_info;
190
191 s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc)); 189 s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc));
192 s3c24xx_init_clocks(16934000); 190 s3c24xx_init_clocks(16934000);
193 s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs)); 191 s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs));
@@ -205,6 +203,7 @@ static void __init rx3715_init_machine(void)
205#endif 203#endif
206 s3c_pm_init(); 204 s3c_pm_init();
207 205
206 s3c_nand_set_platdata(&rx3715_nand_info);
208 s3c24xx_fb_set_platdata(&rx3715_fb_info); 207 s3c24xx_fb_set_platdata(&rx3715_fb_info);
209 platform_add_devices(rx3715_devices, ARRAY_SIZE(rx3715_devices)); 208 platform_add_devices(rx3715_devices, ARRAY_SIZE(rx3715_devices));
210} 209}
diff --git a/arch/arm/mach-s3c2440/mach-smdk2440.c b/arch/arm/mach-s3c2440/mach-smdk2440.c
index db6eafbd4d90..3ac3d636d615 100644
--- a/arch/arm/mach-s3c2440/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2440/mach-smdk2440.c
@@ -1,6 +1,6 @@
1/* linux/arch/arm/mach-s3c2440/mach-smdk2440.c 1/* linux/arch/arm/mach-s3c2440/mach-smdk2440.c
2 * 2 *
3 * Copyright (c) 2004,2005 Simtec Electronics 3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * 5 *
6 * http://www.fluff.org/ben/smdk2440/ 6 * http://www.fluff.org/ben/smdk2440/
@@ -40,7 +40,7 @@
40#include <plat/iic.h> 40#include <plat/iic.h>
41 41
42#include <plat/s3c2410.h> 42#include <plat/s3c2410.h>
43#include <plat/s3c2440.h> 43#include <plat/s3c244x.h>
44#include <plat/clock.h> 44#include <plat/clock.h>
45#include <plat/devs.h> 45#include <plat/devs.h>
46#include <plat/cpu.h> 46#include <plat/cpu.h>
@@ -150,7 +150,7 @@ static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = {
150}; 150};
151 151
152static struct platform_device *smdk2440_devices[] __initdata = { 152static struct platform_device *smdk2440_devices[] __initdata = {
153 &s3c_device_usb, 153 &s3c_device_ohci,
154 &s3c_device_lcd, 154 &s3c_device_lcd,
155 &s3c_device_wdt, 155 &s3c_device_wdt,
156 &s3c_device_i2c0, 156 &s3c_device_i2c0,
diff --git a/arch/arm/mach-s3c2440/s3c2440-cpufreq.c b/arch/arm/mach-s3c2440/s3c2440-cpufreq.c
new file mode 100644
index 000000000000..976002fb1b8f
--- /dev/null
+++ b/arch/arm/mach-s3c2440/s3c2440-cpufreq.c
@@ -0,0 +1,311 @@
1/* linux/arch/arm/plat-s3c24xx/s3c2440-cpufreq.c
2 *
3 * Copyright (c) 2006-2009 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 * Vincent Sanders <vince@simtec.co.uk>
7 *
8 * S3C2440/S3C2442 CPU Frequency scaling
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/interrupt.h>
18#include <linux/ioport.h>
19#include <linux/cpufreq.h>
20#include <linux/sysdev.h>
21#include <linux/delay.h>
22#include <linux/clk.h>
23#include <linux/err.h>
24#include <linux/io.h>
25
26#include <mach/hardware.h>
27
28#include <asm/mach/arch.h>
29#include <asm/mach/map.h>
30
31#include <mach/regs-clock.h>
32
33#include <plat/cpu.h>
34#include <plat/cpu-freq-core.h>
35#include <plat/clock.h>
36
37static struct clk *xtal;
38static struct clk *fclk;
39static struct clk *hclk;
40static struct clk *armclk;
41
42/* HDIV: 1, 2, 3, 4, 6, 8 */
43
44static inline int within_khz(unsigned long a, unsigned long b)
45{
46 long diff = a - b;
47
48 return (diff >= -1000 && diff <= 1000);
49}
50
51/**
52 * s3c2440_cpufreq_calcdivs - calculate divider settings
53 * @cfg: The cpu frequency settings.
54 *
55 * Calcualte the divider values for the given frequency settings
56 * specified in @cfg. The values are stored in @cfg for later use
57 * by the relevant set routine if the request settings can be reached.
58 */
59int s3c2440_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg)
60{
61 unsigned int hdiv, pdiv;
62 unsigned long hclk, fclk, armclk;
63 unsigned long hclk_max;
64
65 fclk = cfg->freq.fclk;
66 armclk = cfg->freq.armclk;
67 hclk_max = cfg->max.hclk;
68
69 s3c_freq_dbg("%s: fclk is %lu, armclk %lu, max hclk %lu\n",
70 __func__, fclk, armclk, hclk_max);
71
72 if (armclk > fclk) {
73 printk(KERN_WARNING "%s: armclk > fclk\n", __func__);
74 armclk = fclk;
75 }
76
77 /* if we are in DVS, we need HCLK to be <= ARMCLK */
78 if (armclk < fclk && armclk < hclk_max)
79 hclk_max = armclk;
80
81 for (hdiv = 1; hdiv < 9; hdiv++) {
82 if (hdiv == 5 || hdiv == 7)
83 hdiv++;
84
85 hclk = (fclk / hdiv);
86 if (hclk <= hclk_max || within_khz(hclk, hclk_max))
87 break;
88 }
89
90 s3c_freq_dbg("%s: hclk %lu, div %d\n", __func__, hclk, hdiv);
91
92 if (hdiv > 8)
93 goto invalid;
94
95 pdiv = (hclk > cfg->max.pclk) ? 2 : 1;
96
97 if ((hclk / pdiv) > cfg->max.pclk)
98 pdiv++;
99
100 s3c_freq_dbg("%s: pdiv %d\n", __func__, pdiv);
101
102 if (pdiv > 2)
103 goto invalid;
104
105 pdiv *= hdiv;
106
107 /* calculate a valid armclk */
108
109 if (armclk < hclk)
110 armclk = hclk;
111
112 /* if we're running armclk lower than fclk, this really means
113 * that the system should go into dvs mode, which means that
114 * armclk is connected to hclk. */
115 if (armclk < fclk) {
116 cfg->divs.dvs = 1;
117 armclk = hclk;
118 } else
119 cfg->divs.dvs = 0;
120
121 cfg->freq.armclk = armclk;
122
123 /* store the result, and then return */
124
125 cfg->divs.h_divisor = hdiv;
126 cfg->divs.p_divisor = pdiv;
127
128 return 0;
129
130 invalid:
131 return -EINVAL;
132}
133
134#define CAMDIVN_HCLK_HALF (S3C2440_CAMDIVN_HCLK3_HALF | \
135 S3C2440_CAMDIVN_HCLK4_HALF)
136
137/**
138 * s3c2440_cpufreq_setdivs - set the cpu frequency divider settings
139 * @cfg: The cpu frequency settings.
140 *
141 * Set the divisors from the settings in @cfg, which where generated
142 * during the calculation phase by s3c2440_cpufreq_calcdivs().
143 */
144static void s3c2440_cpufreq_setdivs(struct s3c_cpufreq_config *cfg)
145{
146 unsigned long clkdiv, camdiv;
147
148 s3c_freq_dbg("%s: divsiors: h=%d, p=%d\n", __func__,
149 cfg->divs.h_divisor, cfg->divs.p_divisor);
150
151 clkdiv = __raw_readl(S3C2410_CLKDIVN);
152 camdiv = __raw_readl(S3C2440_CAMDIVN);
153
154 clkdiv &= ~(S3C2440_CLKDIVN_HDIVN_MASK | S3C2440_CLKDIVN_PDIVN);
155 camdiv &= ~CAMDIVN_HCLK_HALF;
156
157 switch (cfg->divs.h_divisor) {
158 case 1:
159 clkdiv |= S3C2440_CLKDIVN_HDIVN_1;
160 break;
161
162 case 2:
163 clkdiv |= S3C2440_CLKDIVN_HDIVN_2;
164 break;
165
166 case 6:
167 camdiv |= S3C2440_CAMDIVN_HCLK3_HALF;
168 case 3:
169 clkdiv |= S3C2440_CLKDIVN_HDIVN_3_6;
170 break;
171
172 case 8:
173 camdiv |= S3C2440_CAMDIVN_HCLK4_HALF;
174 case 4:
175 clkdiv |= S3C2440_CLKDIVN_HDIVN_4_8;
176 break;
177
178 default:
179 BUG(); /* we don't expect to get here. */
180 }
181
182 if (cfg->divs.p_divisor != cfg->divs.h_divisor)
183 clkdiv |= S3C2440_CLKDIVN_PDIVN;
184
185 /* todo - set pclk. */
186
187 /* Write the divisors first with hclk intentionally halved so that
188 * when we write clkdiv we will under-frequency instead of over. We
189 * then make a short delay and remove the hclk halving if necessary.
190 */
191
192 __raw_writel(camdiv | CAMDIVN_HCLK_HALF, S3C2440_CAMDIVN);
193 __raw_writel(clkdiv, S3C2410_CLKDIVN);
194
195 ndelay(20);
196 __raw_writel(camdiv, S3C2440_CAMDIVN);
197
198 clk_set_parent(armclk, cfg->divs.dvs ? hclk : fclk);
199}
200
201static int run_freq_for(unsigned long max_hclk, unsigned long fclk,
202 int *divs,
203 struct cpufreq_frequency_table *table,
204 size_t table_size)
205{
206 unsigned long freq;
207 int index = 0;
208 int div;
209
210 for (div = *divs; div > 0; div = *divs++) {
211 freq = fclk / div;
212
213 if (freq > max_hclk && div != 1)
214 continue;
215
216 freq /= 1000; /* table is in kHz */
217 index = s3c_cpufreq_addfreq(table, index, table_size, freq);
218 if (index < 0)
219 break;
220 }
221
222 return index;
223}
224
225static int hclk_divs[] = { 1, 2, 3, 4, 6, 8, -1 };
226
227static int s3c2440_cpufreq_calctable(struct s3c_cpufreq_config *cfg,
228 struct cpufreq_frequency_table *table,
229 size_t table_size)
230{
231 int ret;
232
233 WARN_ON(cfg->info == NULL);
234 WARN_ON(cfg->board == NULL);
235
236 ret = run_freq_for(cfg->info->max.hclk,
237 cfg->info->max.fclk,
238 hclk_divs,
239 table, table_size);
240
241 s3c_freq_dbg("%s: returning %d\n", __func__, ret);
242
243 return ret;
244}
245
246struct s3c_cpufreq_info s3c2440_cpufreq_info = {
247 .max = {
248 .fclk = 400000000,
249 .hclk = 133333333,
250 .pclk = 66666666,
251 },
252
253 .locktime_m = 300,
254 .locktime_u = 300,
255 .locktime_bits = 16,
256
257 .name = "s3c244x",
258 .calc_iotiming = s3c2410_iotiming_calc,
259 .set_iotiming = s3c2410_iotiming_set,
260 .get_iotiming = s3c2410_iotiming_get,
261 .set_fvco = s3c2410_set_fvco,
262
263 .set_refresh = s3c2410_cpufreq_setrefresh,
264 .set_divs = s3c2440_cpufreq_setdivs,
265 .calc_divs = s3c2440_cpufreq_calcdivs,
266 .calc_freqtable = s3c2440_cpufreq_calctable,
267
268 .resume_clocks = s3c244x_setup_clocks,
269
270 .debug_io_show = s3c_cpufreq_debugfs_call(s3c2410_iotiming_debugfs),
271};
272
273static int s3c2440_cpufreq_add(struct sys_device *sysdev)
274{
275 xtal = s3c_cpufreq_clk_get(NULL, "xtal");
276 hclk = s3c_cpufreq_clk_get(NULL, "hclk");
277 fclk = s3c_cpufreq_clk_get(NULL, "fclk");
278 armclk = s3c_cpufreq_clk_get(NULL, "armclk");
279
280 if (IS_ERR(xtal) || IS_ERR(hclk) || IS_ERR(fclk) || IS_ERR(armclk)) {
281 printk(KERN_ERR "%s: failed to get clocks\n", __func__);
282 return -ENOENT;
283 }
284
285 return s3c_cpufreq_register(&s3c2440_cpufreq_info);
286}
287
288static struct sysdev_driver s3c2440_cpufreq_driver = {
289 .add = s3c2440_cpufreq_add,
290};
291
292static int s3c2440_cpufreq_init(void)
293{
294 return sysdev_driver_register(&s3c2440_sysclass,
295 &s3c2440_cpufreq_driver);
296}
297
298/* arch_initcall adds the clocks we need, so use subsys_initcall. */
299subsys_initcall(s3c2440_cpufreq_init);
300
301static struct sysdev_driver s3c2442_cpufreq_driver = {
302 .add = s3c2440_cpufreq_add,
303};
304
305static int s3c2442_cpufreq_init(void)
306{
307 return sysdev_driver_register(&s3c2442_sysclass,
308 &s3c2442_cpufreq_driver);
309}
310
311subsys_initcall(s3c2442_cpufreq_init);
diff --git a/arch/arm/mach-s3c2440/s3c2440-pll-12000000.c b/arch/arm/mach-s3c2440/s3c2440-pll-12000000.c
new file mode 100644
index 000000000000..f105d5e8c477
--- /dev/null
+++ b/arch/arm/mach-s3c2440/s3c2440-pll-12000000.c
@@ -0,0 +1,97 @@
1/* arch/arm/mach-s3c2440/s3c2440-pll-12000000.c
2 *
3 * Copyright (c) 2006-2007 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 * Vincent Sanders <vince@arm.linux.org.uk>
7 *
8 * S3C2440/S3C2442 CPU PLL tables (12MHz Crystal)
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#include <linux/types.h>
16#include <linux/kernel.h>
17#include <linux/sysdev.h>
18#include <linux/clk.h>
19#include <linux/err.h>
20
21#include <plat/cpu.h>
22#include <plat/cpu-freq-core.h>
23
24static struct cpufreq_frequency_table s3c2440_plls_12[] __initdata = {
25 { .frequency = 75000000, .index = PLLVAL(0x75, 3, 3), }, /* FVco 600.000000 */
26 { .frequency = 80000000, .index = PLLVAL(0x98, 4, 3), }, /* FVco 640.000000 */
27 { .frequency = 90000000, .index = PLLVAL(0x70, 2, 3), }, /* FVco 720.000000 */
28 { .frequency = 100000000, .index = PLLVAL(0x5c, 1, 3), }, /* FVco 800.000000 */
29 { .frequency = 110000000, .index = PLLVAL(0x66, 1, 3), }, /* FVco 880.000000 */
30 { .frequency = 120000000, .index = PLLVAL(0x70, 1, 3), }, /* FVco 960.000000 */
31 { .frequency = 150000000, .index = PLLVAL(0x75, 3, 2), }, /* FVco 600.000000 */
32 { .frequency = 160000000, .index = PLLVAL(0x98, 4, 2), }, /* FVco 640.000000 */
33 { .frequency = 170000000, .index = PLLVAL(0x4d, 1, 2), }, /* FVco 680.000000 */
34 { .frequency = 180000000, .index = PLLVAL(0x70, 2, 2), }, /* FVco 720.000000 */
35 { .frequency = 190000000, .index = PLLVAL(0x57, 1, 2), }, /* FVco 760.000000 */
36 { .frequency = 200000000, .index = PLLVAL(0x5c, 1, 2), }, /* FVco 800.000000 */
37 { .frequency = 210000000, .index = PLLVAL(0x84, 2, 2), }, /* FVco 840.000000 */
38 { .frequency = 220000000, .index = PLLVAL(0x66, 1, 2), }, /* FVco 880.000000 */
39 { .frequency = 230000000, .index = PLLVAL(0x6b, 1, 2), }, /* FVco 920.000000 */
40 { .frequency = 240000000, .index = PLLVAL(0x70, 1, 2), }, /* FVco 960.000000 */
41 { .frequency = 300000000, .index = PLLVAL(0x75, 3, 1), }, /* FVco 600.000000 */
42 { .frequency = 310000000, .index = PLLVAL(0x93, 4, 1), }, /* FVco 620.000000 */
43 { .frequency = 320000000, .index = PLLVAL(0x98, 4, 1), }, /* FVco 640.000000 */
44 { .frequency = 330000000, .index = PLLVAL(0x66, 2, 1), }, /* FVco 660.000000 */
45 { .frequency = 340000000, .index = PLLVAL(0x4d, 1, 1), }, /* FVco 680.000000 */
46 { .frequency = 350000000, .index = PLLVAL(0xa7, 4, 1), }, /* FVco 700.000000 */
47 { .frequency = 360000000, .index = PLLVAL(0x70, 2, 1), }, /* FVco 720.000000 */
48 { .frequency = 370000000, .index = PLLVAL(0xb1, 4, 1), }, /* FVco 740.000000 */
49 { .frequency = 380000000, .index = PLLVAL(0x57, 1, 1), }, /* FVco 760.000000 */
50 { .frequency = 390000000, .index = PLLVAL(0x7a, 2, 1), }, /* FVco 780.000000 */
51 { .frequency = 400000000, .index = PLLVAL(0x5c, 1, 1), }, /* FVco 800.000000 */
52};
53
54static int s3c2440_plls12_add(struct sys_device *dev)
55{
56 struct clk *xtal_clk;
57 unsigned long xtal;
58
59 xtal_clk = clk_get(NULL, "xtal");
60 if (IS_ERR(xtal_clk))
61 return PTR_ERR(xtal_clk);
62
63 xtal = clk_get_rate(xtal_clk);
64 clk_put(xtal_clk);
65
66 if (xtal == 12000000) {
67 printk(KERN_INFO "Using PLL table for 12MHz crystal\n");
68 return s3c_plltab_register(s3c2440_plls_12,
69 ARRAY_SIZE(s3c2440_plls_12));
70 }
71
72 return 0;
73}
74
75static struct sysdev_driver s3c2440_plls12_drv = {
76 .add = s3c2440_plls12_add,
77};
78
79static int __init s3c2440_pll_12mhz(void)
80{
81 return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_plls12_drv);
82
83}
84
85arch_initcall(s3c2440_pll_12mhz);
86
87static struct sysdev_driver s3c2442_plls12_drv = {
88 .add = s3c2440_plls12_add,
89};
90
91static int __init s3c2442_pll_12mhz(void)
92{
93 return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_plls12_drv);
94
95}
96
97arch_initcall(s3c2442_pll_12mhz);
diff --git a/arch/arm/mach-s3c2440/s3c2440-pll-16934400.c b/arch/arm/mach-s3c2440/s3c2440-pll-16934400.c
new file mode 100644
index 000000000000..c8a8f90ef382
--- /dev/null
+++ b/arch/arm/mach-s3c2440/s3c2440-pll-16934400.c
@@ -0,0 +1,127 @@
1/* arch/arm/mach-s3c2440/s3c2440-pll-16934400.c
2 *
3 * Copyright (c) 2006-2008 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 * Vincent Sanders <vince@arm.linux.org.uk>
7 *
8 * S3C2440/S3C2442 CPU PLL tables (16.93444MHz Crystal)
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#include <linux/types.h>
16#include <linux/kernel.h>
17#include <linux/sysdev.h>
18#include <linux/clk.h>
19#include <linux/err.h>
20
21#include <plat/cpu.h>
22#include <plat/cpu-freq-core.h>
23
24static struct cpufreq_frequency_table s3c2440_plls_169344[] __initdata = {
25 { .frequency = 78019200, .index = PLLVAL(121, 5, 3), }, /* FVco 624.153600 */
26 { .frequency = 84067200, .index = PLLVAL(131, 5, 3), }, /* FVco 672.537600 */
27 { .frequency = 90115200, .index = PLLVAL(141, 5, 3), }, /* FVco 720.921600 */
28 { .frequency = 96163200, .index = PLLVAL(151, 5, 3), }, /* FVco 769.305600 */
29 { .frequency = 102135600, .index = PLLVAL(185, 6, 3), }, /* FVco 817.084800 */
30 { .frequency = 108259200, .index = PLLVAL(171, 5, 3), }, /* FVco 866.073600 */
31 { .frequency = 114307200, .index = PLLVAL(127, 3, 3), }, /* FVco 914.457600 */
32 { .frequency = 120234240, .index = PLLVAL(134, 3, 3), }, /* FVco 961.873920 */
33 { .frequency = 126161280, .index = PLLVAL(141, 3, 3), }, /* FVco 1009.290240 */
34 { .frequency = 132088320, .index = PLLVAL(148, 3, 3), }, /* FVco 1056.706560 */
35 { .frequency = 138015360, .index = PLLVAL(155, 3, 3), }, /* FVco 1104.122880 */
36 { .frequency = 144789120, .index = PLLVAL(163, 3, 3), }, /* FVco 1158.312960 */
37 { .frequency = 150100363, .index = PLLVAL(187, 9, 2), }, /* FVco 600.401454 */
38 { .frequency = 156038400, .index = PLLVAL(121, 5, 2), }, /* FVco 624.153600 */
39 { .frequency = 162086400, .index = PLLVAL(126, 5, 2), }, /* FVco 648.345600 */
40 { .frequency = 168134400, .index = PLLVAL(131, 5, 2), }, /* FVco 672.537600 */
41 { .frequency = 174048000, .index = PLLVAL(177, 7, 2), }, /* FVco 696.192000 */
42 { .frequency = 180230400, .index = PLLVAL(141, 5, 2), }, /* FVco 720.921600 */
43 { .frequency = 186278400, .index = PLLVAL(124, 4, 2), }, /* FVco 745.113600 */
44 { .frequency = 192326400, .index = PLLVAL(151, 5, 2), }, /* FVco 769.305600 */
45 { .frequency = 198132480, .index = PLLVAL(109, 3, 2), }, /* FVco 792.529920 */
46 { .frequency = 204271200, .index = PLLVAL(185, 6, 2), }, /* FVco 817.084800 */
47 { .frequency = 210268800, .index = PLLVAL(141, 4, 2), }, /* FVco 841.075200 */
48 { .frequency = 216518400, .index = PLLVAL(171, 5, 2), }, /* FVco 866.073600 */
49 { .frequency = 222264000, .index = PLLVAL(97, 2, 2), }, /* FVco 889.056000 */
50 { .frequency = 228614400, .index = PLLVAL(127, 3, 2), }, /* FVco 914.457600 */
51 { .frequency = 234259200, .index = PLLVAL(158, 4, 2), }, /* FVco 937.036800 */
52 { .frequency = 240468480, .index = PLLVAL(134, 3, 2), }, /* FVco 961.873920 */
53 { .frequency = 246960000, .index = PLLVAL(167, 4, 2), }, /* FVco 987.840000 */
54 { .frequency = 252322560, .index = PLLVAL(141, 3, 2), }, /* FVco 1009.290240 */
55 { .frequency = 258249600, .index = PLLVAL(114, 2, 2), }, /* FVco 1032.998400 */
56 { .frequency = 264176640, .index = PLLVAL(148, 3, 2), }, /* FVco 1056.706560 */
57 { .frequency = 270950400, .index = PLLVAL(120, 2, 2), }, /* FVco 1083.801600 */
58 { .frequency = 276030720, .index = PLLVAL(155, 3, 2), }, /* FVco 1104.122880 */
59 { .frequency = 282240000, .index = PLLVAL(92, 1, 2), }, /* FVco 1128.960000 */
60 { .frequency = 289578240, .index = PLLVAL(163, 3, 2), }, /* FVco 1158.312960 */
61 { .frequency = 294235200, .index = PLLVAL(131, 2, 2), }, /* FVco 1176.940800 */
62 { .frequency = 300200727, .index = PLLVAL(187, 9, 1), }, /* FVco 600.401454 */
63 { .frequency = 306358690, .index = PLLVAL(191, 9, 1), }, /* FVco 612.717380 */
64 { .frequency = 312076800, .index = PLLVAL(121, 5, 1), }, /* FVco 624.153600 */
65 { .frequency = 318366720, .index = PLLVAL(86, 3, 1), }, /* FVco 636.733440 */
66 { .frequency = 324172800, .index = PLLVAL(126, 5, 1), }, /* FVco 648.345600 */
67 { .frequency = 330220800, .index = PLLVAL(109, 4, 1), }, /* FVco 660.441600 */
68 { .frequency = 336268800, .index = PLLVAL(131, 5, 1), }, /* FVco 672.537600 */
69 { .frequency = 342074880, .index = PLLVAL(93, 3, 1), }, /* FVco 684.149760 */
70 { .frequency = 348096000, .index = PLLVAL(177, 7, 1), }, /* FVco 696.192000 */
71 { .frequency = 355622400, .index = PLLVAL(118, 4, 1), }, /* FVco 711.244800 */
72 { .frequency = 360460800, .index = PLLVAL(141, 5, 1), }, /* FVco 720.921600 */
73 { .frequency = 366206400, .index = PLLVAL(165, 6, 1), }, /* FVco 732.412800 */
74 { .frequency = 372556800, .index = PLLVAL(124, 4, 1), }, /* FVco 745.113600 */
75 { .frequency = 378201600, .index = PLLVAL(126, 4, 1), }, /* FVco 756.403200 */
76 { .frequency = 384652800, .index = PLLVAL(151, 5, 1), }, /* FVco 769.305600 */
77 { .frequency = 391608000, .index = PLLVAL(177, 6, 1), }, /* FVco 783.216000 */
78 { .frequency = 396264960, .index = PLLVAL(109, 3, 1), }, /* FVco 792.529920 */
79 { .frequency = 402192000, .index = PLLVAL(87, 2, 1), }, /* FVco 804.384000 */
80};
81
82static int s3c2440_plls169344_add(struct sys_device *dev)
83{
84 struct clk *xtal_clk;
85 unsigned long xtal;
86
87 xtal_clk = clk_get(NULL, "xtal");
88 if (IS_ERR(xtal_clk))
89 return PTR_ERR(xtal_clk);
90
91 xtal = clk_get_rate(xtal_clk);
92 clk_put(xtal_clk);
93
94 if (xtal == 169344000) {
95 printk(KERN_INFO "Using PLL table for 16.9344MHz crystal\n");
96 return s3c_plltab_register(s3c2440_plls_169344,
97 ARRAY_SIZE(s3c2440_plls_169344));
98 }
99
100 return 0;
101}
102
103static struct sysdev_driver s3c2440_plls169344_drv = {
104 .add = s3c2440_plls169344_add,
105};
106
107static int __init s3c2440_pll_16934400(void)
108{
109 return sysdev_driver_register(&s3c2440_sysclass,
110 &s3c2440_plls169344_drv);
111
112}
113
114arch_initcall(s3c2440_pll_16934400);
115
116static struct sysdev_driver s3c2442_plls169344_drv = {
117 .add = s3c2440_plls169344_add,
118};
119
120static int __init s3c2442_pll_16934400(void)
121{
122 return sysdev_driver_register(&s3c2442_sysclass,
123 &s3c2442_plls169344_drv);
124
125}
126
127arch_initcall(s3c2442_pll_16934400);
diff --git a/arch/arm/mach-s3c2440/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c
index ac1f7ea5f405..2b68f7ea45ae 100644
--- a/arch/arm/mach-s3c2440/s3c2440.c
+++ b/arch/arm/mach-s3c2440/s3c2440.c
@@ -29,9 +29,9 @@
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/s3c2440.h>
33#include <plat/devs.h> 32#include <plat/devs.h>
34#include <plat/cpu.h> 33#include <plat/cpu.h>
34#include <plat/s3c244x.h>
35 35
36static struct sys_device s3c2440_sysdev = { 36static struct sys_device s3c2440_sysdev = {
37 .cls = &s3c2440_sysclass, 37 .cls = &s3c2440_sysclass,
diff --git a/arch/arm/mach-s3c2440/s3c2442.c b/arch/arm/mach-s3c2440/s3c2442.c
new file mode 100644
index 000000000000..188ad1e57dc0
--- /dev/null
+++ b/arch/arm/mach-s3c2440/s3c2442.c
@@ -0,0 +1,165 @@
1/* linux/arch/arm/mach-s3c2442/s3c2442.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 core and lock 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#include <linux/io.h>
37
38#include <mach/hardware.h>
39#include <asm/atomic.h>
40#include <asm/irq.h>
41
42#include <mach/regs-clock.h>
43
44#include <plat/clock.h>
45#include <plat/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 = s3c2410_clkcon_enable,
106 .ctrlbit = S3C2440_CLKCON_CAMERA,
107};
108
109static struct clk s3c2442_clk_cam_upll = {
110 .name = "camif-upll",
111 .id = -1,
112 .ops = &(struct clk_ops) {
113 .set_rate = s3c2442_camif_upll_setrate,
114 .round_rate = s3c2442_camif_upll_round,
115 },
116};
117
118static int s3c2442_clk_add(struct sys_device *sysdev)
119{
120 struct clk *clock_upll;
121 struct clk *clock_h;
122 struct clk *clock_p;
123
124 clock_p = clk_get(NULL, "pclk");
125 clock_h = clk_get(NULL, "hclk");
126 clock_upll = clk_get(NULL, "upll");
127
128 if (IS_ERR(clock_p) || IS_ERR(clock_h) || IS_ERR(clock_upll)) {
129 printk(KERN_ERR "S3C2442: Failed to get parent clocks\n");
130 return -EINVAL;
131 }
132
133 s3c2442_clk_cam.parent = clock_h;
134 s3c2442_clk_cam_upll.parent = clock_upll;
135
136 s3c24xx_register_clock(&s3c2442_clk_cam);
137 s3c24xx_register_clock(&s3c2442_clk_cam_upll);
138
139 clk_disable(&s3c2442_clk_cam);
140
141 return 0;
142}
143
144static struct sysdev_driver s3c2442_clk_driver = {
145 .add = s3c2442_clk_add,
146};
147
148static __init int s3c2442_clk_init(void)
149{
150 return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_clk_driver);
151}
152
153arch_initcall(s3c2442_clk_init);
154
155
156static struct sys_device s3c2442_sysdev = {
157 .cls = &s3c2442_sysclass,
158};
159
160int __init s3c2442_init(void)
161{
162 printk("S3C2442: Initialising architecture\n");
163
164 return sysdev_register(&s3c2442_sysdev);
165}
diff --git a/arch/arm/mach-s3c2440/s3c244x-clock.c b/arch/arm/mach-s3c2440/s3c244x-clock.c
new file mode 100644
index 000000000000..f8d96130d1d1
--- /dev/null
+++ b/arch/arm/mach-s3c2440/s3c244x-clock.c
@@ -0,0 +1,138 @@
1/* linux/arch/arm/plat-s3c24xx/s3c24xx-clock.c
2 *
3 * Copyright (c) 2004-2008 Simtec Electronics
4 * http://armlinux.simtec.co.uk/
5 * Ben Dooks <ben@simtec.co.uk>
6 *
7 * S3C2440/S3C2442 Common 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/clk.h>
35#include <linux/io.h>
36
37#include <mach/hardware.h>
38#include <asm/atomic.h>
39#include <asm/irq.h>
40
41#include <mach/regs-clock.h>
42
43#include <plat/clock.h>
44#include <plat/cpu.h>
45
46static int s3c2440_setparent_armclk(struct clk *clk, struct clk *parent)
47{
48 unsigned long camdivn;
49 unsigned long dvs;
50
51 if (parent == &clk_f)
52 dvs = 0;
53 else if (parent == &clk_h)
54 dvs = S3C2440_CAMDIVN_DVSEN;
55 else
56 return -EINVAL;
57
58 clk->parent = parent;
59
60 camdivn = __raw_readl(S3C2440_CAMDIVN);
61 camdivn &= ~S3C2440_CAMDIVN_DVSEN;
62 camdivn |= dvs;
63 __raw_writel(camdivn, S3C2440_CAMDIVN);
64
65 return 0;
66}
67
68static struct clk clk_arm = {
69 .name = "armclk",
70 .id = -1,
71 .ops = &(struct clk_ops) {
72 .set_parent = s3c2440_setparent_armclk,
73 },
74};
75
76static int s3c244x_clk_add(struct sys_device *sysdev)
77{
78 unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
79 unsigned long clkdivn;
80 struct clk *clock_upll;
81 int ret;
82
83 printk("S3C244X: Clock Support, DVS %s\n",
84 (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
85
86 clk_arm.parent = (camdivn & S3C2440_CAMDIVN_DVSEN) ? &clk_h : &clk_f;
87
88 ret = s3c24xx_register_clock(&clk_arm);
89 if (ret < 0) {
90 printk(KERN_ERR "S3C24XX: Failed to add armclk (%d)\n", ret);
91 return ret;
92 }
93
94 clock_upll = clk_get(NULL, "upll");
95 if (IS_ERR(clock_upll)) {
96 printk(KERN_ERR "S3C244X: Failed to get upll clock\n");
97 return -ENOENT;
98 }
99
100 /* check rate of UPLL, and if it is near 96MHz, then change
101 * to using half the UPLL rate for the system */
102
103 if (clk_get_rate(clock_upll) > (94 * MHZ)) {
104 clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
105
106 spin_lock(&clocks_lock);
107
108 clkdivn = __raw_readl(S3C2410_CLKDIVN);
109 clkdivn |= S3C2440_CLKDIVN_UCLK;
110 __raw_writel(clkdivn, S3C2410_CLKDIVN);
111
112 spin_unlock(&clocks_lock);
113 }
114
115 return 0;
116}
117
118static struct sysdev_driver s3c2440_clk_driver = {
119 .add = s3c244x_clk_add,
120};
121
122static int s3c2440_clk_init(void)
123{
124 return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_clk_driver);
125}
126
127arch_initcall(s3c2440_clk_init);
128
129static struct sysdev_driver s3c2442_clk_driver = {
130 .add = s3c244x_clk_add,
131};
132
133static int s3c2442_clk_init(void)
134{
135 return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_clk_driver);
136}
137
138arch_initcall(s3c2442_clk_init);
diff --git a/arch/arm/mach-s3c2440/s3c244x-irq.c b/arch/arm/mach-s3c2440/s3c244x-irq.c
new file mode 100644
index 000000000000..a75c0c2431ea
--- /dev/null
+++ b/arch/arm/mach-s3c2440/s3c244x-irq.c
@@ -0,0 +1,142 @@
1/* linux/arch/arm/plat-s3c24xx/s3c244x-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*/
21
22#include <linux/init.h>
23#include <linux/module.h>
24#include <linux/interrupt.h>
25#include <linux/ioport.h>
26#include <linux/sysdev.h>
27#include <linux/io.h>
28
29#include <mach/hardware.h>
30#include <asm/irq.h>
31
32#include <asm/mach/irq.h>
33
34#include <mach/regs-irq.h>
35#include <mach/regs-gpio.h>
36
37#include <plat/cpu.h>
38#include <plat/pm.h>
39#include <plat/irq.h>
40
41/* camera irq */
42
43static void s3c_irq_demux_cam(unsigned int irq,
44 struct irq_desc *desc)
45{
46 unsigned int subsrc, submsk;
47
48 /* read the current pending interrupts, and the mask
49 * for what it is available */
50
51 subsrc = __raw_readl(S3C2410_SUBSRCPND);
52 submsk = __raw_readl(S3C2410_INTSUBMSK);
53
54 subsrc &= ~submsk;
55 subsrc >>= 11;
56 subsrc &= 3;
57
58 if (subsrc != 0) {
59 if (subsrc & 1) {
60 generic_handle_irq(IRQ_S3C2440_CAM_C);
61 }
62 if (subsrc & 2) {
63 generic_handle_irq(IRQ_S3C2440_CAM_P);
64 }
65 }
66}
67
68#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
69
70static void
71s3c_irq_cam_mask(unsigned int irqno)
72{
73 s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11);
74}
75
76static void
77s3c_irq_cam_unmask(unsigned int irqno)
78{
79 s3c_irqsub_unmask(irqno, INTMSK_CAM);
80}
81
82static void
83s3c_irq_cam_ack(unsigned int irqno)
84{
85 s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11);
86}
87
88static struct irq_chip s3c_irq_cam = {
89 .mask = s3c_irq_cam_mask,
90 .unmask = s3c_irq_cam_unmask,
91 .ack = s3c_irq_cam_ack,
92};
93
94static int s3c244x_irq_add(struct sys_device *sysdev)
95{
96 unsigned int irqno;
97
98 set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip);
99 set_irq_handler(IRQ_NFCON, handle_level_irq);
100 set_irq_flags(IRQ_NFCON, IRQF_VALID);
101
102 /* add chained handler for camera */
103
104 set_irq_chip(IRQ_CAM, &s3c_irq_level_chip);
105 set_irq_handler(IRQ_CAM, handle_level_irq);
106 set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam);
107
108 for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) {
109 set_irq_chip(irqno, &s3c_irq_cam);
110 set_irq_handler(irqno, handle_level_irq);
111 set_irq_flags(irqno, IRQF_VALID);
112 }
113
114 return 0;
115}
116
117static struct sysdev_driver s3c2440_irq_driver = {
118 .add = s3c244x_irq_add,
119 .suspend = s3c24xx_irq_suspend,
120 .resume = s3c24xx_irq_resume,
121};
122
123static int s3c2440_irq_init(void)
124{
125 return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver);
126}
127
128arch_initcall(s3c2440_irq_init);
129
130static struct sysdev_driver s3c2442_irq_driver = {
131 .add = s3c244x_irq_add,
132 .suspend = s3c24xx_irq_suspend,
133 .resume = s3c24xx_irq_resume,
134};
135
136
137static int s3c2442_irq_init(void)
138{
139 return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_irq_driver);
140}
141
142arch_initcall(s3c2442_irq_init);
diff --git a/arch/arm/mach-s3c2440/s3c244x.c b/arch/arm/mach-s3c2440/s3c244x.c
new file mode 100644
index 000000000000..5e4a97e76533
--- /dev/null
+++ b/arch/arm/mach-s3c2440/s3c244x.c
@@ -0,0 +1,195 @@
1/* linux/arch/arm/plat-s3c24xx/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 (not S3C2443)
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/serial_core.h>
20#include <linux/platform_device.h>
21#include <linux/sysdev.h>
22#include <linux/clk.h>
23#include <linux/io.h>
24
25#include <asm/mach/arch.h>
26#include <asm/mach/map.h>
27#include <asm/mach/irq.h>
28
29#include <mach/hardware.h>
30#include <asm/irq.h>
31
32#include <plat/cpu-freq.h>
33
34#include <mach/regs-clock.h>
35#include <plat/regs-serial.h>
36#include <mach/regs-gpio.h>
37#include <mach/regs-gpioj.h>
38#include <mach/regs-dsc.h>
39
40#include <plat/s3c2410.h>
41#include <plat/s3c244x.h>
42#include <plat/clock.h>
43#include <plat/devs.h>
44#include <plat/cpu.h>
45#include <plat/pm.h>
46#include <plat/pll.h>
47
48static struct map_desc s3c244x_iodesc[] __initdata = {
49 IODESC_ENT(CLKPWR),
50 IODESC_ENT(TIMER),
51 IODESC_ENT(WATCHDOG),
52};
53
54/* uart initialisation */
55
56void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
57{
58 s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
59}
60
61void __init s3c244x_map_io(void)
62{
63 /* register our io-tables */
64
65 iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
66
67 /* rename any peripherals used differing from the s3c2410 */
68
69 s3c_device_sdi.name = "s3c2440-sdi";
70 s3c_device_i2c0.name = "s3c2440-i2c";
71 s3c_device_nand.name = "s3c2440-nand";
72 s3c_device_ts.name = "s3c2440-ts";
73 s3c_device_usbgadget.name = "s3c2440-usbgadget";
74}
75
76void __init_or_cpufreq s3c244x_setup_clocks(void)
77{
78 struct clk *xtal_clk;
79 unsigned long clkdiv;
80 unsigned long camdiv;
81 unsigned long xtal;
82 unsigned long hclk, fclk, pclk;
83 int hdiv = 1;
84
85 xtal_clk = clk_get(NULL, "xtal");
86 xtal = clk_get_rate(xtal_clk);
87 clk_put(xtal_clk);
88
89 fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
90
91 clkdiv = __raw_readl(S3C2410_CLKDIVN);
92 camdiv = __raw_readl(S3C2440_CAMDIVN);
93
94 /* work out clock scalings */
95
96 switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
97 case S3C2440_CLKDIVN_HDIVN_1:
98 hdiv = 1;
99 break;
100
101 case S3C2440_CLKDIVN_HDIVN_2:
102 hdiv = 2;
103 break;
104
105 case S3C2440_CLKDIVN_HDIVN_4_8:
106 hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
107 break;
108
109 case S3C2440_CLKDIVN_HDIVN_3_6:
110 hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
111 break;
112 }
113
114 hclk = fclk / hdiv;
115 pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN) ? 2 : 1);
116
117 /* print brief summary of clocks, etc */
118
119 printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
120 print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
121
122 s3c24xx_setup_clocks(fclk, hclk, pclk);
123}
124
125void __init s3c244x_init_clocks(int xtal)
126{
127 /* initialise the clocks here, to allow other things like the
128 * console to use them, and to add new ones after the initialisation
129 */
130
131 s3c24xx_register_baseclocks(xtal);
132 s3c244x_setup_clocks();
133 s3c2410_baseclk_add();
134}
135
136#ifdef CONFIG_PM
137
138static struct sleep_save s3c244x_sleep[] = {
139 SAVE_ITEM(S3C2440_DSC0),
140 SAVE_ITEM(S3C2440_DSC1),
141 SAVE_ITEM(S3C2440_GPJDAT),
142 SAVE_ITEM(S3C2440_GPJCON),
143 SAVE_ITEM(S3C2440_GPJUP)
144};
145
146static int s3c244x_suspend(struct sys_device *dev, pm_message_t state)
147{
148 s3c_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
149 return 0;
150}
151
152static int s3c244x_resume(struct sys_device *dev)
153{
154 s3c_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
155 return 0;
156}
157
158#else
159#define s3c244x_suspend NULL
160#define s3c244x_resume NULL
161#endif
162
163/* Since the S3C2442 and S3C2440 share items, put both sysclasses here */
164
165struct sysdev_class s3c2440_sysclass = {
166 .name = "s3c2440-core",
167 .suspend = s3c244x_suspend,
168 .resume = s3c244x_resume
169};
170
171struct sysdev_class s3c2442_sysclass = {
172 .name = "s3c2442-core",
173 .suspend = s3c244x_suspend,
174 .resume = s3c244x_resume
175};
176
177/* need to register class before we actually register the device, and
178 * we also need to ensure that it has been initialised before any of the
179 * drivers even try to use it (even if not on an s3c2440 based system)
180 * as a driver which may support both 2410 and 2440 may try and use it.
181*/
182
183static int __init s3c2440_core_init(void)
184{
185 return sysdev_class_register(&s3c2440_sysclass);
186}
187
188core_initcall(s3c2440_core_init);
189
190static int __init s3c2442_core_init(void)
191{
192 return sysdev_class_register(&s3c2442_sysclass);
193}
194
195core_initcall(s3c2442_core_init);