aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-samsung
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-samsung')
-rw-r--r--arch/arm/plat-samsung/Kconfig140
-rw-r--r--arch/arm/plat-samsung/Makefile13
-rw-r--r--arch/arm/plat-samsung/s5p-clock.c263
-rw-r--r--arch/arm/plat-samsung/s5p-dev-mfc.c71
-rw-r--r--arch/arm/plat-samsung/s5p-dev-uart.c89
-rw-r--r--arch/arm/plat-samsung/s5p-irq-eint.c218
-rw-r--r--arch/arm/plat-samsung/s5p-irq-gpioint.c215
-rw-r--r--arch/arm/plat-samsung/s5p-irq-pm.c102
-rw-r--r--arch/arm/plat-samsung/s5p-irq.c35
-rw-r--r--arch/arm/plat-samsung/s5p-pm.c40
-rw-r--r--arch/arm/plat-samsung/s5p-sleep.S80
-rw-r--r--arch/arm/plat-samsung/s5p-time.c405
-rw-r--r--arch/arm/plat-samsung/setup-mipiphy.c63
13 files changed, 1734 insertions, 0 deletions
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index a0ffc77da809..f8c571031da8 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -13,6 +13,24 @@ config PLAT_SAMSUNG
13 help 13 help
14 Base platform code for all Samsung SoC based systems 14 Base platform code for all Samsung SoC based systems
15 15
16config PLAT_S5P
17 bool
18 depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS)
19 default y
20 select ARM_VIC if !ARCH_EXYNOS
21 select ARM_GIC if ARCH_EXYNOS
22 select GIC_NON_BANKED if ARCH_EXYNOS4
23 select NO_IOPORT
24 select ARCH_REQUIRE_GPIOLIB
25 select S3C_GPIO_TRACK
26 select S5P_GPIO_DRVSTR
27 select SAMSUNG_GPIOLIB_4BIT
28 select PLAT_SAMSUNG
29 select SAMSUNG_CLKSRC
30 select SAMSUNG_IRQ_VIC_TIMER
31 help
32 Base platform code for Samsung's S5P series SoC.
33
16if PLAT_SAMSUNG 34if PLAT_SAMSUNG
17 35
18# boot configurations 36# boot configurations
@@ -50,6 +68,14 @@ config S3C_LOWLEVEL_UART_PORT
50 this configuration should be between zero and two. The port 68 this configuration should be between zero and two. The port
51 must have been initialised by the boot-loader before use. 69 must have been initialised by the boot-loader before use.
52 70
71# timer options
72
73config S5P_HRT
74 bool
75 select SAMSUNG_DEV_PWM
76 help
77 Use the High Resolution timer support
78
53# clock options 79# clock options
54 80
55config SAMSUNG_CLKSRC 81config SAMSUNG_CLKSRC
@@ -58,6 +84,11 @@ config SAMSUNG_CLKSRC
58 Select the clock code for the clksrc implementation 84 Select the clock code for the clksrc implementation
59 used by newer systems such as the S3C64XX. 85 used by newer systems such as the S3C64XX.
60 86
87config S5P_CLOCK
88 def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS)
89 help
90 Support common clock part for ARCH_S5P and ARCH_EXYNOS SoCs
91
61# options for IRQ support 92# options for IRQ support
62 93
63config SAMSUNG_IRQ_VIC_TIMER 94config SAMSUNG_IRQ_VIC_TIMER
@@ -65,6 +96,22 @@ config SAMSUNG_IRQ_VIC_TIMER
65 help 96 help
66 Internal configuration to build the VIC timer interrupt code. 97 Internal configuration to build the VIC timer interrupt code.
67 98
99config S5P_IRQ
100 def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS)
101 help
102 Support common interrup part for ARCH_S5P and ARCH_EXYNOS SoCs
103
104config S5P_EXT_INT
105 bool
106 help
107 Use the external interrupts (other than GPIO interrupts.)
108 Note: Do not choose this for S5P6440 and S5P6450.
109
110config S5P_GPIO_INT
111 bool
112 help
113 Common code for the GPIO interrupts (other than external interrupts.)
114
68# options for gpio configuration support 115# options for gpio configuration support
69 116
70config SAMSUNG_GPIOLIB_4BIT 117config SAMSUNG_GPIOLIB_4BIT
@@ -117,6 +164,12 @@ config S3C_GPIO_TRACK
117 Internal configuration option to enable the s3c specific gpio 164 Internal configuration option to enable the s3c specific gpio
118 chip tracking if the platform requires it. 165 chip tracking if the platform requires it.
119 166
167# uart options
168
169config S5P_DEV_UART
170 def_bool y
171 depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210)
172
120# ADC driver 173# ADC driver
121 174
122config S3C_ADC 175config S3C_ADC
@@ -274,6 +327,76 @@ config SAMSUNG_DEV_BACKLIGHT
274 help 327 help
275 Compile in platform device definition LCD backlight with PWM Timer 328 Compile in platform device definition LCD backlight with PWM Timer
276 329
330config S5P_DEV_CSIS0
331 bool
332 help
333 Compile in platform device definitions for MIPI-CSIS channel 0
334
335config S5P_DEV_CSIS1
336 bool
337 help
338 Compile in platform device definitions for MIPI-CSIS channel 1
339
340config S5P_DEV_FIMC0
341 bool
342 help
343 Compile in platform device definitions for FIMC controller 0
344
345config S5P_DEV_FIMC1
346 bool
347 help
348 Compile in platform device definitions for FIMC controller 1
349
350config S5P_DEV_FIMC2
351 bool
352 help
353 Compile in platform device definitions for FIMC controller 2
354
355config S5P_DEV_FIMC3
356 bool
357 help
358 Compile in platform device definitions for FIMC controller 3
359
360config S5P_DEV_FIMD0
361 bool
362 help
363 Compile in platform device definitions for FIMD controller 0
364
365config S5P_DEV_G2D
366 bool
367 help
368 Compile in platform device definitions for G2D device
369
370config S5P_DEV_I2C_HDMIPHY
371 bool
372 help
373 Compile in platform device definitions for I2C HDMIPHY controller
374
375config S5P_DEV_JPEG
376 bool
377 help
378 Compile in platform device definitions for JPEG codec
379
380config S5P_DEV_MFC
381 bool
382 help
383 Compile in setup memory (init) code for MFC
384
385config S5P_DEV_ONENAND
386 bool
387 help
388 Compile in platform device definition for OneNAND controller
389
390config S5P_DEV_TV
391 bool
392 help
393 Compile in platform device definition for TV interface
394
395config S5P_DEV_USB_EHCI
396 bool
397 help
398 Compile in platform device definition for USB EHCI
399
277config S3C24XX_PWM 400config S3C24XX_PWM
278 bool "PWM device support" 401 bool "PWM device support"
279 select HAVE_PWM 402 select HAVE_PWM
@@ -281,6 +404,11 @@ config S3C24XX_PWM
281 Support for exporting the PWM timer blocks via the pwm device 404 Support for exporting the PWM timer blocks via the pwm device
282 system 405 system
283 406
407config S5P_SETUP_MIPIPHY
408 bool
409 help
410 Compile in common setup code for MIPI-CSIS and MIPI-DSIM devices
411
284# DMA 412# DMA
285 413
286config S3C_DMA 414config S3C_DMA
@@ -351,6 +479,18 @@ config SAMSUNG_WAKEMASK
351 and above. This code allows a set of interrupt to wakeup-mask 479 and above. This code allows a set of interrupt to wakeup-mask
352 mappings. See <plat/wakeup-mask.h> 480 mappings. See <plat/wakeup-mask.h>
353 481
482config S5P_PM
483 bool
484 help
485 Common code for power management support on S5P and newer SoCs
486 Note: Do not select this for S5P6440 and S5P6450.
487
488config S5P_SLEEP
489 bool
490 help
491 Internal config node to apply common S5P sleep management code.
492 Can be selected by S5P and newer SoCs with similar sleep procedure.
493
354comment "Power Domain" 494comment "Power Domain"
355 495
356config SAMSUNG_PD 496config SAMSUNG_PD
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 6012366f33cb..860b2db4db15 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -13,12 +13,18 @@ obj- :=
13 13
14obj-y += init.o cpu.o 14obj-y += init.o cpu.o
15obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET) += time.o 15obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET) += time.o
16obj-$(CONFIG_S5P_HRT) += s5p-time.o
17
16obj-y += clock.o 18obj-y += clock.o
17obj-y += pwm-clock.o 19obj-y += pwm-clock.o
18 20
19obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o 21obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o
22obj-$(CONFIG_S5P_CLOCK) += s5p-clock.o
20 23
21obj-$(CONFIG_SAMSUNG_IRQ_VIC_TIMER) += irq-vic-timer.o 24obj-$(CONFIG_SAMSUNG_IRQ_VIC_TIMER) += irq-vic-timer.o
25obj-$(CONFIG_S5P_IRQ) += s5p-irq.o
26obj-$(CONFIG_S5P_EXT_INT) += s5p-irq-eint.o
27obj-$(CONFIG_S5P_GPIO_INT) += s5p-irq-gpioint.o
22 28
23# ADC 29# ADC
24 30
@@ -30,9 +36,13 @@ obj-y += platformdata.o
30 36
31obj-y += devs.o 37obj-y += devs.o
32obj-y += dev-uart.o 38obj-y += dev-uart.o
39obj-$(CONFIG_S5P_DEV_MFC) += s5p-dev-mfc.o
40obj-$(CONFIG_S5P_DEV_UART) += s5p-dev-uart.o
33 41
34obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight.o 42obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight.o
35 43
44obj-$(CONFIG_S5P_SETUP_MIPIPHY) += setup-mipiphy.o
45
36# DMA support 46# DMA support
37 47
38obj-$(CONFIG_S3C_DMA) += dma.o s3c-dma-ops.o 48obj-$(CONFIG_S3C_DMA) += dma.o s3c-dma-ops.o
@@ -47,6 +57,9 @@ obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o
47 57
48obj-$(CONFIG_SAMSUNG_WAKEMASK) += wakeup-mask.o 58obj-$(CONFIG_SAMSUNG_WAKEMASK) += wakeup-mask.o
49 59
60obj-$(CONFIG_S5P_PM) += s5p-pm.o s5p-irq-pm.o
61obj-$(CONFIG_S5P_SLEEP) += s5p-sleep.o
62
50# PD support 63# PD support
51 64
52obj-$(CONFIG_SAMSUNG_PD) += pd.o 65obj-$(CONFIG_SAMSUNG_PD) += pd.o
diff --git a/arch/arm/plat-samsung/s5p-clock.c b/arch/arm/plat-samsung/s5p-clock.c
new file mode 100644
index 000000000000..41d3dfd5dddb
--- /dev/null
+++ b/arch/arm/plat-samsung/s5p-clock.c
@@ -0,0 +1,263 @@
1/*
2 * Copyright 2009 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com/
4 *
5 * S5P - Common clock support
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10*/
11
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/list.h>
16#include <linux/errno.h>
17#include <linux/err.h>
18#include <linux/clk.h>
19#include <linux/device.h>
20#include <linux/io.h>
21#include <asm/div64.h>
22
23#include <mach/regs-clock.h>
24
25#include <plat/clock.h>
26#include <plat/clock-clksrc.h>
27#include <plat/s5p-clock.h>
28
29/* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
30 * clk_ext_xtal_mux.
31*/
32struct clk clk_ext_xtal_mux = {
33 .name = "ext_xtal",
34 .id = -1,
35};
36
37struct clk clk_xusbxti = {
38 .name = "xusbxti",
39 .id = -1,
40};
41
42struct clk s5p_clk_27m = {
43 .name = "clk_27m",
44 .id = -1,
45 .rate = 27000000,
46};
47
48/* 48MHz USB Phy clock output */
49struct clk clk_48m = {
50 .name = "clk_48m",
51 .id = -1,
52 .rate = 48000000,
53};
54
55/* APLL clock output
56 * No need .ctrlbit, this is always on
57*/
58struct clk clk_fout_apll = {
59 .name = "fout_apll",
60 .id = -1,
61};
62
63/* BPLL clock output */
64
65struct clk clk_fout_bpll = {
66 .name = "fout_bpll",
67 .id = -1,
68};
69
70/* CPLL clock output */
71
72struct clk clk_fout_cpll = {
73 .name = "fout_cpll",
74 .id = -1,
75};
76
77/* MPLL clock output
78 * No need .ctrlbit, this is always on
79*/
80struct clk clk_fout_mpll = {
81 .name = "fout_mpll",
82 .id = -1,
83};
84
85/* EPLL clock output */
86struct clk clk_fout_epll = {
87 .name = "fout_epll",
88 .id = -1,
89 .ctrlbit = (1 << 31),
90};
91
92/* DPLL clock output */
93struct clk clk_fout_dpll = {
94 .name = "fout_dpll",
95 .id = -1,
96 .ctrlbit = (1 << 31),
97};
98
99/* VPLL clock output */
100struct clk clk_fout_vpll = {
101 .name = "fout_vpll",
102 .id = -1,
103 .ctrlbit = (1 << 31),
104};
105
106/* Possible clock sources for APLL Mux */
107static struct clk *clk_src_apll_list[] = {
108 [0] = &clk_fin_apll,
109 [1] = &clk_fout_apll,
110};
111
112struct clksrc_sources clk_src_apll = {
113 .sources = clk_src_apll_list,
114 .nr_sources = ARRAY_SIZE(clk_src_apll_list),
115};
116
117/* Possible clock sources for BPLL Mux */
118static struct clk *clk_src_bpll_list[] = {
119 [0] = &clk_fin_bpll,
120 [1] = &clk_fout_bpll,
121};
122
123struct clksrc_sources clk_src_bpll = {
124 .sources = clk_src_bpll_list,
125 .nr_sources = ARRAY_SIZE(clk_src_bpll_list),
126};
127
128/* Possible clock sources for CPLL Mux */
129static struct clk *clk_src_cpll_list[] = {
130 [0] = &clk_fin_cpll,
131 [1] = &clk_fout_cpll,
132};
133
134struct clksrc_sources clk_src_cpll = {
135 .sources = clk_src_cpll_list,
136 .nr_sources = ARRAY_SIZE(clk_src_cpll_list),
137};
138
139/* Possible clock sources for MPLL Mux */
140static struct clk *clk_src_mpll_list[] = {
141 [0] = &clk_fin_mpll,
142 [1] = &clk_fout_mpll,
143};
144
145struct clksrc_sources clk_src_mpll = {
146 .sources = clk_src_mpll_list,
147 .nr_sources = ARRAY_SIZE(clk_src_mpll_list),
148};
149
150/* Possible clock sources for EPLL Mux */
151static struct clk *clk_src_epll_list[] = {
152 [0] = &clk_fin_epll,
153 [1] = &clk_fout_epll,
154};
155
156struct clksrc_sources clk_src_epll = {
157 .sources = clk_src_epll_list,
158 .nr_sources = ARRAY_SIZE(clk_src_epll_list),
159};
160
161/* Possible clock sources for DPLL Mux */
162static struct clk *clk_src_dpll_list[] = {
163 [0] = &clk_fin_dpll,
164 [1] = &clk_fout_dpll,
165};
166
167struct clksrc_sources clk_src_dpll = {
168 .sources = clk_src_dpll_list,
169 .nr_sources = ARRAY_SIZE(clk_src_dpll_list),
170};
171
172struct clk clk_vpll = {
173 .name = "vpll",
174 .id = -1,
175};
176
177int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable)
178{
179 unsigned int ctrlbit = clk->ctrlbit;
180 u32 con;
181
182 con = __raw_readl(reg);
183 con = enable ? (con | ctrlbit) : (con & ~ctrlbit);
184 __raw_writel(con, reg);
185 return 0;
186}
187
188int s5p_epll_enable(struct clk *clk, int enable)
189{
190 unsigned int ctrlbit = clk->ctrlbit;
191 unsigned int epll_con = __raw_readl(S5P_EPLL_CON) & ~ctrlbit;
192
193 if (enable)
194 __raw_writel(epll_con | ctrlbit, S5P_EPLL_CON);
195 else
196 __raw_writel(epll_con, S5P_EPLL_CON);
197
198 return 0;
199}
200
201unsigned long s5p_epll_get_rate(struct clk *clk)
202{
203 return clk->rate;
204}
205
206int s5p_spdif_set_rate(struct clk *clk, unsigned long rate)
207{
208 struct clk *pclk;
209 int ret;
210
211 pclk = clk_get_parent(clk);
212 if (IS_ERR(pclk))
213 return -EINVAL;
214
215 ret = pclk->ops->set_rate(pclk, rate);
216 clk_put(pclk);
217
218 return ret;
219}
220
221unsigned long s5p_spdif_get_rate(struct clk *clk)
222{
223 struct clk *pclk;
224 int rate;
225
226 pclk = clk_get_parent(clk);
227 if (IS_ERR(pclk))
228 return -EINVAL;
229
230 rate = pclk->ops->get_rate(pclk);
231 clk_put(pclk);
232
233 return rate;
234}
235
236struct clk_ops s5p_sclk_spdif_ops = {
237 .set_rate = s5p_spdif_set_rate,
238 .get_rate = s5p_spdif_get_rate,
239};
240
241static struct clk *s5p_clks[] __initdata = {
242 &clk_ext_xtal_mux,
243 &clk_48m,
244 &s5p_clk_27m,
245 &clk_fout_apll,
246 &clk_fout_mpll,
247 &clk_fout_epll,
248 &clk_fout_dpll,
249 &clk_fout_vpll,
250 &clk_vpll,
251 &clk_xusbxti,
252};
253
254void __init s5p_register_clocks(unsigned long xtal_freq)
255{
256 int ret;
257
258 clk_ext_xtal_mux.rate = xtal_freq;
259
260 ret = s3c24xx_register_clocks(s5p_clks, ARRAY_SIZE(s5p_clks));
261 if (ret > 0)
262 printk(KERN_ERR "Failed to register s5p clocks\n");
263}
diff --git a/arch/arm/plat-samsung/s5p-dev-mfc.c b/arch/arm/plat-samsung/s5p-dev-mfc.c
new file mode 100644
index 000000000000..ad6089465e2a
--- /dev/null
+++ b/arch/arm/plat-samsung/s5p-dev-mfc.c
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
3 *
4 * Base S5P MFC resource and device definitions
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 version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/kernel.h>
12#include <linux/interrupt.h>
13#include <linux/platform_device.h>
14#include <linux/dma-mapping.h>
15#include <linux/memblock.h>
16#include <linux/ioport.h>
17
18#include <mach/map.h>
19#include <plat/devs.h>
20#include <plat/irqs.h>
21#include <plat/mfc.h>
22
23struct s5p_mfc_reserved_mem {
24 phys_addr_t base;
25 unsigned long size;
26 struct device *dev;
27};
28
29static struct s5p_mfc_reserved_mem s5p_mfc_mem[2] __initdata;
30
31void __init s5p_mfc_reserve_mem(phys_addr_t rbase, unsigned int rsize,
32 phys_addr_t lbase, unsigned int lsize)
33{
34 int i;
35
36 s5p_mfc_mem[0].dev = &s5p_device_mfc_r.dev;
37 s5p_mfc_mem[0].base = rbase;
38 s5p_mfc_mem[0].size = rsize;
39
40 s5p_mfc_mem[1].dev = &s5p_device_mfc_l.dev;
41 s5p_mfc_mem[1].base = lbase;
42 s5p_mfc_mem[1].size = lsize;
43
44 for (i = 0; i < ARRAY_SIZE(s5p_mfc_mem); i++) {
45 struct s5p_mfc_reserved_mem *area = &s5p_mfc_mem[i];
46 if (memblock_remove(area->base, area->size)) {
47 printk(KERN_ERR "Failed to reserve memory for MFC device (%ld bytes at 0x%08lx)\n",
48 area->size, (unsigned long) area->base);
49 area->base = 0;
50 }
51 }
52}
53
54static int __init s5p_mfc_memory_init(void)
55{
56 int i;
57
58 for (i = 0; i < ARRAY_SIZE(s5p_mfc_mem); i++) {
59 struct s5p_mfc_reserved_mem *area = &s5p_mfc_mem[i];
60 if (!area->base)
61 continue;
62
63 if (dma_declare_coherent_memory(area->dev, area->base,
64 area->base, area->size,
65 DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0)
66 printk(KERN_ERR "Failed to declare coherent memory for MFC device (%ld bytes at 0x%08lx)\n",
67 area->size, (unsigned long) area->base);
68 }
69 return 0;
70}
71device_initcall(s5p_mfc_memory_init);
diff --git a/arch/arm/plat-samsung/s5p-dev-uart.c b/arch/arm/plat-samsung/s5p-dev-uart.c
new file mode 100644
index 000000000000..cafa3deddcc1
--- /dev/null
+++ b/arch/arm/plat-samsung/s5p-dev-uart.c
@@ -0,0 +1,89 @@
1/*
2 * Copyright (c) 2009,2012 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com/
4 *
5 * Base S5P UART resource and device definitions
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10*/
11
12#include <linux/kernel.h>
13#include <linux/types.h>
14#include <linux/interrupt.h>
15#include <linux/list.h>
16#include <linux/ioport.h>
17#include <linux/platform_device.h>
18
19#include <asm/mach/arch.h>
20#include <asm/mach/irq.h>
21#include <mach/hardware.h>
22#include <mach/map.h>
23
24#include <plat/devs.h>
25
26 /* Serial port registrations */
27
28static struct resource s5p_uart0_resource[] = {
29 [0] = DEFINE_RES_MEM(S5P_PA_UART0, S5P_SZ_UART),
30 [1] = DEFINE_RES_IRQ(IRQ_UART0),
31};
32
33static struct resource s5p_uart1_resource[] = {
34 [0] = DEFINE_RES_MEM(S5P_PA_UART1, S5P_SZ_UART),
35 [1] = DEFINE_RES_IRQ(IRQ_UART1),
36};
37
38static struct resource s5p_uart2_resource[] = {
39 [0] = DEFINE_RES_MEM(S5P_PA_UART2, S5P_SZ_UART),
40 [1] = DEFINE_RES_IRQ(IRQ_UART2),
41};
42
43static struct resource s5p_uart3_resource[] = {
44#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
45 [0] = DEFINE_RES_MEM(S5P_PA_UART3, S5P_SZ_UART),
46 [1] = DEFINE_RES_IRQ(IRQ_UART3),
47#endif
48};
49
50static struct resource s5p_uart4_resource[] = {
51#if CONFIG_SERIAL_SAMSUNG_UARTS > 4
52 [0] = DEFINE_RES_MEM(S5P_PA_UART4, S5P_SZ_UART),
53 [1] = DEFINE_RES_IRQ(IRQ_UART4),
54#endif
55};
56
57static struct resource s5p_uart5_resource[] = {
58#if CONFIG_SERIAL_SAMSUNG_UARTS > 5
59 [0] = DEFINE_RES_MEM(S5P_PA_UART5, S5P_SZ_UART),
60 [1] = DEFINE_RES_IRQ(IRQ_UART5),
61#endif
62};
63
64struct s3c24xx_uart_resources s5p_uart_resources[] __initdata = {
65 [0] = {
66 .resources = s5p_uart0_resource,
67 .nr_resources = ARRAY_SIZE(s5p_uart0_resource),
68 },
69 [1] = {
70 .resources = s5p_uart1_resource,
71 .nr_resources = ARRAY_SIZE(s5p_uart1_resource),
72 },
73 [2] = {
74 .resources = s5p_uart2_resource,
75 .nr_resources = ARRAY_SIZE(s5p_uart2_resource),
76 },
77 [3] = {
78 .resources = s5p_uart3_resource,
79 .nr_resources = ARRAY_SIZE(s5p_uart3_resource),
80 },
81 [4] = {
82 .resources = s5p_uart4_resource,
83 .nr_resources = ARRAY_SIZE(s5p_uart4_resource),
84 },
85 [5] = {
86 .resources = s5p_uart5_resource,
87 .nr_resources = ARRAY_SIZE(s5p_uart5_resource),
88 },
89};
diff --git a/arch/arm/plat-samsung/s5p-irq-eint.c b/arch/arm/plat-samsung/s5p-irq-eint.c
new file mode 100644
index 000000000000..33bd3f3d20f5
--- /dev/null
+++ b/arch/arm/plat-samsung/s5p-irq-eint.c
@@ -0,0 +1,218 @@
1/*
2 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
4 *
5 * S5P - IRQ EINT support
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10*/
11
12#include <linux/kernel.h>
13#include <linux/interrupt.h>
14#include <linux/irq.h>
15#include <linux/io.h>
16#include <linux/device.h>
17#include <linux/gpio.h>
18
19#include <asm/hardware/vic.h>
20
21#include <plat/regs-irqtype.h>
22
23#include <mach/map.h>
24#include <plat/cpu.h>
25#include <plat/pm.h>
26
27#include <plat/gpio-cfg.h>
28#include <mach/regs-gpio.h>
29
30static inline void s5p_irq_eint_mask(struct irq_data *data)
31{
32 u32 mask;
33
34 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
35 mask |= eint_irq_to_bit(data->irq);
36 __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
37}
38
39static void s5p_irq_eint_unmask(struct irq_data *data)
40{
41 u32 mask;
42
43 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
44 mask &= ~(eint_irq_to_bit(data->irq));
45 __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
46}
47
48static inline void s5p_irq_eint_ack(struct irq_data *data)
49{
50 __raw_writel(eint_irq_to_bit(data->irq),
51 S5P_EINT_PEND(EINT_REG_NR(data->irq)));
52}
53
54static void s5p_irq_eint_maskack(struct irq_data *data)
55{
56 /* compiler should in-line these */
57 s5p_irq_eint_mask(data);
58 s5p_irq_eint_ack(data);
59}
60
61static int s5p_irq_eint_set_type(struct irq_data *data, unsigned int type)
62{
63 int offs = EINT_OFFSET(data->irq);
64 int shift;
65 u32 ctrl, mask;
66 u32 newvalue = 0;
67
68 switch (type) {
69 case IRQ_TYPE_EDGE_RISING:
70 newvalue = S5P_IRQ_TYPE_EDGE_RISING;
71 break;
72
73 case IRQ_TYPE_EDGE_FALLING:
74 newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
75 break;
76
77 case IRQ_TYPE_EDGE_BOTH:
78 newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
79 break;
80
81 case IRQ_TYPE_LEVEL_LOW:
82 newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
83 break;
84
85 case IRQ_TYPE_LEVEL_HIGH:
86 newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
87 break;
88
89 default:
90 printk(KERN_ERR "No such irq type %d", type);
91 return -EINVAL;
92 }
93
94 shift = (offs & 0x7) * 4;
95 mask = 0x7 << shift;
96
97 ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq)));
98 ctrl &= ~mask;
99 ctrl |= newvalue << shift;
100 __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq)));
101
102 if ((0 <= offs) && (offs < 8))
103 s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE);
104
105 else if ((8 <= offs) && (offs < 16))
106 s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE);
107
108 else if ((16 <= offs) && (offs < 24))
109 s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE);
110
111 else if ((24 <= offs) && (offs < 32))
112 s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE);
113
114 else
115 printk(KERN_ERR "No such irq number %d", offs);
116
117 return 0;
118}
119
120static struct irq_chip s5p_irq_eint = {
121 .name = "s5p-eint",
122 .irq_mask = s5p_irq_eint_mask,
123 .irq_unmask = s5p_irq_eint_unmask,
124 .irq_mask_ack = s5p_irq_eint_maskack,
125 .irq_ack = s5p_irq_eint_ack,
126 .irq_set_type = s5p_irq_eint_set_type,
127#ifdef CONFIG_PM
128 .irq_set_wake = s3c_irqext_wake,
129#endif
130};
131
132/* s5p_irq_demux_eint
133 *
134 * This function demuxes the IRQ from the group0 external interrupts,
135 * from EINTs 16 to 31. It is designed to be inlined into the specific
136 * handler s5p_irq_demux_eintX_Y.
137 *
138 * Each EINT pend/mask registers handle eight of them.
139 */
140static inline void s5p_irq_demux_eint(unsigned int start)
141{
142 u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start)));
143 u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start)));
144 unsigned int irq;
145
146 status &= ~mask;
147 status &= 0xff;
148
149 while (status) {
150 irq = fls(status) - 1;
151 generic_handle_irq(irq + start);
152 status &= ~(1 << irq);
153 }
154}
155
156static void s5p_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
157{
158 s5p_irq_demux_eint(IRQ_EINT(16));
159 s5p_irq_demux_eint(IRQ_EINT(24));
160}
161
162static inline void s5p_irq_vic_eint_mask(struct irq_data *data)
163{
164 void __iomem *base = irq_data_get_irq_chip_data(data);
165
166 s5p_irq_eint_mask(data);
167 writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE_CLEAR);
168}
169
170static void s5p_irq_vic_eint_unmask(struct irq_data *data)
171{
172 void __iomem *base = irq_data_get_irq_chip_data(data);
173
174 s5p_irq_eint_unmask(data);
175 writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE);
176}
177
178static inline void s5p_irq_vic_eint_ack(struct irq_data *data)
179{
180 __raw_writel(eint_irq_to_bit(data->irq),
181 S5P_EINT_PEND(EINT_REG_NR(data->irq)));
182}
183
184static void s5p_irq_vic_eint_maskack(struct irq_data *data)
185{
186 s5p_irq_vic_eint_mask(data);
187 s5p_irq_vic_eint_ack(data);
188}
189
190static struct irq_chip s5p_irq_vic_eint = {
191 .name = "s5p_vic_eint",
192 .irq_mask = s5p_irq_vic_eint_mask,
193 .irq_unmask = s5p_irq_vic_eint_unmask,
194 .irq_mask_ack = s5p_irq_vic_eint_maskack,
195 .irq_ack = s5p_irq_vic_eint_ack,
196 .irq_set_type = s5p_irq_eint_set_type,
197#ifdef CONFIG_PM
198 .irq_set_wake = s3c_irqext_wake,
199#endif
200};
201
202static int __init s5p_init_irq_eint(void)
203{
204 int irq;
205
206 for (irq = IRQ_EINT(0); irq <= IRQ_EINT(15); irq++)
207 irq_set_chip(irq, &s5p_irq_vic_eint);
208
209 for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) {
210 irq_set_chip_and_handler(irq, &s5p_irq_eint, handle_level_irq);
211 set_irq_flags(irq, IRQF_VALID);
212 }
213
214 irq_set_chained_handler(IRQ_EINT16_31, s5p_irq_demux_eint16_31);
215 return 0;
216}
217
218arch_initcall(s5p_init_irq_eint);
diff --git a/arch/arm/plat-samsung/s5p-irq-gpioint.c b/arch/arm/plat-samsung/s5p-irq-gpioint.c
new file mode 100644
index 000000000000..f9431fe5b06e
--- /dev/null
+++ b/arch/arm/plat-samsung/s5p-irq-gpioint.c
@@ -0,0 +1,215 @@
1/*
2 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
3 * Author: Kyungmin Park <kyungmin.park@samsung.com>
4 * Author: Joonyoung Shim <jy0922.shim@samsung.com>
5 * Author: Marek Szyprowski <m.szyprowski@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#include <linux/kernel.h>
15#include <linux/interrupt.h>
16#include <linux/irq.h>
17#include <linux/io.h>
18#include <linux/gpio.h>
19#include <linux/slab.h>
20
21#include <mach/map.h>
22#include <plat/gpio-core.h>
23#include <plat/gpio-cfg.h>
24
25#include <asm/mach/irq.h>
26
27#define GPIO_BASE(chip) (((unsigned long)(chip)->base) & 0xFFFFF000u)
28
29#define CON_OFFSET 0x700
30#define MASK_OFFSET 0x900
31#define PEND_OFFSET 0xA00
32#define REG_OFFSET(x) ((x) << 2)
33
34struct s5p_gpioint_bank {
35 struct list_head list;
36 int start;
37 int nr_groups;
38 int irq;
39 struct samsung_gpio_chip **chips;
40 void (*handler)(unsigned int, struct irq_desc *);
41};
42
43static LIST_HEAD(banks);
44
45static int s5p_gpioint_set_type(struct irq_data *d, unsigned int type)
46{
47 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
48 struct irq_chip_type *ct = gc->chip_types;
49 unsigned int shift = (d->irq - gc->irq_base) << 2;
50
51 switch (type) {
52 case IRQ_TYPE_EDGE_RISING:
53 type = S5P_IRQ_TYPE_EDGE_RISING;
54 break;
55 case IRQ_TYPE_EDGE_FALLING:
56 type = S5P_IRQ_TYPE_EDGE_FALLING;
57 break;
58 case IRQ_TYPE_EDGE_BOTH:
59 type = S5P_IRQ_TYPE_EDGE_BOTH;
60 break;
61 case IRQ_TYPE_LEVEL_HIGH:
62 type = S5P_IRQ_TYPE_LEVEL_HIGH;
63 break;
64 case IRQ_TYPE_LEVEL_LOW:
65 type = S5P_IRQ_TYPE_LEVEL_LOW;
66 break;
67 case IRQ_TYPE_NONE:
68 default:
69 printk(KERN_WARNING "No irq type\n");
70 return -EINVAL;
71 }
72
73 gc->type_cache &= ~(0x7 << shift);
74 gc->type_cache |= type << shift;
75 writel(gc->type_cache, gc->reg_base + ct->regs.type);
76 return 0;
77}
78
79static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
80{
81 struct s5p_gpioint_bank *bank = irq_get_handler_data(irq);
82 int group, pend_offset, mask_offset;
83 unsigned int pend, mask;
84
85 struct irq_chip *chip = irq_get_chip(irq);
86 chained_irq_enter(chip, desc);
87
88 for (group = 0; group < bank->nr_groups; group++) {
89 struct samsung_gpio_chip *chip = bank->chips[group];
90 if (!chip)
91 continue;
92
93 pend_offset = REG_OFFSET(group);
94 pend = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
95 if (!pend)
96 continue;
97
98 mask_offset = REG_OFFSET(group);
99 mask = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
100 pend &= ~mask;
101
102 while (pend) {
103 int offset = fls(pend) - 1;
104 int real_irq = chip->irq_base + offset;
105 generic_handle_irq(real_irq);
106 pend &= ~BIT(offset);
107 }
108 }
109 chained_irq_exit(chip, desc);
110}
111
112static __init int s5p_gpioint_add(struct samsung_gpio_chip *chip)
113{
114 static int used_gpioint_groups = 0;
115 int group = chip->group;
116 struct s5p_gpioint_bank *b, *bank = NULL;
117 struct irq_chip_generic *gc;
118 struct irq_chip_type *ct;
119
120 if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT)
121 return -ENOMEM;
122
123 list_for_each_entry(b, &banks, list) {
124 if (group >= b->start && group < b->start + b->nr_groups) {
125 bank = b;
126 break;
127 }
128 }
129 if (!bank)
130 return -EINVAL;
131
132 if (!bank->handler) {
133 bank->chips = kzalloc(sizeof(struct samsung_gpio_chip *) *
134 bank->nr_groups, GFP_KERNEL);
135 if (!bank->chips)
136 return -ENOMEM;
137
138 irq_set_chained_handler(bank->irq, s5p_gpioint_handler);
139 irq_set_handler_data(bank->irq, bank);
140 bank->handler = s5p_gpioint_handler;
141 printk(KERN_INFO "Registered chained gpio int handler for interrupt %d.\n",
142 bank->irq);
143 }
144
145 /*
146 * chained GPIO irq has been successfully registered, allocate new gpio
147 * int group and assign irq nubmers
148 */
149 chip->irq_base = S5P_GPIOINT_BASE +
150 used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE;
151 used_gpioint_groups++;
152
153 bank->chips[group - bank->start] = chip;
154
155 gc = irq_alloc_generic_chip("s5p_gpioint", 1, chip->irq_base,
156 (void __iomem *)GPIO_BASE(chip),
157 handle_level_irq);
158 if (!gc)
159 return -ENOMEM;
160 ct = gc->chip_types;
161 ct->chip.irq_ack = irq_gc_ack_set_bit;
162 ct->chip.irq_mask = irq_gc_mask_set_bit;
163 ct->chip.irq_unmask = irq_gc_mask_clr_bit;
164 ct->chip.irq_set_type = s5p_gpioint_set_type,
165 ct->regs.ack = PEND_OFFSET + REG_OFFSET(group - bank->start);
166 ct->regs.mask = MASK_OFFSET + REG_OFFSET(group - bank->start);
167 ct->regs.type = CON_OFFSET + REG_OFFSET(group - bank->start);
168 irq_setup_generic_chip(gc, IRQ_MSK(chip->chip.ngpio),
169 IRQ_GC_INIT_MASK_CACHE,
170 IRQ_NOREQUEST | IRQ_NOPROBE, 0);
171 return 0;
172}
173
174int __init s5p_register_gpio_interrupt(int pin)
175{
176 struct samsung_gpio_chip *my_chip = samsung_gpiolib_getchip(pin);
177 int offset, group;
178 int ret;
179
180 if (!my_chip)
181 return -EINVAL;
182
183 offset = pin - my_chip->chip.base;
184 group = my_chip->group;
185
186 /* check if the group has been already registered */
187 if (my_chip->irq_base)
188 return my_chip->irq_base + offset;
189
190 /* register gpio group */
191 ret = s5p_gpioint_add(my_chip);
192 if (ret == 0) {
193 my_chip->chip.to_irq = samsung_gpiolib_to_irq;
194 printk(KERN_INFO "Registered interrupt support for gpio group %d.\n",
195 group);
196 return my_chip->irq_base + offset;
197 }
198 return ret;
199}
200
201int __init s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups)
202{
203 struct s5p_gpioint_bank *bank;
204
205 bank = kzalloc(sizeof(*bank), GFP_KERNEL);
206 if (!bank)
207 return -ENOMEM;
208
209 bank->start = start;
210 bank->nr_groups = nr_groups;
211 bank->irq = chain_irq;
212
213 list_add_tail(&bank->list, &banks);
214 return 0;
215}
diff --git a/arch/arm/plat-samsung/s5p-irq-pm.c b/arch/arm/plat-samsung/s5p-irq-pm.c
new file mode 100644
index 000000000000..7c1e3b7072fc
--- /dev/null
+++ b/arch/arm/plat-samsung/s5p-irq-pm.c
@@ -0,0 +1,102 @@
1/*
2 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
4 *
5 * Based on arch/arm/plat-s3c24xx/irq-pm.c,
6 * Copyright (c) 2003,2004 Simtec Electronics
7 * Ben Dooks <ben@simtec.co.uk>
8 * http://armlinux.simtec.co.uk/
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
19#include <plat/cpu.h>
20#include <plat/irqs.h>
21#include <plat/pm.h>
22#include <mach/map.h>
23
24#include <mach/regs-gpio.h>
25#include <mach/regs-irq.h>
26
27/* state for IRQs over sleep */
28
29/* default is to allow for EINT0..EINT31, and IRQ_RTC_TIC, IRQ_RTC_ALARM,
30 * as wakeup sources
31 *
32 * set bit to 1 in allow bitfield to enable the wakeup settings on it
33*/
34
35unsigned long s3c_irqwake_intallow = 0x00000006L;
36unsigned long s3c_irqwake_eintallow = 0xffffffffL;
37
38int s3c_irq_wake(struct irq_data *data, unsigned int state)
39{
40 unsigned long irqbit;
41 unsigned int irq_rtc_tic, irq_rtc_alarm;
42
43#ifdef CONFIG_ARCH_EXYNOS
44 if (soc_is_exynos5250()) {
45 irq_rtc_tic = EXYNOS5_IRQ_RTC_TIC;
46 irq_rtc_alarm = EXYNOS5_IRQ_RTC_ALARM;
47 } else {
48 irq_rtc_tic = EXYNOS4_IRQ_RTC_TIC;
49 irq_rtc_alarm = EXYNOS4_IRQ_RTC_ALARM;
50 }
51#else
52 irq_rtc_tic = IRQ_RTC_TIC;
53 irq_rtc_alarm = IRQ_RTC_ALARM;
54#endif
55
56 if (data->irq == irq_rtc_tic || data->irq == irq_rtc_alarm) {
57 irqbit = 1 << (data->irq + 1 - irq_rtc_alarm);
58
59 if (!state)
60 s3c_irqwake_intmask |= irqbit;
61 else
62 s3c_irqwake_intmask &= ~irqbit;
63 } else {
64 return -ENOENT;
65 }
66
67 return 0;
68}
69
70static struct sleep_save eint_save[] = {
71 SAVE_ITEM(S5P_EINT_CON(0)),
72 SAVE_ITEM(S5P_EINT_CON(1)),
73 SAVE_ITEM(S5P_EINT_CON(2)),
74 SAVE_ITEM(S5P_EINT_CON(3)),
75
76 SAVE_ITEM(S5P_EINT_FLTCON(0)),
77 SAVE_ITEM(S5P_EINT_FLTCON(1)),
78 SAVE_ITEM(S5P_EINT_FLTCON(2)),
79 SAVE_ITEM(S5P_EINT_FLTCON(3)),
80 SAVE_ITEM(S5P_EINT_FLTCON(4)),
81 SAVE_ITEM(S5P_EINT_FLTCON(5)),
82 SAVE_ITEM(S5P_EINT_FLTCON(6)),
83 SAVE_ITEM(S5P_EINT_FLTCON(7)),
84
85 SAVE_ITEM(S5P_EINT_MASK(0)),
86 SAVE_ITEM(S5P_EINT_MASK(1)),
87 SAVE_ITEM(S5P_EINT_MASK(2)),
88 SAVE_ITEM(S5P_EINT_MASK(3)),
89};
90
91int s3c24xx_irq_suspend(void)
92{
93 s3c_pm_do_save(eint_save, ARRAY_SIZE(eint_save));
94
95 return 0;
96}
97
98void s3c24xx_irq_resume(void)
99{
100 s3c_pm_do_restore(eint_save, ARRAY_SIZE(eint_save));
101}
102
diff --git a/arch/arm/plat-samsung/s5p-irq.c b/arch/arm/plat-samsung/s5p-irq.c
new file mode 100644
index 000000000000..dfb47d638f03
--- /dev/null
+++ b/arch/arm/plat-samsung/s5p-irq.c
@@ -0,0 +1,35 @@
1/*
2 * Copyright (c) 2009 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com/
4 *
5 * S5P - Interrupt handling
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10*/
11
12#include <linux/kernel.h>
13#include <linux/interrupt.h>
14#include <linux/irq.h>
15#include <linux/io.h>
16
17#include <asm/hardware/vic.h>
18
19#include <mach/map.h>
20#include <plat/regs-timer.h>
21#include <plat/cpu.h>
22#include <plat/irq-vic-timer.h>
23
24void __init s5p_init_irq(u32 *vic, u32 num_vic)
25{
26#ifdef CONFIG_ARM_VIC
27 int irq;
28
29 /* initialize the VICs */
30 for (irq = 0; irq < num_vic; irq++)
31 vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0);
32#endif
33
34 s3c_init_vic_timer_irq(5, IRQ_TIMER0);
35}
diff --git a/arch/arm/plat-samsung/s5p-pm.c b/arch/arm/plat-samsung/s5p-pm.c
new file mode 100644
index 000000000000..0747468f0936
--- /dev/null
+++ b/arch/arm/plat-samsung/s5p-pm.c
@@ -0,0 +1,40 @@
1/*
2 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
4 *
5 * S5P Power Manager (Suspend-To-RAM) support
6 *
7 * Based on arch/arm/plat-s3c24xx/pm.c
8 * Copyright (c) 2004,2006 Simtec Electronics
9 * Ben Dooks <ben@simtec.co.uk>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14*/
15
16#include <linux/suspend.h>
17#include <plat/pm.h>
18
19#define PFX "s5p pm: "
20
21/* s3c_pm_configure_extint
22 *
23 * configure all external interrupt pins
24*/
25
26void s3c_pm_configure_extint(void)
27{
28 /* nothing here yet */
29}
30
31void s3c_pm_restore_core(void)
32{
33 /* nothing here yet */
34}
35
36void s3c_pm_save_core(void)
37{
38 /* nothing here yet */
39}
40
diff --git a/arch/arm/plat-samsung/s5p-sleep.S b/arch/arm/plat-samsung/s5p-sleep.S
new file mode 100644
index 000000000000..bdf6dadf8790
--- /dev/null
+++ b/arch/arm/plat-samsung/s5p-sleep.S
@@ -0,0 +1,80 @@
1/*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
4 *
5 * Common S5P Sleep Code
6 * Based on S3C64XX sleep code by:
7 * Ben Dooks, (c) 2008 Simtec Electronics
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/linkage.h>
25#include <asm/asm-offsets.h>
26#include <asm/hardware/cache-l2x0.h>
27
28/*
29 * The following code is located into the .data section. This is to
30 * allow l2x0_regs_phys to be accessed with a relative load while we
31 * can't rely on any MMU translation. We could have put l2x0_regs_phys
32 * in the .text section as well, but some setups might insist on it to
33 * be truly read-only. (Reference from: arch/arm/kernel/sleep.S)
34 */
35 .data
36 .align
37
38 /*
39 * sleep magic, to allow the bootloader to check for an valid
40 * image to resume to. Must be the first word before the
41 * s3c_cpu_resume entry.
42 */
43
44 .word 0x2bedf00d
45
46 /*
47 * s3c_cpu_resume
48 *
49 * resume code entry for bootloader to call
50 */
51
52ENTRY(s3c_cpu_resume)
53#ifdef CONFIG_CACHE_L2X0
54 adr r0, l2x0_regs_phys
55 ldr r0, [r0]
56 ldr r1, [r0, #L2X0_R_PHY_BASE]
57 ldr r2, [r1, #L2X0_CTRL]
58 tst r2, #0x1
59 bne resume_l2on
60 ldr r2, [r0, #L2X0_R_AUX_CTRL]
61 str r2, [r1, #L2X0_AUX_CTRL]
62 ldr r2, [r0, #L2X0_R_TAG_LATENCY]
63 str r2, [r1, #L2X0_TAG_LATENCY_CTRL]
64 ldr r2, [r0, #L2X0_R_DATA_LATENCY]
65 str r2, [r1, #L2X0_DATA_LATENCY_CTRL]
66 ldr r2, [r0, #L2X0_R_PREFETCH_CTRL]
67 str r2, [r1, #L2X0_PREFETCH_CTRL]
68 ldr r2, [r0, #L2X0_R_PWR_CTRL]
69 str r2, [r1, #L2X0_POWER_CTRL]
70 mov r2, #1
71 str r2, [r1, #L2X0_CTRL]
72resume_l2on:
73#endif
74 b cpu_resume
75ENDPROC(s3c_cpu_resume)
76#ifdef CONFIG_CACHE_L2X0
77 .globl l2x0_regs_phys
78l2x0_regs_phys:
79 .long 0
80#endif
diff --git a/arch/arm/plat-samsung/s5p-time.c b/arch/arm/plat-samsung/s5p-time.c
new file mode 100644
index 000000000000..028b6e877eb9
--- /dev/null
+++ b/arch/arm/plat-samsung/s5p-time.c
@@ -0,0 +1,405 @@
1/*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com/
4 *
5 * S5P - Common hr-timer support
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10*/
11
12#include <linux/interrupt.h>
13#include <linux/irq.h>
14#include <linux/err.h>
15#include <linux/clk.h>
16#include <linux/clockchips.h>
17#include <linux/platform_device.h>
18
19#include <asm/smp_twd.h>
20#include <asm/mach/time.h>
21#include <asm/mach/arch.h>
22#include <asm/mach/map.h>
23#include <asm/sched_clock.h>
24
25#include <mach/map.h>
26#include <plat/devs.h>
27#include <plat/regs-timer.h>
28#include <plat/s5p-time.h>
29
30static struct clk *tin_event;
31static struct clk *tin_source;
32static struct clk *tdiv_event;
33static struct clk *tdiv_source;
34static struct clk *timerclk;
35static struct s5p_timer_source timer_source;
36static unsigned long clock_count_per_tick;
37static void s5p_timer_resume(void);
38
39static void s5p_time_stop(enum s5p_timer_mode mode)
40{
41 unsigned long tcon;
42
43 tcon = __raw_readl(S3C2410_TCON);
44
45 switch (mode) {
46 case S5P_PWM0:
47 tcon &= ~S3C2410_TCON_T0START;
48 break;
49
50 case S5P_PWM1:
51 tcon &= ~S3C2410_TCON_T1START;
52 break;
53
54 case S5P_PWM2:
55 tcon &= ~S3C2410_TCON_T2START;
56 break;
57
58 case S5P_PWM3:
59 tcon &= ~S3C2410_TCON_T3START;
60 break;
61
62 case S5P_PWM4:
63 tcon &= ~S3C2410_TCON_T4START;
64 break;
65
66 default:
67 printk(KERN_ERR "Invalid Timer %d\n", mode);
68 break;
69 }
70 __raw_writel(tcon, S3C2410_TCON);
71}
72
73static void s5p_time_setup(enum s5p_timer_mode mode, unsigned long tcnt)
74{
75 unsigned long tcon;
76
77 tcon = __raw_readl(S3C2410_TCON);
78
79 tcnt--;
80
81 switch (mode) {
82 case S5P_PWM0:
83 tcon &= ~(0x0f << 0);
84 tcon |= S3C2410_TCON_T0MANUALUPD;
85 break;
86
87 case S5P_PWM1:
88 tcon &= ~(0x0f << 8);
89 tcon |= S3C2410_TCON_T1MANUALUPD;
90 break;
91
92 case S5P_PWM2:
93 tcon &= ~(0x0f << 12);
94 tcon |= S3C2410_TCON_T2MANUALUPD;
95 break;
96
97 case S5P_PWM3:
98 tcon &= ~(0x0f << 16);
99 tcon |= S3C2410_TCON_T3MANUALUPD;
100 break;
101
102 case S5P_PWM4:
103 tcon &= ~(0x07 << 20);
104 tcon |= S3C2410_TCON_T4MANUALUPD;
105 break;
106
107 default:
108 printk(KERN_ERR "Invalid Timer %d\n", mode);
109 break;
110 }
111
112 __raw_writel(tcnt, S3C2410_TCNTB(mode));
113 __raw_writel(tcnt, S3C2410_TCMPB(mode));
114 __raw_writel(tcon, S3C2410_TCON);
115}
116
117static void s5p_time_start(enum s5p_timer_mode mode, bool periodic)
118{
119 unsigned long tcon;
120
121 tcon = __raw_readl(S3C2410_TCON);
122
123 switch (mode) {
124 case S5P_PWM0:
125 tcon |= S3C2410_TCON_T0START;
126 tcon &= ~S3C2410_TCON_T0MANUALUPD;
127
128 if (periodic)
129 tcon |= S3C2410_TCON_T0RELOAD;
130 else
131 tcon &= ~S3C2410_TCON_T0RELOAD;
132 break;
133
134 case S5P_PWM1:
135 tcon |= S3C2410_TCON_T1START;
136 tcon &= ~S3C2410_TCON_T1MANUALUPD;
137
138 if (periodic)
139 tcon |= S3C2410_TCON_T1RELOAD;
140 else
141 tcon &= ~S3C2410_TCON_T1RELOAD;
142 break;
143
144 case S5P_PWM2:
145 tcon |= S3C2410_TCON_T2START;
146 tcon &= ~S3C2410_TCON_T2MANUALUPD;
147
148 if (periodic)
149 tcon |= S3C2410_TCON_T2RELOAD;
150 else
151 tcon &= ~S3C2410_TCON_T2RELOAD;
152 break;
153
154 case S5P_PWM3:
155 tcon |= S3C2410_TCON_T3START;
156 tcon &= ~S3C2410_TCON_T3MANUALUPD;
157
158 if (periodic)
159 tcon |= S3C2410_TCON_T3RELOAD;
160 else
161 tcon &= ~S3C2410_TCON_T3RELOAD;
162 break;
163
164 case S5P_PWM4:
165 tcon |= S3C2410_TCON_T4START;
166 tcon &= ~S3C2410_TCON_T4MANUALUPD;
167
168 if (periodic)
169 tcon |= S3C2410_TCON_T4RELOAD;
170 else
171 tcon &= ~S3C2410_TCON_T4RELOAD;
172 break;
173
174 default:
175 printk(KERN_ERR "Invalid Timer %d\n", mode);
176 break;
177 }
178 __raw_writel(tcon, S3C2410_TCON);
179}
180
181static int s5p_set_next_event(unsigned long cycles,
182 struct clock_event_device *evt)
183{
184 s5p_time_setup(timer_source.event_id, cycles);
185 s5p_time_start(timer_source.event_id, NON_PERIODIC);
186
187 return 0;
188}
189
190static void s5p_set_mode(enum clock_event_mode mode,
191 struct clock_event_device *evt)
192{
193 s5p_time_stop(timer_source.event_id);
194
195 switch (mode) {
196 case CLOCK_EVT_MODE_PERIODIC:
197 s5p_time_setup(timer_source.event_id, clock_count_per_tick);
198 s5p_time_start(timer_source.event_id, PERIODIC);
199 break;
200
201 case CLOCK_EVT_MODE_ONESHOT:
202 break;
203
204 case CLOCK_EVT_MODE_UNUSED:
205 case CLOCK_EVT_MODE_SHUTDOWN:
206 break;
207
208 case CLOCK_EVT_MODE_RESUME:
209 s5p_timer_resume();
210 break;
211 }
212}
213
214static void s5p_timer_resume(void)
215{
216 /* event timer restart */
217 s5p_time_setup(timer_source.event_id, clock_count_per_tick);
218 s5p_time_start(timer_source.event_id, PERIODIC);
219
220 /* source timer restart */
221 s5p_time_setup(timer_source.source_id, TCNT_MAX);
222 s5p_time_start(timer_source.source_id, PERIODIC);
223}
224
225void __init s5p_set_timer_source(enum s5p_timer_mode event,
226 enum s5p_timer_mode source)
227{
228 s3c_device_timer[event].dev.bus = &platform_bus_type;
229 s3c_device_timer[source].dev.bus = &platform_bus_type;
230
231 timer_source.event_id = event;
232 timer_source.source_id = source;
233}
234
235static struct clock_event_device time_event_device = {
236 .name = "s5p_event_timer",
237 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
238 .rating = 200,
239 .set_next_event = s5p_set_next_event,
240 .set_mode = s5p_set_mode,
241};
242
243static irqreturn_t s5p_clock_event_isr(int irq, void *dev_id)
244{
245 struct clock_event_device *evt = dev_id;
246
247 evt->event_handler(evt);
248
249 return IRQ_HANDLED;
250}
251
252static struct irqaction s5p_clock_event_irq = {
253 .name = "s5p_time_irq",
254 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
255 .handler = s5p_clock_event_isr,
256 .dev_id = &time_event_device,
257};
258
259static void __init s5p_clockevent_init(void)
260{
261 unsigned long pclk;
262 unsigned long clock_rate;
263 unsigned int irq_number;
264 struct clk *tscaler;
265
266 pclk = clk_get_rate(timerclk);
267
268 tscaler = clk_get_parent(tdiv_event);
269
270 clk_set_rate(tscaler, pclk / 2);
271 clk_set_rate(tdiv_event, pclk / 2);
272 clk_set_parent(tin_event, tdiv_event);
273
274 clock_rate = clk_get_rate(tin_event);
275 clock_count_per_tick = clock_rate / HZ;
276
277 clockevents_calc_mult_shift(&time_event_device,
278 clock_rate, S5PTIMER_MIN_RANGE);
279 time_event_device.max_delta_ns =
280 clockevent_delta2ns(-1, &time_event_device);
281 time_event_device.min_delta_ns =
282 clockevent_delta2ns(1, &time_event_device);
283
284 time_event_device.cpumask = cpumask_of(0);
285 clockevents_register_device(&time_event_device);
286
287 irq_number = timer_source.event_id + IRQ_TIMER0;
288 setup_irq(irq_number, &s5p_clock_event_irq);
289}
290
291static void __iomem *s5p_timer_reg(void)
292{
293 unsigned long offset = 0;
294
295 switch (timer_source.source_id) {
296 case S5P_PWM0:
297 case S5P_PWM1:
298 case S5P_PWM2:
299 case S5P_PWM3:
300 offset = (timer_source.source_id * 0x0c) + 0x14;
301 break;
302
303 case S5P_PWM4:
304 offset = 0x40;
305 break;
306
307 default:
308 printk(KERN_ERR "Invalid Timer %d\n", timer_source.source_id);
309 return NULL;
310 }
311
312 return S3C_TIMERREG(offset);
313}
314
315/*
316 * Override the global weak sched_clock symbol with this
317 * local implementation which uses the clocksource to get some
318 * better resolution when scheduling the kernel. We accept that
319 * this wraps around for now, since it is just a relative time
320 * stamp. (Inspired by U300 implementation.)
321 */
322static u32 notrace s5p_read_sched_clock(void)
323{
324 void __iomem *reg = s5p_timer_reg();
325
326 if (!reg)
327 return 0;
328
329 return ~__raw_readl(reg);
330}
331
332static void __init s5p_clocksource_init(void)
333{
334 unsigned long pclk;
335 unsigned long clock_rate;
336
337 pclk = clk_get_rate(timerclk);
338
339 clk_set_rate(tdiv_source, pclk / 2);
340 clk_set_parent(tin_source, tdiv_source);
341
342 clock_rate = clk_get_rate(tin_source);
343
344 s5p_time_setup(timer_source.source_id, TCNT_MAX);
345 s5p_time_start(timer_source.source_id, PERIODIC);
346
347 setup_sched_clock(s5p_read_sched_clock, 32, clock_rate);
348
349 if (clocksource_mmio_init(s5p_timer_reg(), "s5p_clocksource_timer",
350 clock_rate, 250, 32, clocksource_mmio_readl_down))
351 panic("s5p_clocksource_timer: can't register clocksource\n");
352}
353
354static void __init s5p_timer_resources(void)
355{
356
357 unsigned long event_id = timer_source.event_id;
358 unsigned long source_id = timer_source.source_id;
359 char devname[15];
360
361 timerclk = clk_get(NULL, "timers");
362 if (IS_ERR(timerclk))
363 panic("failed to get timers clock for timer");
364
365 clk_enable(timerclk);
366
367 sprintf(devname, "s3c24xx-pwm.%lu", event_id);
368 s3c_device_timer[event_id].id = event_id;
369 s3c_device_timer[event_id].dev.init_name = devname;
370
371 tin_event = clk_get(&s3c_device_timer[event_id].dev, "pwm-tin");
372 if (IS_ERR(tin_event))
373 panic("failed to get pwm-tin clock for event timer");
374
375 tdiv_event = clk_get(&s3c_device_timer[event_id].dev, "pwm-tdiv");
376 if (IS_ERR(tdiv_event))
377 panic("failed to get pwm-tdiv clock for event timer");
378
379 clk_enable(tin_event);
380
381 sprintf(devname, "s3c24xx-pwm.%lu", source_id);
382 s3c_device_timer[source_id].id = source_id;
383 s3c_device_timer[source_id].dev.init_name = devname;
384
385 tin_source = clk_get(&s3c_device_timer[source_id].dev, "pwm-tin");
386 if (IS_ERR(tin_source))
387 panic("failed to get pwm-tin clock for source timer");
388
389 tdiv_source = clk_get(&s3c_device_timer[source_id].dev, "pwm-tdiv");
390 if (IS_ERR(tdiv_source))
391 panic("failed to get pwm-tdiv clock for source timer");
392
393 clk_enable(tin_source);
394}
395
396static void __init s5p_timer_init(void)
397{
398 s5p_timer_resources();
399 s5p_clockevent_init();
400 s5p_clocksource_init();
401}
402
403struct sys_timer s5p_timer = {
404 .init = s5p_timer_init,
405};
diff --git a/arch/arm/plat-samsung/setup-mipiphy.c b/arch/arm/plat-samsung/setup-mipiphy.c
new file mode 100644
index 000000000000..683c466c0e6a
--- /dev/null
+++ b/arch/arm/plat-samsung/setup-mipiphy.c
@@ -0,0 +1,63 @@
1/*
2 * Copyright (C) 2011 Samsung Electronics Co., Ltd.
3 *
4 * S5P - Helper functions for MIPI-CSIS and MIPI-DSIM D-PHY control
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 version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/kernel.h>
12#include <linux/platform_device.h>
13#include <linux/io.h>
14#include <linux/spinlock.h>
15#include <mach/regs-clock.h>
16
17static int __s5p_mipi_phy_control(struct platform_device *pdev,
18 bool on, u32 reset)
19{
20 static DEFINE_SPINLOCK(lock);
21 void __iomem *addr;
22 unsigned long flags;
23 int pid;
24 u32 cfg;
25
26 if (!pdev)
27 return -EINVAL;
28
29 pid = (pdev->id == -1) ? 0 : pdev->id;
30
31 if (pid != 0 && pid != 1)
32 return -EINVAL;
33
34 addr = S5P_MIPI_DPHY_CONTROL(pid);
35
36 spin_lock_irqsave(&lock, flags);
37
38 cfg = __raw_readl(addr);
39 cfg = on ? (cfg | reset) : (cfg & ~reset);
40 __raw_writel(cfg, addr);
41
42 if (on) {
43 cfg |= S5P_MIPI_DPHY_ENABLE;
44 } else if (!(cfg & (S5P_MIPI_DPHY_SRESETN |
45 S5P_MIPI_DPHY_MRESETN) & ~reset)) {
46 cfg &= ~S5P_MIPI_DPHY_ENABLE;
47 }
48
49 __raw_writel(cfg, addr);
50 spin_unlock_irqrestore(&lock, flags);
51
52 return 0;
53}
54
55int s5p_csis_phy_enable(struct platform_device *pdev, bool on)
56{
57 return __s5p_mipi_phy_control(pdev, on, S5P_MIPI_DPHY_SRESETN);
58}
59
60int s5p_dsim_phy_enable(struct platform_device *pdev, bool on)
61{
62 return __s5p_mipi_phy_control(pdev, on, S5P_MIPI_DPHY_MRESETN);
63}