diff options
author | Arnd Bergmann <arnd@arndb.de> | 2012-05-16 09:53:15 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2012-05-16 09:53:15 -0400 |
commit | a551204badbea5119a84ee4f03faefce9f2c0543 (patch) | |
tree | 8592f756c984f376be13cf839c4815ff8a7266a6 /arch/arm/plat-samsung | |
parent | 26625ddadbe9cd5791c9d64b0425821b036c5188 (diff) | |
parent | 199642bfe107c411f25fbfc16c9fd49cfef9785d (diff) |
Merge branch 'samsung/cleanup-plat-s5p' into next/soc2
Diffstat (limited to 'arch/arm/plat-samsung')
-rw-r--r-- | arch/arm/plat-samsung/Kconfig | 140 | ||||
-rw-r--r-- | arch/arm/plat-samsung/Makefile | 13 | ||||
-rw-r--r-- | arch/arm/plat-samsung/s5p-clock.c | 263 | ||||
-rw-r--r-- | arch/arm/plat-samsung/s5p-dev-mfc.c | 71 | ||||
-rw-r--r-- | arch/arm/plat-samsung/s5p-dev-uart.c | 89 | ||||
-rw-r--r-- | arch/arm/plat-samsung/s5p-irq-eint.c | 218 | ||||
-rw-r--r-- | arch/arm/plat-samsung/s5p-irq-gpioint.c | 215 | ||||
-rw-r--r-- | arch/arm/plat-samsung/s5p-irq-pm.c | 102 | ||||
-rw-r--r-- | arch/arm/plat-samsung/s5p-irq.c | 35 | ||||
-rw-r--r-- | arch/arm/plat-samsung/s5p-pm.c | 40 | ||||
-rw-r--r-- | arch/arm/plat-samsung/s5p-sleep.S | 80 | ||||
-rw-r--r-- | arch/arm/plat-samsung/s5p-time.c | 405 | ||||
-rw-r--r-- | arch/arm/plat-samsung/setup-mipiphy.c | 63 |
13 files changed, 1734 insertions, 0 deletions
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig index 77e65b483f90..a2fae4ea0936 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 | ||
16 | config 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 | |||
16 | if PLAT_SAMSUNG | 34 | if 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 | |||
73 | config 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 | ||
55 | config SAMSUNG_CLKSRC | 81 | config 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 | ||
87 | config 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 | ||
63 | config SAMSUNG_IRQ_VIC_TIMER | 94 | config 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 | ||
99 | config 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 | |||
104 | config 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 | |||
110 | config 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 | ||
70 | config SAMSUNG_GPIOLIB_4BIT | 117 | config 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 | |||
169 | config 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 | ||
122 | config S3C_ADC | 175 | config 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 | ||
330 | config S5P_DEV_CSIS0 | ||
331 | bool | ||
332 | help | ||
333 | Compile in platform device definitions for MIPI-CSIS channel 0 | ||
334 | |||
335 | config S5P_DEV_CSIS1 | ||
336 | bool | ||
337 | help | ||
338 | Compile in platform device definitions for MIPI-CSIS channel 1 | ||
339 | |||
340 | config S5P_DEV_FIMC0 | ||
341 | bool | ||
342 | help | ||
343 | Compile in platform device definitions for FIMC controller 0 | ||
344 | |||
345 | config S5P_DEV_FIMC1 | ||
346 | bool | ||
347 | help | ||
348 | Compile in platform device definitions for FIMC controller 1 | ||
349 | |||
350 | config S5P_DEV_FIMC2 | ||
351 | bool | ||
352 | help | ||
353 | Compile in platform device definitions for FIMC controller 2 | ||
354 | |||
355 | config S5P_DEV_FIMC3 | ||
356 | bool | ||
357 | help | ||
358 | Compile in platform device definitions for FIMC controller 3 | ||
359 | |||
360 | config S5P_DEV_FIMD0 | ||
361 | bool | ||
362 | help | ||
363 | Compile in platform device definitions for FIMD controller 0 | ||
364 | |||
365 | config S5P_DEV_G2D | ||
366 | bool | ||
367 | help | ||
368 | Compile in platform device definitions for G2D device | ||
369 | |||
370 | config S5P_DEV_I2C_HDMIPHY | ||
371 | bool | ||
372 | help | ||
373 | Compile in platform device definitions for I2C HDMIPHY controller | ||
374 | |||
375 | config S5P_DEV_JPEG | ||
376 | bool | ||
377 | help | ||
378 | Compile in platform device definitions for JPEG codec | ||
379 | |||
380 | config S5P_DEV_MFC | ||
381 | bool | ||
382 | help | ||
383 | Compile in setup memory (init) code for MFC | ||
384 | |||
385 | config S5P_DEV_ONENAND | ||
386 | bool | ||
387 | help | ||
388 | Compile in platform device definition for OneNAND controller | ||
389 | |||
390 | config S5P_DEV_TV | ||
391 | bool | ||
392 | help | ||
393 | Compile in platform device definition for TV interface | ||
394 | |||
395 | config S5P_DEV_USB_EHCI | ||
396 | bool | ||
397 | help | ||
398 | Compile in platform device definition for USB EHCI | ||
399 | |||
277 | config S3C24XX_PWM | 400 | config 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 | ||
407 | config 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 | ||
286 | config S3C_DMA | 414 | config 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 | ||
482 | config 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 | |||
488 | config 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 | |||
354 | comment "Power Domain" | 494 | comment "Power Domain" |
355 | 495 | ||
356 | config SAMSUNG_PD | 496 | config 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 | ||
14 | obj-y += init.o cpu.o | 14 | obj-y += init.o cpu.o |
15 | obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET) += time.o | 15 | obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET) += time.o |
16 | obj-$(CONFIG_S5P_HRT) += s5p-time.o | ||
17 | |||
16 | obj-y += clock.o | 18 | obj-y += clock.o |
17 | obj-y += pwm-clock.o | 19 | obj-y += pwm-clock.o |
18 | 20 | ||
19 | obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o | 21 | obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o |
22 | obj-$(CONFIG_S5P_CLOCK) += s5p-clock.o | ||
20 | 23 | ||
21 | obj-$(CONFIG_SAMSUNG_IRQ_VIC_TIMER) += irq-vic-timer.o | 24 | obj-$(CONFIG_SAMSUNG_IRQ_VIC_TIMER) += irq-vic-timer.o |
25 | obj-$(CONFIG_S5P_IRQ) += s5p-irq.o | ||
26 | obj-$(CONFIG_S5P_EXT_INT) += s5p-irq-eint.o | ||
27 | obj-$(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 | ||
31 | obj-y += devs.o | 37 | obj-y += devs.o |
32 | obj-y += dev-uart.o | 38 | obj-y += dev-uart.o |
39 | obj-$(CONFIG_S5P_DEV_MFC) += s5p-dev-mfc.o | ||
40 | obj-$(CONFIG_S5P_DEV_UART) += s5p-dev-uart.o | ||
33 | 41 | ||
34 | obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight.o | 42 | obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight.o |
35 | 43 | ||
44 | obj-$(CONFIG_S5P_SETUP_MIPIPHY) += setup-mipiphy.o | ||
45 | |||
36 | # DMA support | 46 | # DMA support |
37 | 47 | ||
38 | obj-$(CONFIG_S3C_DMA) += dma.o s3c-dma-ops.o | 48 | obj-$(CONFIG_S3C_DMA) += dma.o s3c-dma-ops.o |
@@ -47,6 +57,9 @@ obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o | |||
47 | 57 | ||
48 | obj-$(CONFIG_SAMSUNG_WAKEMASK) += wakeup-mask.o | 58 | obj-$(CONFIG_SAMSUNG_WAKEMASK) += wakeup-mask.o |
49 | 59 | ||
60 | obj-$(CONFIG_S5P_PM) += s5p-pm.o s5p-irq-pm.o | ||
61 | obj-$(CONFIG_S5P_SLEEP) += s5p-sleep.o | ||
62 | |||
50 | # PD support | 63 | # PD support |
51 | 64 | ||
52 | obj-$(CONFIG_SAMSUNG_PD) += pd.o | 65 | obj-$(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 | */ | ||
32 | struct clk clk_ext_xtal_mux = { | ||
33 | .name = "ext_xtal", | ||
34 | .id = -1, | ||
35 | }; | ||
36 | |||
37 | struct clk clk_xusbxti = { | ||
38 | .name = "xusbxti", | ||
39 | .id = -1, | ||
40 | }; | ||
41 | |||
42 | struct clk s5p_clk_27m = { | ||
43 | .name = "clk_27m", | ||
44 | .id = -1, | ||
45 | .rate = 27000000, | ||
46 | }; | ||
47 | |||
48 | /* 48MHz USB Phy clock output */ | ||
49 | struct 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 | */ | ||
58 | struct clk clk_fout_apll = { | ||
59 | .name = "fout_apll", | ||
60 | .id = -1, | ||
61 | }; | ||
62 | |||
63 | /* BPLL clock output */ | ||
64 | |||
65 | struct clk clk_fout_bpll = { | ||
66 | .name = "fout_bpll", | ||
67 | .id = -1, | ||
68 | }; | ||
69 | |||
70 | /* CPLL clock output */ | ||
71 | |||
72 | struct 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 | */ | ||
80 | struct clk clk_fout_mpll = { | ||
81 | .name = "fout_mpll", | ||
82 | .id = -1, | ||
83 | }; | ||
84 | |||
85 | /* EPLL clock output */ | ||
86 | struct clk clk_fout_epll = { | ||
87 | .name = "fout_epll", | ||
88 | .id = -1, | ||
89 | .ctrlbit = (1 << 31), | ||
90 | }; | ||
91 | |||
92 | /* DPLL clock output */ | ||
93 | struct clk clk_fout_dpll = { | ||
94 | .name = "fout_dpll", | ||
95 | .id = -1, | ||
96 | .ctrlbit = (1 << 31), | ||
97 | }; | ||
98 | |||
99 | /* VPLL clock output */ | ||
100 | struct clk clk_fout_vpll = { | ||
101 | .name = "fout_vpll", | ||
102 | .id = -1, | ||
103 | .ctrlbit = (1 << 31), | ||
104 | }; | ||
105 | |||
106 | /* Possible clock sources for APLL Mux */ | ||
107 | static struct clk *clk_src_apll_list[] = { | ||
108 | [0] = &clk_fin_apll, | ||
109 | [1] = &clk_fout_apll, | ||
110 | }; | ||
111 | |||
112 | struct 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 */ | ||
118 | static struct clk *clk_src_bpll_list[] = { | ||
119 | [0] = &clk_fin_bpll, | ||
120 | [1] = &clk_fout_bpll, | ||
121 | }; | ||
122 | |||
123 | struct 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 */ | ||
129 | static struct clk *clk_src_cpll_list[] = { | ||
130 | [0] = &clk_fin_cpll, | ||
131 | [1] = &clk_fout_cpll, | ||
132 | }; | ||
133 | |||
134 | struct 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 */ | ||
140 | static struct clk *clk_src_mpll_list[] = { | ||
141 | [0] = &clk_fin_mpll, | ||
142 | [1] = &clk_fout_mpll, | ||
143 | }; | ||
144 | |||
145 | struct 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 */ | ||
151 | static struct clk *clk_src_epll_list[] = { | ||
152 | [0] = &clk_fin_epll, | ||
153 | [1] = &clk_fout_epll, | ||
154 | }; | ||
155 | |||
156 | struct 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 */ | ||
162 | static struct clk *clk_src_dpll_list[] = { | ||
163 | [0] = &clk_fin_dpll, | ||
164 | [1] = &clk_fout_dpll, | ||
165 | }; | ||
166 | |||
167 | struct clksrc_sources clk_src_dpll = { | ||
168 | .sources = clk_src_dpll_list, | ||
169 | .nr_sources = ARRAY_SIZE(clk_src_dpll_list), | ||
170 | }; | ||
171 | |||
172 | struct clk clk_vpll = { | ||
173 | .name = "vpll", | ||
174 | .id = -1, | ||
175 | }; | ||
176 | |||
177 | int 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 | |||
188 | int 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 | |||
201 | unsigned long s5p_epll_get_rate(struct clk *clk) | ||
202 | { | ||
203 | return clk->rate; | ||
204 | } | ||
205 | |||
206 | int 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 | |||
221 | unsigned 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 | |||
236 | struct clk_ops s5p_sclk_spdif_ops = { | ||
237 | .set_rate = s5p_spdif_set_rate, | ||
238 | .get_rate = s5p_spdif_get_rate, | ||
239 | }; | ||
240 | |||
241 | static 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 | |||
254 | void __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 | |||
23 | struct s5p_mfc_reserved_mem { | ||
24 | phys_addr_t base; | ||
25 | unsigned long size; | ||
26 | struct device *dev; | ||
27 | }; | ||
28 | |||
29 | static struct s5p_mfc_reserved_mem s5p_mfc_mem[2] __initdata; | ||
30 | |||
31 | void __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 | |||
54 | static 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 | } | ||
71 | device_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 | |||
28 | static 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 | |||
33 | static 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 | |||
38 | static 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 | |||
43 | static 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 | |||
50 | static 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 | |||
57 | static 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 | |||
64 | struct 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 | |||
30 | static 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 | |||
39 | static 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 | |||
48 | static 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 | |||
54 | static 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 | |||
61 | static 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 | |||
120 | static 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 | */ | ||
140 | static 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 | |||
156 | static 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 | |||
162 | static 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 | |||
170 | static 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 | |||
178 | static 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 | |||
184 | static 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 | |||
190 | static 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 | |||
202 | static 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 | |||
218 | arch_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 | |||
34 | struct 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 | |||
43 | static LIST_HEAD(banks); | ||
44 | |||
45 | static 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 | |||
79 | static 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 | |||
112 | static __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 | |||
174 | int __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 | |||
201 | int __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 | |||
35 | unsigned long s3c_irqwake_intallow = 0x00000006L; | ||
36 | unsigned long s3c_irqwake_eintallow = 0xffffffffL; | ||
37 | |||
38 | int 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 | |||
70 | static 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 | |||
91 | int s3c24xx_irq_suspend(void) | ||
92 | { | ||
93 | s3c_pm_do_save(eint_save, ARRAY_SIZE(eint_save)); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | void 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 | |||
24 | void __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 | |||
26 | void s3c_pm_configure_extint(void) | ||
27 | { | ||
28 | /* nothing here yet */ | ||
29 | } | ||
30 | |||
31 | void s3c_pm_restore_core(void) | ||
32 | { | ||
33 | /* nothing here yet */ | ||
34 | } | ||
35 | |||
36 | void 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 | |||
52 | ENTRY(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] | ||
72 | resume_l2on: | ||
73 | #endif | ||
74 | b cpu_resume | ||
75 | ENDPROC(s3c_cpu_resume) | ||
76 | #ifdef CONFIG_CACHE_L2X0 | ||
77 | .globl l2x0_regs_phys | ||
78 | l2x0_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 | |||
30 | static struct clk *tin_event; | ||
31 | static struct clk *tin_source; | ||
32 | static struct clk *tdiv_event; | ||
33 | static struct clk *tdiv_source; | ||
34 | static struct clk *timerclk; | ||
35 | static struct s5p_timer_source timer_source; | ||
36 | static unsigned long clock_count_per_tick; | ||
37 | static void s5p_timer_resume(void); | ||
38 | |||
39 | static 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 | |||
73 | static 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 | |||
117 | static 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 | |||
181 | static 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 | |||
190 | static 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 | |||
214 | static 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 | |||
225 | void __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 | |||
235 | static 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 | |||
243 | static 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 | |||
252 | static 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 | |||
259 | static 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 | |||
291 | static 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 | */ | ||
322 | static 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 | |||
332 | static 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 | |||
354 | static 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 | |||
396 | static void __init s5p_timer_init(void) | ||
397 | { | ||
398 | s5p_timer_resources(); | ||
399 | s5p_clockevent_init(); | ||
400 | s5p_clocksource_init(); | ||
401 | } | ||
402 | |||
403 | struct 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 | |||
17 | static 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 | |||
55 | int 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 | |||
60 | int s5p_dsim_phy_enable(struct platform_device *pdev, bool on) | ||
61 | { | ||
62 | return __s5p_mipi_phy_control(pdev, on, S5P_MIPI_DPHY_MRESETN); | ||
63 | } | ||