aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-samsung
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-06 16:21:16 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-06 16:21:16 -0400
commit8e73e367f7dc50f1d1bc22a63e5764bb4eea9b48 (patch)
tree9bf593c1fc7612bcdd64b9ba46e41d340f9e94d3 /arch/arm/plat-samsung
parentd2f3e9eb7c9e12e89f0ac5f0dbc7a9aed0ea925d (diff)
parent7323f219533e01cc075ba45a76f3e5b214adb23f (diff)
Merge tag 'cleanup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC cleanups from Olof Johansson: "This branch contains code cleanups, moves and removals for 3.12. There's a large number of various cleanups, and a nice net removal of 13500 lines of code. Highlights worth mentioning are: - A series of patches from Stephen Boyd removing the ARM local timer API. - Move of Qualcomm MSM IOMMU code to drivers/iommu. - Samsung PWM driver cleanups from Tomasz Figa, removing legacy PWM driver and switching over to the drivers/pwm one. - Removal of some unusued auto-generated headers for OMAP2+ (PRM/CM). There's also a move of a header file out of include/linux/i2c/ to platform_data, where it really belongs. It touches mostly ARM platform code for include changes so we took it through our tree" * tag 'cleanup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (83 commits) ARM: OMAP2+: Add back the define for AM33XX_RST_GLOBAL_WARM_SW_MASK gpio: (gpio-pca953x) move header to linux/platform_data/ arm: zynq: hotplug: Remove unreachable code ARM: SAMSUNG: Remove unnecessary exynos4_default_sdhci*() tegra: simplify use of devm_ioremap_resource ARM: SAMSUNG: Remove plat/regs-timer.h header ARM: SAMSUNG: Remove remaining uses of plat/regs-timer.h header ARM: SAMSUNG: Remove pwm-clock infrastructure ARM: SAMSUNG: Remove old PWM timer platform devices pwm: Remove superseded pwm-samsung-legacy driver ARM: SAMSUNG: Modify board files to use new PWM platform device ARM: SAMSUNG: Rework private data handling in dev-backlight pwm: Add new pwm-samsung driver ARM: mach-mvebu: remove redundant DT parsing and validation ARM: msm: Only compile io.c on platforms that use it iommu/msm: Move mach includes to iommu directory ARM: msm: Remove devices-iommu.c ARM: msm: Move mach/board.h contents to common.h ARM: msm: Migrate msm_timer to CLOCKSOURCE_OF_DECLARE ARM: msm: Remove TMR and TMR0 static mappings ...
Diffstat (limited to 'arch/arm/plat-samsung')
-rw-r--r--arch/arm/plat-samsung/Kconfig14
-rw-r--r--arch/arm/plat-samsung/Makefile3
-rw-r--r--arch/arm/plat-samsung/dev-backlight.c61
-rw-r--r--arch/arm/plat-samsung/devs.c42
-rw-r--r--arch/arm/plat-samsung/include/plat/clock.h4
-rw-r--r--arch/arm/plat-samsung/include/plat/devs.h1
-rw-r--r--arch/arm/plat-samsung/include/plat/irq-vic-timer.h13
-rw-r--r--arch/arm/plat-samsung/include/plat/irqs.h9
-rw-r--r--arch/arm/plat-samsung/include/plat/pwm-clock.h81
-rw-r--r--arch/arm/plat-samsung/include/plat/pwm-core.h22
-rw-r--r--arch/arm/plat-samsung/include/plat/regs-timer.h124
-rw-r--r--arch/arm/plat-samsung/include/plat/samsung-time.h23
-rw-r--r--arch/arm/plat-samsung/include/plat/sdhci.h38
-rw-r--r--arch/arm/plat-samsung/irq-vic-timer.c98
-rw-r--r--arch/arm/plat-samsung/pwm-clock.c474
-rw-r--r--arch/arm/plat-samsung/s5p-irq.c4
-rw-r--r--arch/arm/plat-samsung/samsung-time.c394
17 files changed, 66 insertions, 1339 deletions
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index a5b5ff6e68d2..7dfba937d8fc 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -25,7 +25,6 @@ config PLAT_S5P
25 select S5P_GPIO_DRVSTR 25 select S5P_GPIO_DRVSTR
26 select SAMSUNG_CLKSRC if !COMMON_CLK 26 select SAMSUNG_CLKSRC if !COMMON_CLK
27 select SAMSUNG_GPIOLIB_4BIT 27 select SAMSUNG_GPIOLIB_4BIT
28 select SAMSUNG_IRQ_VIC_TIMER
29 help 28 help
30 Base platform code for Samsung's S5P series SoC. 29 Base platform code for Samsung's S5P series SoC.
31 30
@@ -79,14 +78,6 @@ config SAMSUNG_ATAGS
79 78
80if SAMSUNG_ATAGS 79if SAMSUNG_ATAGS
81 80
82# timer options
83
84config SAMSUNG_HRT
85 bool
86 select SAMSUNG_DEV_PWM
87 help
88 Use the High Resolution timer support
89
90# clock options 81# clock options
91 82
92config SAMSUNG_CLOCK 83config SAMSUNG_CLOCK
@@ -106,11 +97,6 @@ config S5P_CLOCK
106 97
107# options for IRQ support 98# options for IRQ support
108 99
109config SAMSUNG_IRQ_VIC_TIMER
110 bool
111 help
112 Internal configuration to build the VIC timer interrupt code.
113
114config S5P_IRQ 100config S5P_IRQ
115 def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210) 101 def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210)
116 help 102 help
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 199bbe304d02..498c7c23e9f4 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -12,15 +12,12 @@ obj- :=
12# Objects we always build independent of SoC choice 12# Objects we always build independent of SoC choice
13 13
14obj-y += init.o cpu.o 14obj-y += init.o cpu.o
15obj-$(CONFIG_SAMSUNG_HRT) += samsung-time.o
16 15
17obj-$(CONFIG_SAMSUNG_CLOCK) += clock.o 16obj-$(CONFIG_SAMSUNG_CLOCK) += clock.o
18obj-$(CONFIG_SAMSUNG_CLOCK) += pwm-clock.o
19 17
20obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o 18obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o
21obj-$(CONFIG_S5P_CLOCK) += s5p-clock.o 19obj-$(CONFIG_S5P_CLOCK) += s5p-clock.o
22 20
23obj-$(CONFIG_SAMSUNG_IRQ_VIC_TIMER) += irq-vic-timer.o
24obj-$(CONFIG_S5P_IRQ) += s5p-irq.o 21obj-$(CONFIG_S5P_IRQ) += s5p-irq.o
25obj-$(CONFIG_S5P_EXT_INT) += s5p-irq-eint.o 22obj-$(CONFIG_S5P_EXT_INT) += s5p-irq-eint.o
26obj-$(CONFIG_S5P_GPIO_INT) += s5p-irq-gpioint.o 23obj-$(CONFIG_S5P_GPIO_INT) += s5p-irq-gpioint.o
diff --git a/arch/arm/plat-samsung/dev-backlight.c b/arch/arm/plat-samsung/dev-backlight.c
index 5f197dcaf10c..d51f9565567c 100644
--- a/arch/arm/plat-samsung/dev-backlight.c
+++ b/arch/arm/plat-samsung/dev-backlight.c
@@ -20,13 +20,18 @@
20#include <plat/gpio-cfg.h> 20#include <plat/gpio-cfg.h>
21#include <plat/backlight.h> 21#include <plat/backlight.h>
22 22
23struct samsung_bl_drvdata {
24 struct platform_pwm_backlight_data plat_data;
25 struct samsung_bl_gpio_info *gpio_info;
26};
27
23static int samsung_bl_init(struct device *dev) 28static int samsung_bl_init(struct device *dev)
24{ 29{
25 int ret = 0; 30 int ret = 0;
26 struct platform_device *timer_dev = 31 struct platform_pwm_backlight_data *pdata = dev->platform_data;
27 container_of(dev->parent, struct platform_device, dev); 32 struct samsung_bl_drvdata *drvdata = container_of(pdata,
28 struct samsung_bl_gpio_info *bl_gpio_info = 33 struct samsung_bl_drvdata, plat_data);
29 timer_dev->dev.platform_data; 34 struct samsung_bl_gpio_info *bl_gpio_info = drvdata->gpio_info;
30 35
31 ret = gpio_request(bl_gpio_info->no, "Backlight"); 36 ret = gpio_request(bl_gpio_info->no, "Backlight");
32 if (ret) { 37 if (ret) {
@@ -42,10 +47,10 @@ static int samsung_bl_init(struct device *dev)
42 47
43static void samsung_bl_exit(struct device *dev) 48static void samsung_bl_exit(struct device *dev)
44{ 49{
45 struct platform_device *timer_dev = 50 struct platform_pwm_backlight_data *pdata = dev->platform_data;
46 container_of(dev->parent, struct platform_device, dev); 51 struct samsung_bl_drvdata *drvdata = container_of(pdata,
47 struct samsung_bl_gpio_info *bl_gpio_info = 52 struct samsung_bl_drvdata, plat_data);
48 timer_dev->dev.platform_data; 53 struct samsung_bl_gpio_info *bl_gpio_info = drvdata->gpio_info;
49 54
50 s3c_gpio_cfgpin(bl_gpio_info->no, S3C_GPIO_OUTPUT); 55 s3c_gpio_cfgpin(bl_gpio_info->no, S3C_GPIO_OUTPUT);
51 gpio_free(bl_gpio_info->no); 56 gpio_free(bl_gpio_info->no);
@@ -60,12 +65,14 @@ static void samsung_bl_exit(struct device *dev)
60 * for their specific boards 65 * for their specific boards
61 */ 66 */
62 67
63static struct platform_pwm_backlight_data samsung_dfl_bl_data __initdata = { 68static struct samsung_bl_drvdata samsung_dfl_bl_data __initdata = {
64 .max_brightness = 255, 69 .plat_data = {
65 .dft_brightness = 255, 70 .max_brightness = 255,
66 .pwm_period_ns = 78770, 71 .dft_brightness = 255,
67 .init = samsung_bl_init, 72 .pwm_period_ns = 78770,
68 .exit = samsung_bl_exit, 73 .init = samsung_bl_init,
74 .exit = samsung_bl_exit,
75 },
69}; 76};
70 77
71static struct platform_device samsung_dfl_bl_device __initdata = { 78static struct platform_device samsung_dfl_bl_device __initdata = {
@@ -82,6 +89,7 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
82{ 89{
83 int ret = 0; 90 int ret = 0;
84 struct platform_device *samsung_bl_device; 91 struct platform_device *samsung_bl_device;
92 struct samsung_bl_drvdata *samsung_bl_drvdata;
85 struct platform_pwm_backlight_data *samsung_bl_data; 93 struct platform_pwm_backlight_data *samsung_bl_data;
86 94
87 samsung_bl_device = kmemdup(&samsung_dfl_bl_device, 95 samsung_bl_device = kmemdup(&samsung_dfl_bl_device,
@@ -91,17 +99,19 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
91 return; 99 return;
92 } 100 }
93 101
94 samsung_bl_data = s3c_set_platdata(&samsung_dfl_bl_data, 102 samsung_bl_drvdata = kmemdup(&samsung_dfl_bl_data,
95 sizeof(struct platform_pwm_backlight_data), samsung_bl_device); 103 sizeof(samsung_dfl_bl_data), GFP_KERNEL);
96 if (!samsung_bl_data) { 104 if (!samsung_bl_drvdata) {
97 printk(KERN_ERR "%s: no memory for platform dev\n", __func__); 105 printk(KERN_ERR "%s: no memory for platform dev\n", __func__);
98 goto err_data; 106 goto err_data;
99 } 107 }
108 samsung_bl_device->dev.platform_data = &samsung_bl_drvdata->plat_data;
109 samsung_bl_drvdata->gpio_info = gpio_info;
110 samsung_bl_data = &samsung_bl_drvdata->plat_data;
100 111
101 /* Copy board specific data provided by user */ 112 /* Copy board specific data provided by user */
102 samsung_bl_data->pwm_id = bl_data->pwm_id; 113 samsung_bl_data->pwm_id = bl_data->pwm_id;
103 samsung_bl_device->dev.parent = 114 samsung_bl_device->dev.parent = &samsung_device_pwm.dev;
104 &s3c_device_timer[samsung_bl_data->pwm_id].dev;
105 115
106 if (bl_data->max_brightness) 116 if (bl_data->max_brightness)
107 samsung_bl_data->max_brightness = bl_data->max_brightness; 117 samsung_bl_data->max_brightness = bl_data->max_brightness;
@@ -122,17 +132,6 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
122 if (bl_data->check_fb) 132 if (bl_data->check_fb)
123 samsung_bl_data->check_fb = bl_data->check_fb; 133 samsung_bl_data->check_fb = bl_data->check_fb;
124 134
125 /* Keep the GPIO info for future use */
126 s3c_device_timer[samsung_bl_data->pwm_id].dev.platform_data = gpio_info;
127
128 /* Register the specific PWM timer dev for Backlight control */
129 ret = platform_device_register(
130 &s3c_device_timer[samsung_bl_data->pwm_id]);
131 if (ret) {
132 printk(KERN_ERR "failed to register pwm timer for backlight: %d\n", ret);
133 goto err_plat_reg1;
134 }
135
136 /* Register the Backlight dev */ 135 /* Register the Backlight dev */
137 ret = platform_device_register(samsung_bl_device); 136 ret = platform_device_register(samsung_bl_device);
138 if (ret) { 137 if (ret) {
@@ -143,8 +142,6 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
143 return; 142 return;
144 143
145err_plat_reg2: 144err_plat_reg2:
146 platform_device_unregister(&s3c_device_timer[samsung_bl_data->pwm_id]);
147err_plat_reg1:
148 kfree(samsung_bl_data); 145 kfree(samsung_bl_data);
149err_data: 146err_data:
150 kfree(samsung_bl_device); 147 kfree(samsung_bl_device);
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 0f9c3f431a5f..8ce0ac007eb9 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -58,6 +58,7 @@
58#include <plat/keypad.h> 58#include <plat/keypad.h>
59#include <linux/platform_data/mmc-s3cmci.h> 59#include <linux/platform_data/mmc-s3cmci.h>
60#include <linux/platform_data/mtd-nand-s3c2410.h> 60#include <linux/platform_data/mtd-nand-s3c2410.h>
61#include <plat/pwm-core.h>
61#include <plat/sdhci.h> 62#include <plat/sdhci.h>
62#include <linux/platform_data/touchscreen-s3c2410.h> 63#include <linux/platform_data/touchscreen-s3c2410.h>
63#include <linux/platform_data/usb-s3c2410_udc.h> 64#include <linux/platform_data/usb-s3c2410_udc.h>
@@ -1097,36 +1098,21 @@ arch_initcall(s5p_pmu_init);
1097/* PWM Timer */ 1098/* PWM Timer */
1098 1099
1099#ifdef CONFIG_SAMSUNG_DEV_PWM 1100#ifdef CONFIG_SAMSUNG_DEV_PWM
1101static struct resource samsung_pwm_resource[] = {
1102 DEFINE_RES_MEM(SAMSUNG_PA_TIMER, SZ_4K),
1103};
1100 1104
1101#define TIMER_RESOURCE_SIZE (1) 1105struct platform_device samsung_device_pwm = {
1102 1106 .name = "samsung-pwm",
1103#define TIMER_RESOURCE(_tmr, _irq) \ 1107 .id = -1,
1104 (struct resource [TIMER_RESOURCE_SIZE]) { \ 1108 .num_resources = ARRAY_SIZE(samsung_pwm_resource),
1105 [0] = { \ 1109 .resource = samsung_pwm_resource,
1106 .start = _irq, \
1107 .end = _irq, \
1108 .flags = IORESOURCE_IRQ \
1109 } \
1110 }
1111
1112#define DEFINE_S3C_TIMER(_tmr_no, _irq) \
1113 .name = "s3c24xx-pwm", \
1114 .id = _tmr_no, \
1115 .num_resources = TIMER_RESOURCE_SIZE, \
1116 .resource = TIMER_RESOURCE(_tmr_no, _irq), \
1117
1118/*
1119 * since we already have an static mapping for the timer,
1120 * we do not bother setting any IO resource for the base.
1121 */
1122
1123struct platform_device s3c_device_timer[] = {
1124 [0] = { DEFINE_S3C_TIMER(0, IRQ_TIMER0) },
1125 [1] = { DEFINE_S3C_TIMER(1, IRQ_TIMER1) },
1126 [2] = { DEFINE_S3C_TIMER(2, IRQ_TIMER2) },
1127 [3] = { DEFINE_S3C_TIMER(3, IRQ_TIMER3) },
1128 [4] = { DEFINE_S3C_TIMER(4, IRQ_TIMER4) },
1129}; 1110};
1111
1112void __init samsung_pwm_set_platdata(struct samsung_pwm_variant *pd)
1113{
1114 samsung_device_pwm.dev.platform_data = pd;
1115}
1130#endif /* CONFIG_SAMSUNG_DEV_PWM */ 1116#endif /* CONFIG_SAMSUNG_DEV_PWM */
1131 1117
1132/* RTC */ 1118/* RTC */
diff --git a/arch/arm/plat-samsung/include/plat/clock.h b/arch/arm/plat-samsung/include/plat/clock.h
index df45d6edc98d..63239f409807 100644
--- a/arch/arm/plat-samsung/include/plat/clock.h
+++ b/arch/arm/plat-samsung/include/plat/clock.h
@@ -145,10 +145,6 @@ extern int s3c2443_clkcon_enable_s(struct clk *clk, int enable);
145 145
146extern int s3c64xx_sclk_ctrl(struct clk *clk, int enable); 146extern int s3c64xx_sclk_ctrl(struct clk *clk, int enable);
147 147
148/* Init for pwm clock code */
149
150extern void s3c_pwmclk_init(void);
151
152/* Global watchdog clock used by arch_wtd_reset() callback */ 148/* Global watchdog clock used by arch_wtd_reset() callback */
153 149
154extern struct clk *s3c2410_wdtclk; 150extern struct clk *s3c2410_wdtclk;
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 87d501ff3328..0dc4ac4909b0 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -134,6 +134,7 @@ extern struct platform_device exynos4_device_spdif;
134 134
135extern struct platform_device samsung_asoc_idma; 135extern struct platform_device samsung_asoc_idma;
136extern struct platform_device samsung_device_keypad; 136extern struct platform_device samsung_device_keypad;
137extern struct platform_device samsung_device_pwm;
137 138
138/* s3c2440 specific devices */ 139/* s3c2440 specific devices */
139 140
diff --git a/arch/arm/plat-samsung/include/plat/irq-vic-timer.h b/arch/arm/plat-samsung/include/plat/irq-vic-timer.h
deleted file mode 100644
index 5b9c42fd32d7..000000000000
--- a/arch/arm/plat-samsung/include/plat/irq-vic-timer.h
+++ /dev/null
@@ -1,13 +0,0 @@
1/* arch/arm/plat-samsung/include/plat/irq-vic-timer.h
2 *
3 * Copyright (c) 2010 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Header file for Samsung SoC IRQ VIC timer
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13extern void s3c_init_vic_timer_irq(unsigned int num, unsigned int timer_irq);
diff --git a/arch/arm/plat-samsung/include/plat/irqs.h b/arch/arm/plat-samsung/include/plat/irqs.h
index df46b776976a..039001c0ef05 100644
--- a/arch/arm/plat-samsung/include/plat/irqs.h
+++ b/arch/arm/plat-samsung/include/plat/irqs.h
@@ -44,15 +44,6 @@
44#define S5P_IRQ_VIC2(x) (S5P_VIC2_BASE + (x)) 44#define S5P_IRQ_VIC2(x) (S5P_VIC2_BASE + (x))
45#define S5P_IRQ_VIC3(x) (S5P_VIC3_BASE + (x)) 45#define S5P_IRQ_VIC3(x) (S5P_VIC3_BASE + (x))
46 46
47#define S5P_TIMER_IRQ(x) (IRQ_TIMER_BASE + (x))
48
49#define IRQ_TIMER0 S5P_TIMER_IRQ(0)
50#define IRQ_TIMER1 S5P_TIMER_IRQ(1)
51#define IRQ_TIMER2 S5P_TIMER_IRQ(2)
52#define IRQ_TIMER3 S5P_TIMER_IRQ(3)
53#define IRQ_TIMER4 S5P_TIMER_IRQ(4)
54#define IRQ_TIMER_COUNT (5)
55
56#define IRQ_EINT(x) ((x) < 16 ? ((x) + S5P_EINT_BASE1) \ 47#define IRQ_EINT(x) ((x) < 16 ? ((x) + S5P_EINT_BASE1) \
57 : ((x) - 16 + S5P_EINT_BASE2)) 48 : ((x) - 16 + S5P_EINT_BASE2))
58 49
diff --git a/arch/arm/plat-samsung/include/plat/pwm-clock.h b/arch/arm/plat-samsung/include/plat/pwm-clock.h
deleted file mode 100644
index bf6a60eb6237..000000000000
--- a/arch/arm/plat-samsung/include/plat/pwm-clock.h
+++ /dev/null
@@ -1,81 +0,0 @@
1/* linux/arch/arm/plat-samsung/include/plat/pwm-clock.h
2 *
3 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * Copyright 2008 Openmoko, Inc.
7 * Copyright 2008 Simtec Electronics
8 * Ben Dooks <ben@simtec.co.uk>
9 * http://armlinux.simtec.co.uk/
10 *
11 * SAMSUNG - pwm clock and timer support
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16*/
17
18#ifndef __ASM_PLAT_PWM_CLOCK_H
19#define __ASM_PLAT_PWM_CLOCK_H __FILE__
20
21/**
22 * pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
23 * @tcfg: The timer TCFG1 register bits shifted down to 0.
24 *
25 * Return true if the given configuration from TCFG1 is a TCLK instead
26 * any of the TDIV clocks.
27 */
28static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
29{
30 if (soc_is_s3c24xx())
31 return tcfg == S3C2410_TCFG1_MUX_TCLK;
32 else if (soc_is_s3c64xx() || soc_is_s5pc100())
33 return tcfg >= S3C64XX_TCFG1_MUX_TCLK;
34 else if (soc_is_s5p6440() || soc_is_s5p6450())
35 return 0;
36 else
37 return tcfg == S3C64XX_TCFG1_MUX_TCLK;
38}
39
40/**
41 * tcfg_to_divisor() - convert tcfg1 setting to a divisor
42 * @tcfg1: The tcfg1 setting, shifted down.
43 *
44 * Get the divisor value for the given tcfg1 setting. We assume the
45 * caller has already checked to see if this is not a TCLK source.
46 */
47static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
48{
49 if (soc_is_s3c24xx())
50 return 1 << (tcfg1 + 1);
51 else
52 return 1 << tcfg1;
53}
54
55/**
56 * pwm_tdiv_has_div1() - does the tdiv setting have a /1
57 *
58 * Return true if we have a /1 in the tdiv setting.
59 */
60static inline unsigned int pwm_tdiv_has_div1(void)
61{
62 if (soc_is_s3c24xx())
63 return 0;
64 else
65 return 1;
66}
67
68/**
69 * pwm_tdiv_div_bits() - calculate TCFG1 divisor value.
70 * @div: The divisor to calculate the bit information for.
71 *
72 * Turn a divisor into the necessary bit field for TCFG1.
73 */
74static inline unsigned long pwm_tdiv_div_bits(unsigned int div)
75{
76 if (soc_is_s3c24xx())
77 return ilog2(div) - 1;
78 else
79 return ilog2(div);
80}
81#endif /* __ASM_PLAT_PWM_CLOCK_H */
diff --git a/arch/arm/plat-samsung/include/plat/pwm-core.h b/arch/arm/plat-samsung/include/plat/pwm-core.h
new file mode 100644
index 000000000000..5bff1facb672
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/pwm-core.h
@@ -0,0 +1,22 @@
1/*
2 * Copyright 2013 Tomasz Figa <tomasz.figa@gmail.com>
3 *
4 * Samsung PWM controller platform data helpers.
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#ifndef __ASM_ARCH_PWM_CORE_H
12#define __ASM_ARCH_PWM_CORE_H __FILE__
13
14#include <clocksource/samsung_pwm.h>
15
16#ifdef CONFIG_SAMSUNG_DEV_PWM
17extern void samsung_pwm_set_platdata(struct samsung_pwm_variant *pd);
18#else
19static inline void samsung_pwm_set_platdata(struct samsung_pwm_variant *pd) { }
20#endif
21
22#endif /* __ASM_ARCH_PWM_CORE_H */
diff --git a/arch/arm/plat-samsung/include/plat/regs-timer.h b/arch/arm/plat-samsung/include/plat/regs-timer.h
deleted file mode 100644
index d097d92f8cc7..000000000000
--- a/arch/arm/plat-samsung/include/plat/regs-timer.h
+++ /dev/null
@@ -1,124 +0,0 @@
1/* arch/arm/mach-s3c2410/include/mach/regs-timer.h
2 *
3 * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
4 * http://www.simtec.co.uk/products/SWLINUX/
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 * S3C2410 Timer configuration
11*/
12
13#ifndef __ASM_ARCH_REGS_TIMER_H
14#define __ASM_ARCH_REGS_TIMER_H
15
16#define S3C_TIMERREG(x) (S3C_VA_TIMER + (x))
17#define S3C_TIMERREG2(tmr,reg) S3C_TIMERREG((reg)+0x0c+((tmr)*0x0c))
18
19#define S3C2410_TCFG0 S3C_TIMERREG(0x00)
20#define S3C2410_TCFG1 S3C_TIMERREG(0x04)
21#define S3C2410_TCON S3C_TIMERREG(0x08)
22
23#define S3C64XX_TINT_CSTAT S3C_TIMERREG(0x44)
24
25#define S3C2410_TCFG_PRESCALER0_MASK (255<<0)
26#define S3C2410_TCFG_PRESCALER1_MASK (255<<8)
27#define S3C2410_TCFG_PRESCALER1_SHIFT (8)
28#define S3C2410_TCFG_DEADZONE_MASK (255<<16)
29#define S3C2410_TCFG_DEADZONE_SHIFT (16)
30
31#define S3C2410_TCFG1_MUX4_DIV2 (0<<16)
32#define S3C2410_TCFG1_MUX4_DIV4 (1<<16)
33#define S3C2410_TCFG1_MUX4_DIV8 (2<<16)
34#define S3C2410_TCFG1_MUX4_DIV16 (3<<16)
35#define S3C2410_TCFG1_MUX4_TCLK1 (4<<16)
36#define S3C2410_TCFG1_MUX4_MASK (15<<16)
37#define S3C2410_TCFG1_MUX4_SHIFT (16)
38
39#define S3C2410_TCFG1_MUX3_DIV2 (0<<12)
40#define S3C2410_TCFG1_MUX3_DIV4 (1<<12)
41#define S3C2410_TCFG1_MUX3_DIV8 (2<<12)
42#define S3C2410_TCFG1_MUX3_DIV16 (3<<12)
43#define S3C2410_TCFG1_MUX3_TCLK1 (4<<12)
44#define S3C2410_TCFG1_MUX3_MASK (15<<12)
45
46
47#define S3C2410_TCFG1_MUX2_DIV2 (0<<8)
48#define S3C2410_TCFG1_MUX2_DIV4 (1<<8)
49#define S3C2410_TCFG1_MUX2_DIV8 (2<<8)
50#define S3C2410_TCFG1_MUX2_DIV16 (3<<8)
51#define S3C2410_TCFG1_MUX2_TCLK1 (4<<8)
52#define S3C2410_TCFG1_MUX2_MASK (15<<8)
53
54
55#define S3C2410_TCFG1_MUX1_DIV2 (0<<4)
56#define S3C2410_TCFG1_MUX1_DIV4 (1<<4)
57#define S3C2410_TCFG1_MUX1_DIV8 (2<<4)
58#define S3C2410_TCFG1_MUX1_DIV16 (3<<4)
59#define S3C2410_TCFG1_MUX1_TCLK0 (4<<4)
60#define S3C2410_TCFG1_MUX1_MASK (15<<4)
61
62#define S3C2410_TCFG1_MUX0_DIV2 (0<<0)
63#define S3C2410_TCFG1_MUX0_DIV4 (1<<0)
64#define S3C2410_TCFG1_MUX0_DIV8 (2<<0)
65#define S3C2410_TCFG1_MUX0_DIV16 (3<<0)
66#define S3C2410_TCFG1_MUX0_TCLK0 (4<<0)
67#define S3C2410_TCFG1_MUX0_MASK (15<<0)
68
69#define S3C2410_TCFG1_MUX_DIV2 (0<<0)
70#define S3C2410_TCFG1_MUX_DIV4 (1<<0)
71#define S3C2410_TCFG1_MUX_DIV8 (2<<0)
72#define S3C2410_TCFG1_MUX_DIV16 (3<<0)
73#define S3C2410_TCFG1_MUX_TCLK (4<<0)
74#define S3C2410_TCFG1_MUX_MASK (15<<0)
75
76#define S3C64XX_TCFG1_MUX_DIV1 (0<<0)
77#define S3C64XX_TCFG1_MUX_DIV2 (1<<0)
78#define S3C64XX_TCFG1_MUX_DIV4 (2<<0)
79#define S3C64XX_TCFG1_MUX_DIV8 (3<<0)
80#define S3C64XX_TCFG1_MUX_DIV16 (4<<0)
81#define S3C64XX_TCFG1_MUX_TCLK (5<<0) /* 3 sets of TCLK */
82#define S3C64XX_TCFG1_MUX_MASK (15<<0)
83
84#define S3C2410_TCFG1_SHIFT(x) ((x) * 4)
85
86/* for each timer, we have an count buffer, an compare buffer and
87 * an observation buffer
88*/
89
90/* WARNING - timer 4 has no buffer reg, and it's observation is at +4 */
91
92#define S3C2410_TCNTB(tmr) S3C_TIMERREG2(tmr, 0x00)
93#define S3C2410_TCMPB(tmr) S3C_TIMERREG2(tmr, 0x04)
94#define S3C2410_TCNTO(tmr) S3C_TIMERREG2(tmr, (((tmr) == 4) ? 0x04 : 0x08))
95
96#define S3C2410_TCON_T4RELOAD (1<<22)
97#define S3C2410_TCON_T4MANUALUPD (1<<21)
98#define S3C2410_TCON_T4START (1<<20)
99
100#define S3C2410_TCON_T3RELOAD (1<<19)
101#define S3C2410_TCON_T3INVERT (1<<18)
102#define S3C2410_TCON_T3MANUALUPD (1<<17)
103#define S3C2410_TCON_T3START (1<<16)
104
105#define S3C2410_TCON_T2RELOAD (1<<15)
106#define S3C2410_TCON_T2INVERT (1<<14)
107#define S3C2410_TCON_T2MANUALUPD (1<<13)
108#define S3C2410_TCON_T2START (1<<12)
109
110#define S3C2410_TCON_T1RELOAD (1<<11)
111#define S3C2410_TCON_T1INVERT (1<<10)
112#define S3C2410_TCON_T1MANUALUPD (1<<9)
113#define S3C2410_TCON_T1START (1<<8)
114
115#define S3C2410_TCON_T0DEADZONE (1<<4)
116#define S3C2410_TCON_T0RELOAD (1<<3)
117#define S3C2410_TCON_T0INVERT (1<<2)
118#define S3C2410_TCON_T0MANUALUPD (1<<1)
119#define S3C2410_TCON_T0START (1<<0)
120
121#endif /* __ASM_ARCH_REGS_TIMER_H */
122
123
124
diff --git a/arch/arm/plat-samsung/include/plat/samsung-time.h b/arch/arm/plat-samsung/include/plat/samsung-time.h
index 4cc99bb1f176..209464adef97 100644
--- a/arch/arm/plat-samsung/include/plat/samsung-time.h
+++ b/arch/arm/plat-samsung/include/plat/samsung-time.h
@@ -22,29 +22,6 @@ enum samsung_timer_mode {
22 SAMSUNG_PWM4, 22 SAMSUNG_PWM4,
23}; 23};
24 24
25struct samsung_timer_source {
26 unsigned int event_id;
27 unsigned int source_id;
28};
29
30/* Be able to sleep for atleast 4 seconds (usually more) */
31#define SAMSUNG_TIMER_MIN_RANGE 4
32
33#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S5PC100)
34#define TCNT_MAX 0xffff
35#define TSCALER_DIV 25
36#define TDIV 50
37#define TSIZE 16
38#else
39#define TCNT_MAX 0xffffffff
40#define TSCALER_DIV 2
41#define TDIV 2
42#define TSIZE 32
43#endif
44
45#define NON_PERIODIC 0
46#define PERIODIC 1
47
48extern void __init samsung_set_timer_source(enum samsung_timer_mode event, 25extern void __init samsung_set_timer_source(enum samsung_timer_mode event,
49 enum samsung_timer_mode source); 26 enum samsung_timer_mode source);
50 27
diff --git a/arch/arm/plat-samsung/include/plat/sdhci.h b/arch/arm/plat-samsung/include/plat/sdhci.h
index ce1d0f785efd..bf650218b40e 100644
--- a/arch/arm/plat-samsung/include/plat/sdhci.h
+++ b/arch/arm/plat-samsung/include/plat/sdhci.h
@@ -260,44 +260,6 @@ static inline void s5pv210_default_sdhci3(void) { }
260 260
261#endif /* CONFIG_S5PV210_SETUP_SDHCI */ 261#endif /* CONFIG_S5PV210_SETUP_SDHCI */
262 262
263/* EXYNOS4 SDHCI setup */
264#ifdef CONFIG_EXYNOS4_SETUP_SDHCI
265static inline void exynos4_default_sdhci0(void)
266{
267#ifdef CONFIG_S3C_DEV_HSMMC
268 s3c_hsmmc0_def_platdata.cfg_gpio = exynos4_setup_sdhci0_cfg_gpio;
269#endif
270}
271
272static inline void exynos4_default_sdhci1(void)
273{
274#ifdef CONFIG_S3C_DEV_HSMMC1
275 s3c_hsmmc1_def_platdata.cfg_gpio = exynos4_setup_sdhci1_cfg_gpio;
276#endif
277}
278
279static inline void exynos4_default_sdhci2(void)
280{
281#ifdef CONFIG_S3C_DEV_HSMMC2
282 s3c_hsmmc2_def_platdata.cfg_gpio = exynos4_setup_sdhci2_cfg_gpio;
283#endif
284}
285
286static inline void exynos4_default_sdhci3(void)
287{
288#ifdef CONFIG_S3C_DEV_HSMMC3
289 s3c_hsmmc3_def_platdata.cfg_gpio = exynos4_setup_sdhci3_cfg_gpio;
290#endif
291}
292
293#else
294static inline void exynos4_default_sdhci0(void) { }
295static inline void exynos4_default_sdhci1(void) { }
296static inline void exynos4_default_sdhci2(void) { }
297static inline void exynos4_default_sdhci3(void) { }
298
299#endif /* CONFIG_EXYNOS4_SETUP_SDHCI */
300
301static inline void s3c_sdhci_setname(int id, char *name) 263static inline void s3c_sdhci_setname(int id, char *name)
302{ 264{
303 switch (id) { 265 switch (id) {
diff --git a/arch/arm/plat-samsung/irq-vic-timer.c b/arch/arm/plat-samsung/irq-vic-timer.c
deleted file mode 100644
index 0fceb4273824..000000000000
--- a/arch/arm/plat-samsung/irq-vic-timer.c
+++ /dev/null
@@ -1,98 +0,0 @@
1/* arch/arm/plat-samsung/irq-vic-timer.c
2 * originally part of arch/arm/plat-s3c64xx/irq.c
3 *
4 * Copyright 2008 Openmoko, Inc.
5 * Copyright 2008 Simtec Electronics
6 * Ben Dooks <ben@simtec.co.uk>
7 * http://armlinux.simtec.co.uk/
8 *
9 * S3C64XX - Interrupt handling
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/kernel.h>
17#include <linux/interrupt.h>
18#include <linux/irq.h>
19#include <linux/irqchip/chained_irq.h>
20#include <linux/io.h>
21
22#include <mach/map.h>
23#include <mach/irqs.h>
24#include <plat/cpu.h>
25#include <plat/irq-vic-timer.h>
26#include <plat/regs-timer.h>
27
28static void s3c_irq_demux_vic_timer(unsigned int irq, struct irq_desc *desc)
29{
30 struct irq_chip *chip = irq_get_chip(irq);
31 chained_irq_enter(chip, desc);
32 generic_handle_irq((int)desc->irq_data.handler_data);
33 chained_irq_exit(chip, desc);
34}
35
36/* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */
37static void s3c_irq_timer_ack(struct irq_data *d)
38{
39 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
40 u32 mask = (1 << 5) << (d->irq - gc->irq_base);
41
42 irq_reg_writel(mask | gc->mask_cache, gc->reg_base);
43}
44
45/**
46 * s3c_init_vic_timer_irq() - initialise timer irq chanined off VIC.\
47 * @num: Number of timers to initialize
48 * @timer_irq: Base IRQ number to be used for the timers.
49 *
50 * Register the necessary IRQ chaining and support for the timer IRQs
51 * chained of the VIC.
52 */
53void __init s3c_init_vic_timer_irq(unsigned int num, unsigned int timer_irq)
54{
55 unsigned int pirq[5] = { IRQ_TIMER0_VIC, IRQ_TIMER1_VIC, IRQ_TIMER2_VIC,
56 IRQ_TIMER3_VIC, IRQ_TIMER4_VIC };
57 struct irq_chip_generic *s3c_tgc;
58 struct irq_chip_type *ct;
59 unsigned int i;
60
61#ifdef CONFIG_ARCH_EXYNOS
62 if (soc_is_exynos5250()) {
63 pirq[0] = EXYNOS5_IRQ_TIMER0_VIC;
64 pirq[1] = EXYNOS5_IRQ_TIMER1_VIC;
65 pirq[2] = EXYNOS5_IRQ_TIMER2_VIC;
66 pirq[3] = EXYNOS5_IRQ_TIMER3_VIC;
67 pirq[4] = EXYNOS5_IRQ_TIMER4_VIC;
68 } else {
69 pirq[0] = EXYNOS4_IRQ_TIMER0_VIC;
70 pirq[1] = EXYNOS4_IRQ_TIMER1_VIC;
71 pirq[2] = EXYNOS4_IRQ_TIMER2_VIC;
72 pirq[3] = EXYNOS4_IRQ_TIMER3_VIC;
73 pirq[4] = EXYNOS4_IRQ_TIMER4_VIC;
74 }
75#endif
76 s3c_tgc = irq_alloc_generic_chip("s3c-timer", 1, timer_irq,
77 S3C64XX_TINT_CSTAT, handle_level_irq);
78
79 if (!s3c_tgc) {
80 pr_err("%s: irq_alloc_generic_chip for IRQ %d failed\n",
81 __func__, timer_irq);
82 return;
83 }
84
85 ct = s3c_tgc->chip_types;
86 ct->chip.irq_mask = irq_gc_mask_clr_bit;
87 ct->chip.irq_unmask = irq_gc_mask_set_bit;
88 ct->chip.irq_ack = s3c_irq_timer_ack;
89 irq_setup_generic_chip(s3c_tgc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
90 IRQ_NOREQUEST | IRQ_NOPROBE, 0);
91 /* Clear the upper bits of the mask_cache*/
92 s3c_tgc->mask_cache &= 0x1f;
93
94 for (i = 0; i < num; i++, timer_irq++) {
95 irq_set_chained_handler(pirq[i], s3c_irq_demux_vic_timer);
96 irq_set_handler_data(pirq[i], (void *)timer_irq);
97 }
98}
diff --git a/arch/arm/plat-samsung/pwm-clock.c b/arch/arm/plat-samsung/pwm-clock.c
deleted file mode 100644
index a35ff3bcffe4..000000000000
--- a/arch/arm/plat-samsung/pwm-clock.c
+++ /dev/null
@@ -1,474 +0,0 @@
1/* linux/arch/arm/plat-s3c24xx/pwm-clock.c
2 *
3 * Copyright (c) 2007 Simtec Electronics
4 * Copyright (c) 2007, 2008 Ben Dooks
5 * Ben Dooks <ben-linux@fluff.org>
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 as published by
9 * the Free Software Foundation; either version 2 of the License.
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/log2.h>
18#include <linux/clk.h>
19#include <linux/err.h>
20#include <linux/io.h>
21
22#include <mach/hardware.h>
23#include <mach/map.h>
24#include <asm/irq.h>
25
26#include <plat/clock.h>
27#include <plat/cpu.h>
28
29#include <plat/regs-timer.h>
30#include <plat/pwm-clock.h>
31
32/* Each of the timers 0 through 5 go through the following
33 * clock tree, with the inputs depending on the timers.
34 *
35 * pclk ---- [ prescaler 0 ] -+---> timer 0
36 * +---> timer 1
37 *
38 * pclk ---- [ prescaler 1 ] -+---> timer 2
39 * +---> timer 3
40 * \---> timer 4
41 *
42 * Which are fed into the timers as so:
43 *
44 * prescaled 0 ---- [ div 2,4,8,16 ] ---\
45 * [mux] -> timer 0
46 * tclk 0 ------------------------------/
47 *
48 * prescaled 0 ---- [ div 2,4,8,16 ] ---\
49 * [mux] -> timer 1
50 * tclk 0 ------------------------------/
51 *
52 *
53 * prescaled 1 ---- [ div 2,4,8,16 ] ---\
54 * [mux] -> timer 2
55 * tclk 1 ------------------------------/
56 *
57 * prescaled 1 ---- [ div 2,4,8,16 ] ---\
58 * [mux] -> timer 3
59 * tclk 1 ------------------------------/
60 *
61 * prescaled 1 ---- [ div 2,4,8, 16 ] --\
62 * [mux] -> timer 4
63 * tclk 1 ------------------------------/
64 *
65 * Since the mux and the divider are tied together in the
66 * same register space, it is impossible to set the parent
67 * and the rate at the same time. To avoid this, we add an
68 * intermediate 'prescaled-and-divided' clock to select
69 * as the parent for the timer input clock called tdiv.
70 *
71 * prescaled clk --> pwm-tdiv ---\
72 * [ mux ] --> timer X
73 * tclk -------------------------/
74*/
75
76static struct clk clk_timer_scaler[];
77
78static unsigned long clk_pwm_scaler_get_rate(struct clk *clk)
79{
80 unsigned long tcfg0 = __raw_readl(S3C2410_TCFG0);
81
82 if (clk == &clk_timer_scaler[1]) {
83 tcfg0 &= S3C2410_TCFG_PRESCALER1_MASK;
84 tcfg0 >>= S3C2410_TCFG_PRESCALER1_SHIFT;
85 } else {
86 tcfg0 &= S3C2410_TCFG_PRESCALER0_MASK;
87 }
88
89 return clk_get_rate(clk->parent) / (tcfg0 + 1);
90}
91
92static unsigned long clk_pwm_scaler_round_rate(struct clk *clk,
93 unsigned long rate)
94{
95 unsigned long parent_rate = clk_get_rate(clk->parent);
96 unsigned long divisor = parent_rate / rate;
97
98 if (divisor > 256)
99 divisor = 256;
100 else if (divisor < 2)
101 divisor = 2;
102
103 return parent_rate / divisor;
104}
105
106static int clk_pwm_scaler_set_rate(struct clk *clk, unsigned long rate)
107{
108 unsigned long round = clk_pwm_scaler_round_rate(clk, rate);
109 unsigned long tcfg0;
110 unsigned long divisor;
111 unsigned long flags;
112
113 divisor = clk_get_rate(clk->parent) / round;
114 divisor--;
115
116 local_irq_save(flags);
117 tcfg0 = __raw_readl(S3C2410_TCFG0);
118
119 if (clk == &clk_timer_scaler[1]) {
120 tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
121 tcfg0 |= divisor << S3C2410_TCFG_PRESCALER1_SHIFT;
122 } else {
123 tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
124 tcfg0 |= divisor;
125 }
126
127 __raw_writel(tcfg0, S3C2410_TCFG0);
128 local_irq_restore(flags);
129
130 return 0;
131}
132
133static struct clk_ops clk_pwm_scaler_ops = {
134 .get_rate = clk_pwm_scaler_get_rate,
135 .set_rate = clk_pwm_scaler_set_rate,
136 .round_rate = clk_pwm_scaler_round_rate,
137};
138
139static struct clk clk_timer_scaler[] = {
140 [0] = {
141 .name = "pwm-scaler0",
142 .id = -1,
143 .ops = &clk_pwm_scaler_ops,
144 },
145 [1] = {
146 .name = "pwm-scaler1",
147 .id = -1,
148 .ops = &clk_pwm_scaler_ops,
149 },
150};
151
152static struct clk clk_timer_tclk[] = {
153 [0] = {
154 .name = "pwm-tclk0",
155 .id = -1,
156 },
157 [1] = {
158 .name = "pwm-tclk1",
159 .id = -1,
160 },
161};
162
163struct pwm_tdiv_clk {
164 struct clk clk;
165 unsigned int divisor;
166};
167
168static inline struct pwm_tdiv_clk *to_tdiv(struct clk *clk)
169{
170 return container_of(clk, struct pwm_tdiv_clk, clk);
171}
172
173static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk)
174{
175 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
176 unsigned int divisor;
177
178 tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
179 tcfg1 &= S3C2410_TCFG1_MUX_MASK;
180
181 if (pwm_cfg_src_is_tclk(tcfg1))
182 divisor = to_tdiv(clk)->divisor;
183 else
184 divisor = tcfg_to_divisor(tcfg1);
185
186 return clk_get_rate(clk->parent) / divisor;
187}
188
189static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk,
190 unsigned long rate)
191{
192 unsigned long parent_rate;
193 unsigned long divisor;
194
195 parent_rate = clk_get_rate(clk->parent);
196 divisor = parent_rate / rate;
197
198 if (divisor <= 1 && pwm_tdiv_has_div1())
199 divisor = 1;
200 else if (divisor <= 2)
201 divisor = 2;
202 else if (divisor <= 4)
203 divisor = 4;
204 else if (divisor <= 8)
205 divisor = 8;
206 else
207 divisor = 16;
208
209 return parent_rate / divisor;
210}
211
212static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk)
213{
214 return pwm_tdiv_div_bits(divclk->divisor);
215}
216
217static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk)
218{
219 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
220 unsigned long bits = clk_pwm_tdiv_bits(divclk);
221 unsigned long flags;
222 unsigned long shift = S3C2410_TCFG1_SHIFT(divclk->clk.id);
223
224 local_irq_save(flags);
225
226 tcfg1 = __raw_readl(S3C2410_TCFG1);
227 tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
228 tcfg1 |= bits << shift;
229 __raw_writel(tcfg1, S3C2410_TCFG1);
230
231 local_irq_restore(flags);
232}
233
234static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate)
235{
236 struct pwm_tdiv_clk *divclk = to_tdiv(clk);
237 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
238 unsigned long parent_rate = clk_get_rate(clk->parent);
239 unsigned long divisor;
240
241 tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
242 tcfg1 &= S3C2410_TCFG1_MUX_MASK;
243
244 rate = clk_round_rate(clk, rate);
245 divisor = parent_rate / rate;
246
247 if (divisor > 16)
248 return -EINVAL;
249
250 divclk->divisor = divisor;
251
252 /* Update the current MUX settings if we are currently
253 * selected as the clock source for this clock. */
254
255 if (!pwm_cfg_src_is_tclk(tcfg1))
256 clk_pwm_tdiv_update(divclk);
257
258 return 0;
259}
260
261static struct clk_ops clk_tdiv_ops = {
262 .get_rate = clk_pwm_tdiv_get_rate,
263 .set_rate = clk_pwm_tdiv_set_rate,
264 .round_rate = clk_pwm_tdiv_round_rate,
265};
266
267static struct pwm_tdiv_clk clk_timer_tdiv[] = {
268 [0] = {
269 .clk = {
270 .name = "pwm-tdiv",
271 .devname = "s3c24xx-pwm.0",
272 .ops = &clk_tdiv_ops,
273 .parent = &clk_timer_scaler[0],
274 },
275 },
276 [1] = {
277 .clk = {
278 .name = "pwm-tdiv",
279 .devname = "s3c24xx-pwm.1",
280 .ops = &clk_tdiv_ops,
281 .parent = &clk_timer_scaler[0],
282 }
283 },
284 [2] = {
285 .clk = {
286 .name = "pwm-tdiv",
287 .devname = "s3c24xx-pwm.2",
288 .ops = &clk_tdiv_ops,
289 .parent = &clk_timer_scaler[1],
290 },
291 },
292 [3] = {
293 .clk = {
294 .name = "pwm-tdiv",
295 .devname = "s3c24xx-pwm.3",
296 .ops = &clk_tdiv_ops,
297 .parent = &clk_timer_scaler[1],
298 },
299 },
300 [4] = {
301 .clk = {
302 .name = "pwm-tdiv",
303 .devname = "s3c24xx-pwm.4",
304 .ops = &clk_tdiv_ops,
305 .parent = &clk_timer_scaler[1],
306 },
307 },
308};
309
310static int __init clk_pwm_tdiv_register(unsigned int id)
311{
312 struct pwm_tdiv_clk *divclk = &clk_timer_tdiv[id];
313 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
314
315 tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
316 tcfg1 &= S3C2410_TCFG1_MUX_MASK;
317
318 divclk->clk.id = id;
319 divclk->divisor = tcfg_to_divisor(tcfg1);
320
321 return s3c24xx_register_clock(&divclk->clk);
322}
323
324static inline struct clk *s3c24xx_pwmclk_tclk(unsigned int id)
325{
326 return (id >= 2) ? &clk_timer_tclk[1] : &clk_timer_tclk[0];
327}
328
329static inline struct clk *s3c24xx_pwmclk_tdiv(unsigned int id)
330{
331 return &clk_timer_tdiv[id].clk;
332}
333
334static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent)
335{
336 unsigned int id = clk->id;
337 unsigned long tcfg1;
338 unsigned long flags;
339 unsigned long bits;
340 unsigned long shift = S3C2410_TCFG1_SHIFT(id);
341
342 unsigned long mux_tclk;
343
344 if (soc_is_s3c24xx())
345 mux_tclk = S3C2410_TCFG1_MUX_TCLK;
346 else if (soc_is_s5p6440() || soc_is_s5p6450())
347 mux_tclk = 0;
348 else
349 mux_tclk = S3C64XX_TCFG1_MUX_TCLK;
350
351 if (parent == s3c24xx_pwmclk_tclk(id))
352 bits = mux_tclk << shift;
353 else if (parent == s3c24xx_pwmclk_tdiv(id))
354 bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift;
355 else
356 return -EINVAL;
357
358 clk->parent = parent;
359
360 local_irq_save(flags);
361
362 tcfg1 = __raw_readl(S3C2410_TCFG1);
363 tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
364 __raw_writel(tcfg1 | bits, S3C2410_TCFG1);
365
366 local_irq_restore(flags);
367
368 return 0;
369}
370
371static struct clk_ops clk_tin_ops = {
372 .set_parent = clk_pwm_tin_set_parent,
373};
374
375static struct clk clk_tin[] = {
376 [0] = {
377 .name = "pwm-tin",
378 .devname = "s3c24xx-pwm.0",
379 .id = 0,
380 .ops = &clk_tin_ops,
381 },
382 [1] = {
383 .name = "pwm-tin",
384 .devname = "s3c24xx-pwm.1",
385 .id = 1,
386 .ops = &clk_tin_ops,
387 },
388 [2] = {
389 .name = "pwm-tin",
390 .devname = "s3c24xx-pwm.2",
391 .id = 2,
392 .ops = &clk_tin_ops,
393 },
394 [3] = {
395 .name = "pwm-tin",
396 .devname = "s3c24xx-pwm.3",
397 .id = 3,
398 .ops = &clk_tin_ops,
399 },
400 [4] = {
401 .name = "pwm-tin",
402 .devname = "s3c24xx-pwm.4",
403 .id = 4,
404 .ops = &clk_tin_ops,
405 },
406};
407
408static __init int clk_pwm_tin_register(struct clk *pwm)
409{
410 unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
411 unsigned int id = pwm->id;
412
413 struct clk *parent;
414 int ret;
415
416 ret = s3c24xx_register_clock(pwm);
417 if (ret < 0)
418 return ret;
419
420 tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
421 tcfg1 &= S3C2410_TCFG1_MUX_MASK;
422
423 if (pwm_cfg_src_is_tclk(tcfg1))
424 parent = s3c24xx_pwmclk_tclk(id);
425 else
426 parent = s3c24xx_pwmclk_tdiv(id);
427
428 return clk_set_parent(pwm, parent);
429}
430
431/**
432 * s3c_pwmclk_init() - initialise pwm clocks
433 *
434 * Initialise and register the clocks which provide the inputs for the
435 * pwm timer blocks.
436 *
437 * Note, this call is required by the time core, so must be called after
438 * the base clocks are added and before any of the initcalls are run.
439 */
440__init void s3c_pwmclk_init(void)
441{
442 struct clk *clk_timers;
443 unsigned int clk;
444 int ret;
445
446 clk_timers = clk_get(NULL, "timers");
447 if (IS_ERR(clk_timers)) {
448 printk(KERN_ERR "%s: no parent clock\n", __func__);
449 return;
450 }
451
452 for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++)
453 clk_timer_scaler[clk].parent = clk_timers;
454
455 s3c_register_clocks(clk_timer_scaler, ARRAY_SIZE(clk_timer_scaler));
456 s3c_register_clocks(clk_timer_tclk, ARRAY_SIZE(clk_timer_tclk));
457
458 for (clk = 0; clk < ARRAY_SIZE(clk_timer_tdiv); clk++) {
459 ret = clk_pwm_tdiv_register(clk);
460
461 if (ret < 0) {
462 printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk);
463 return;
464 }
465 }
466
467 for (clk = 0; clk < ARRAY_SIZE(clk_tin); clk++) {
468 ret = clk_pwm_tin_register(&clk_tin[clk]);
469 if (ret < 0) {
470 printk(KERN_ERR "error adding pwm%d tin clock\n", clk);
471 return;
472 }
473 }
474}
diff --git a/arch/arm/plat-samsung/s5p-irq.c b/arch/arm/plat-samsung/s5p-irq.c
index ff1a76011b1e..ddfaca9c79d8 100644
--- a/arch/arm/plat-samsung/s5p-irq.c
+++ b/arch/arm/plat-samsung/s5p-irq.c
@@ -17,9 +17,7 @@
17 17
18#include <mach/irqs.h> 18#include <mach/irqs.h>
19#include <mach/map.h> 19#include <mach/map.h>
20#include <plat/regs-timer.h>
21#include <plat/cpu.h> 20#include <plat/cpu.h>
22#include <plat/irq-vic-timer.h>
23 21
24void __init s5p_init_irq(u32 *vic, u32 num_vic) 22void __init s5p_init_irq(u32 *vic, u32 num_vic)
25{ 23{
@@ -30,6 +28,4 @@ void __init s5p_init_irq(u32 *vic, u32 num_vic)
30 for (irq = 0; irq < num_vic; irq++) 28 for (irq = 0; irq < num_vic; irq++)
31 vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0); 29 vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0);
32#endif 30#endif
33
34 s3c_init_vic_timer_irq(5, IRQ_TIMER0);
35} 31}
diff --git a/arch/arm/plat-samsung/samsung-time.c b/arch/arm/plat-samsung/samsung-time.c
deleted file mode 100644
index 2957075ca836..000000000000
--- a/arch/arm/plat-samsung/samsung-time.c
+++ /dev/null
@@ -1,394 +0,0 @@
1/*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com/
4 *
5 * samsung - Common hr-timer support (s3c and s5p)
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#include <linux/sched_clock.h>
19
20#include <asm/smp_twd.h>
21#include <asm/mach/time.h>
22#include <asm/mach/arch.h>
23#include <asm/mach/map.h>
24
25#include <mach/map.h>
26#include <plat/devs.h>
27#include <plat/regs-timer.h>
28#include <plat/samsung-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 samsung_timer_source timer_source;
36static unsigned long clock_count_per_tick;
37static void samsung_timer_resume(void);
38
39static void samsung_time_stop(enum samsung_timer_mode mode)
40{
41 unsigned long tcon;
42
43 tcon = __raw_readl(S3C2410_TCON);
44
45 switch (mode) {
46 case SAMSUNG_PWM0:
47 tcon &= ~S3C2410_TCON_T0START;
48 break;
49
50 case SAMSUNG_PWM1:
51 tcon &= ~S3C2410_TCON_T1START;
52 break;
53
54 case SAMSUNG_PWM2:
55 tcon &= ~S3C2410_TCON_T2START;
56 break;
57
58 case SAMSUNG_PWM3:
59 tcon &= ~S3C2410_TCON_T3START;
60 break;
61
62 case SAMSUNG_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 samsung_time_setup(enum samsung_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 SAMSUNG_PWM0:
83 tcon &= ~(0x0f << 0);
84 tcon |= S3C2410_TCON_T0MANUALUPD;
85 break;
86
87 case SAMSUNG_PWM1:
88 tcon &= ~(0x0f << 8);
89 tcon |= S3C2410_TCON_T1MANUALUPD;
90 break;
91
92 case SAMSUNG_PWM2:
93 tcon &= ~(0x0f << 12);
94 tcon |= S3C2410_TCON_T2MANUALUPD;
95 break;
96
97 case SAMSUNG_PWM3:
98 tcon &= ~(0x0f << 16);
99 tcon |= S3C2410_TCON_T3MANUALUPD;
100 break;
101
102 case SAMSUNG_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 samsung_time_start(enum samsung_timer_mode mode, bool periodic)
118{
119 unsigned long tcon;
120
121 tcon = __raw_readl(S3C2410_TCON);
122
123 switch (mode) {
124 case SAMSUNG_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 SAMSUNG_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 SAMSUNG_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 SAMSUNG_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 SAMSUNG_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 samsung_set_next_event(unsigned long cycles,
182 struct clock_event_device *evt)
183{
184 samsung_time_setup(timer_source.event_id, cycles);
185 samsung_time_start(timer_source.event_id, NON_PERIODIC);
186
187 return 0;
188}
189
190static void samsung_set_mode(enum clock_event_mode mode,
191 struct clock_event_device *evt)
192{
193 samsung_time_stop(timer_source.event_id);
194
195 switch (mode) {
196 case CLOCK_EVT_MODE_PERIODIC:
197 samsung_time_setup(timer_source.event_id, clock_count_per_tick);
198 samsung_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 samsung_timer_resume();
210 break;
211 }
212}
213
214static void samsung_timer_resume(void)
215{
216 /* event timer restart */
217 samsung_time_setup(timer_source.event_id, clock_count_per_tick);
218 samsung_time_start(timer_source.event_id, PERIODIC);
219
220 /* source timer restart */
221 samsung_time_setup(timer_source.source_id, TCNT_MAX);
222 samsung_time_start(timer_source.source_id, PERIODIC);
223}
224
225void __init samsung_set_timer_source(enum samsung_timer_mode event,
226 enum samsung_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 = "samsung_event_timer",
237 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
238 .rating = 200,
239 .set_next_event = samsung_set_next_event,
240 .set_mode = samsung_set_mode,
241};
242
243static irqreturn_t samsung_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 samsung_clock_event_irq = {
253 .name = "samsung_time_irq",
254 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
255 .handler = samsung_clock_event_isr,
256 .dev_id = &time_event_device,
257};
258
259static void __init samsung_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 / TSCALER_DIV);
271 clk_set_rate(tdiv_event, pclk / TDIV);
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 time_event_device.cpumask = cpumask_of(0);
278 clockevents_config_and_register(&time_event_device, clock_rate, 1, -1);
279
280 irq_number = timer_source.event_id + IRQ_TIMER0;
281 setup_irq(irq_number, &samsung_clock_event_irq);
282}
283
284static void __iomem *samsung_timer_reg(void)
285{
286 unsigned long offset = 0;
287
288 switch (timer_source.source_id) {
289 case SAMSUNG_PWM0:
290 case SAMSUNG_PWM1:
291 case SAMSUNG_PWM2:
292 case SAMSUNG_PWM3:
293 offset = (timer_source.source_id * 0x0c) + 0x14;
294 break;
295
296 case SAMSUNG_PWM4:
297 offset = 0x40;
298 break;
299
300 default:
301 printk(KERN_ERR "Invalid Timer %d\n", timer_source.source_id);
302 return NULL;
303 }
304
305 return S3C_TIMERREG(offset);
306}
307
308/*
309 * Override the global weak sched_clock symbol with this
310 * local implementation which uses the clocksource to get some
311 * better resolution when scheduling the kernel. We accept that
312 * this wraps around for now, since it is just a relative time
313 * stamp. (Inspired by U300 implementation.)
314 */
315static u32 notrace samsung_read_sched_clock(void)
316{
317 void __iomem *reg = samsung_timer_reg();
318
319 if (!reg)
320 return 0;
321
322 return ~__raw_readl(reg);
323}
324
325static void __init samsung_clocksource_init(void)
326{
327 unsigned long pclk;
328 unsigned long clock_rate;
329
330 pclk = clk_get_rate(timerclk);
331
332 clk_set_rate(tdiv_source, pclk / TDIV);
333 clk_set_parent(tin_source, tdiv_source);
334
335 clock_rate = clk_get_rate(tin_source);
336
337 samsung_time_setup(timer_source.source_id, TCNT_MAX);
338 samsung_time_start(timer_source.source_id, PERIODIC);
339
340 setup_sched_clock(samsung_read_sched_clock, TSIZE, clock_rate);
341
342 if (clocksource_mmio_init(samsung_timer_reg(), "samsung_clocksource_timer",
343 clock_rate, 250, TSIZE, clocksource_mmio_readl_down))
344 panic("samsung_clocksource_timer: can't register clocksource\n");
345}
346
347static void __init samsung_timer_resources(void)
348{
349
350 unsigned long event_id = timer_source.event_id;
351 unsigned long source_id = timer_source.source_id;
352 char devname[15];
353
354 timerclk = clk_get(NULL, "timers");
355 if (IS_ERR(timerclk))
356 panic("failed to get timers clock for timer");
357
358 clk_enable(timerclk);
359
360 sprintf(devname, "s3c24xx-pwm.%lu", event_id);
361 s3c_device_timer[event_id].id = event_id;
362 s3c_device_timer[event_id].dev.init_name = devname;
363
364 tin_event = clk_get(&s3c_device_timer[event_id].dev, "pwm-tin");
365 if (IS_ERR(tin_event))
366 panic("failed to get pwm-tin clock for event timer");
367
368 tdiv_event = clk_get(&s3c_device_timer[event_id].dev, "pwm-tdiv");
369 if (IS_ERR(tdiv_event))
370 panic("failed to get pwm-tdiv clock for event timer");
371
372 clk_enable(tin_event);
373
374 sprintf(devname, "s3c24xx-pwm.%lu", source_id);
375 s3c_device_timer[source_id].id = source_id;
376 s3c_device_timer[source_id].dev.init_name = devname;
377
378 tin_source = clk_get(&s3c_device_timer[source_id].dev, "pwm-tin");
379 if (IS_ERR(tin_source))
380 panic("failed to get pwm-tin clock for source timer");
381
382 tdiv_source = clk_get(&s3c_device_timer[source_id].dev, "pwm-tdiv");
383 if (IS_ERR(tdiv_source))
384 panic("failed to get pwm-tdiv clock for source timer");
385
386 clk_enable(tin_source);
387}
388
389void __init samsung_timer_init(void)
390{
391 samsung_timer_resources();
392 samsung_clockevent_init();
393 samsung_clocksource_init();
394}