diff options
-rw-r--r-- | arch/arm/mach-omap2/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/timer-gp.c | 86 | ||||
-rw-r--r-- | arch/arm/plat-omap/Kconfig | 2 | ||||
-rw-r--r-- | arch/arm/plat-omap/dmtimer.c | 413 | ||||
-rw-r--r-- | arch/arm/plat-omap/timer32k.c | 121 | ||||
-rw-r--r-- | include/asm-arm/arch-omap/dmtimer.h | 79 | ||||
-rw-r--r-- | include/asm-arm/arch-omap/irqs.h | 12 |
7 files changed, 412 insertions, 302 deletions
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 537dd2e6d380..aab97ccf1e63 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig | |||
@@ -8,6 +8,7 @@ config ARCH_OMAP24XX | |||
8 | config ARCH_OMAP2420 | 8 | config ARCH_OMAP2420 |
9 | bool "OMAP2420 support" | 9 | bool "OMAP2420 support" |
10 | depends on ARCH_OMAP24XX | 10 | depends on ARCH_OMAP24XX |
11 | select OMAP_DM_TIMER | ||
11 | 12 | ||
12 | comment "OMAP Board Type" | 13 | comment "OMAP Board Type" |
13 | depends on ARCH_OMAP2 | 14 | depends on ARCH_OMAP2 |
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c index 1d2f5ac2f69b..3358c0d47b1a 100644 --- a/arch/arm/mach-omap2/timer-gp.c +++ b/arch/arm/mach-omap2/timer-gp.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * Copyright (C) 2005 Nokia Corporation | 6 | * Copyright (C) 2005 Nokia Corporation |
7 | * Author: Paul Mundt <paul.mundt@nokia.com> | 7 | * Author: Paul Mundt <paul.mundt@nokia.com> |
8 | * Juha Yrjölä <juha.yrjola@nokia.com> | 8 | * Juha Yrjölä <juha.yrjola@nokia.com> |
9 | * OMAP Dual-mode timer framework support by Timo Teras | ||
9 | * | 10 | * |
10 | * Some parts based off of TI's 24xx code: | 11 | * Some parts based off of TI's 24xx code: |
11 | * | 12 | * |
@@ -22,54 +23,18 @@ | |||
22 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
23 | #include <linux/err.h> | 24 | #include <linux/err.h> |
24 | #include <linux/clk.h> | 25 | #include <linux/clk.h> |
26 | #include <linux/delay.h> | ||
25 | 27 | ||
26 | #include <asm/mach/time.h> | 28 | #include <asm/mach/time.h> |
27 | #include <asm/delay.h> | 29 | #include <asm/arch/dmtimer.h> |
28 | #include <asm/io.h> | ||
29 | 30 | ||
30 | #define OMAP2_GP_TIMER1_BASE 0x48028000 | 31 | static struct omap_dm_timer *gptimer; |
31 | #define OMAP2_GP_TIMER2_BASE 0x4802a000 | ||
32 | #define OMAP2_GP_TIMER3_BASE 0x48078000 | ||
33 | #define OMAP2_GP_TIMER4_BASE 0x4807a000 | ||
34 | 32 | ||
35 | #define GP_TIMER_TIDR 0x00 | 33 | static inline void omap2_gp_timer_start(unsigned long load_val) |
36 | #define GP_TIMER_TISR 0x18 | ||
37 | #define GP_TIMER_TIER 0x1c | ||
38 | #define GP_TIMER_TCLR 0x24 | ||
39 | #define GP_TIMER_TCRR 0x28 | ||
40 | #define GP_TIMER_TLDR 0x2c | ||
41 | #define GP_TIMER_TSICR 0x40 | ||
42 | |||
43 | #define OS_TIMER_NR 1 /* GP timer 2 */ | ||
44 | |||
45 | static unsigned long timer_base[] = { | ||
46 | IO_ADDRESS(OMAP2_GP_TIMER1_BASE), | ||
47 | IO_ADDRESS(OMAP2_GP_TIMER2_BASE), | ||
48 | IO_ADDRESS(OMAP2_GP_TIMER3_BASE), | ||
49 | IO_ADDRESS(OMAP2_GP_TIMER4_BASE), | ||
50 | }; | ||
51 | |||
52 | static inline unsigned int timer_read_reg(int nr, unsigned int reg) | ||
53 | { | ||
54 | return __raw_readl(timer_base[nr] + reg); | ||
55 | } | ||
56 | |||
57 | static inline void timer_write_reg(int nr, unsigned int reg, unsigned int val) | ||
58 | { | ||
59 | __raw_writel(val, timer_base[nr] + reg); | ||
60 | } | ||
61 | |||
62 | /* Note that we always enable the clock prescale divider bit */ | ||
63 | static inline void omap2_gp_timer_start(int nr, unsigned long load_val) | ||
64 | { | 34 | { |
65 | unsigned int tmp; | 35 | omap_dm_timer_set_load(gptimer, 1, 0xffffffff - load_val); |
66 | 36 | omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW); | |
67 | tmp = 0xffffffff - load_val; | 37 | omap_dm_timer_start(gptimer); |
68 | |||
69 | timer_write_reg(nr, GP_TIMER_TLDR, tmp); | ||
70 | timer_write_reg(nr, GP_TIMER_TCRR, tmp); | ||
71 | timer_write_reg(nr, GP_TIMER_TIER, 1 << 1); | ||
72 | timer_write_reg(nr, GP_TIMER_TCLR, (1 << 5) | (1 << 1) | 1); | ||
73 | } | 38 | } |
74 | 39 | ||
75 | static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id, | 40 | static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id, |
@@ -77,7 +42,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id, | |||
77 | { | 42 | { |
78 | write_seqlock(&xtime_lock); | 43 | write_seqlock(&xtime_lock); |
79 | 44 | ||
80 | timer_write_reg(OS_TIMER_NR, GP_TIMER_TISR, 1 << 1); | 45 | omap_dm_timer_write_status(gptimer, OMAP_TIMER_INT_OVERFLOW); |
81 | timer_tick(regs); | 46 | timer_tick(regs); |
82 | 47 | ||
83 | write_sequnlock(&xtime_lock); | 48 | write_sequnlock(&xtime_lock); |
@@ -87,41 +52,26 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id, | |||
87 | 52 | ||
88 | static struct irqaction omap2_gp_timer_irq = { | 53 | static struct irqaction omap2_gp_timer_irq = { |
89 | .name = "gp timer", | 54 | .name = "gp timer", |
90 | .flags = SA_INTERRUPT, | 55 | .flags = SA_INTERRUPT | SA_TIMER, |
91 | .handler = omap2_gp_timer_interrupt, | 56 | .handler = omap2_gp_timer_interrupt, |
92 | }; | 57 | }; |
93 | 58 | ||
94 | static void __init omap2_gp_timer_init(void) | 59 | static void __init omap2_gp_timer_init(void) |
95 | { | 60 | { |
96 | struct clk * sys_ck; | 61 | u32 tick_period; |
97 | u32 tick_period = 120000; | ||
98 | u32 l; | ||
99 | 62 | ||
100 | /* Reset clock and prescale value */ | 63 | omap_dm_timer_init(); |
101 | timer_write_reg(OS_TIMER_NR, GP_TIMER_TCLR, 0); | 64 | gptimer = omap_dm_timer_request_specific(2); |
65 | BUG_ON(gptimer == NULL); | ||
102 | 66 | ||
103 | sys_ck = clk_get(NULL, "sys_ck"); | 67 | omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_SYS_CLK); |
104 | if (IS_ERR(sys_ck)) | 68 | tick_period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / 100; |
105 | printk(KERN_ERR "Could not get sys_ck\n"); | ||
106 | else { | ||
107 | clk_enable(sys_ck); | ||
108 | tick_period = clk_get_rate(sys_ck) / 100; | ||
109 | clk_put(sys_ck); | ||
110 | } | ||
111 | |||
112 | tick_period /= 2; /* Minimum prescale divider is 2 */ | ||
113 | tick_period -= 1; | 69 | tick_period -= 1; |
114 | 70 | ||
115 | l = timer_read_reg(OS_TIMER_NR, GP_TIMER_TIDR); | 71 | setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq); |
116 | printk(KERN_INFO "OMAP2 GP timer (HW version %d.%d)\n", | 72 | omap2_gp_timer_start(tick_period); |
117 | (l >> 4) & 0x0f, l & 0x0f); | ||
118 | |||
119 | setup_irq(38, &omap2_gp_timer_irq); | ||
120 | |||
121 | omap2_gp_timer_start(OS_TIMER_NR, tick_period); | ||
122 | } | 73 | } |
123 | 74 | ||
124 | struct sys_timer omap_timer = { | 75 | struct sys_timer omap_timer = { |
125 | .init = omap2_gp_timer_init, | 76 | .init = omap2_gp_timer_init, |
126 | }; | 77 | }; |
127 | |||
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index ec49495e651e..ec752e16d618 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig | |||
@@ -91,7 +91,7 @@ config OMAP_32K_TIMER_HZ | |||
91 | 91 | ||
92 | config OMAP_DM_TIMER | 92 | config OMAP_DM_TIMER |
93 | bool "Use dual-mode timer" | 93 | bool "Use dual-mode timer" |
94 | depends on ARCH_OMAP16XX | 94 | depends on ARCH_OMAP16XX || ARCH_OMAP24XX |
95 | help | 95 | help |
96 | Select this option if you want to use OMAP Dual-Mode timers. | 96 | Select this option if you want to use OMAP Dual-Mode timers. |
97 | 97 | ||
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index eba3cb52ad87..c25a1a6d2b03 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c | |||
@@ -4,7 +4,8 @@ | |||
4 | * OMAP Dual-Mode Timers | 4 | * OMAP Dual-Mode Timers |
5 | * | 5 | * |
6 | * Copyright (C) 2005 Nokia Corporation | 6 | * Copyright (C) 2005 Nokia Corporation |
7 | * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com> | 7 | * OMAP2 support by Juha Yrjola |
8 | * API improvements and OMAP2 clock framework support by Timo Teras | ||
8 | * | 9 | * |
9 | * This program is free software; you can redistribute it and/or modify it | 10 | * This program is free software; you can redistribute it and/or modify it |
10 | * under the terms of the GNU General Public License as published by the | 11 | * under the terms of the GNU General Public License as published by the |
@@ -26,15 +27,17 @@ | |||
26 | */ | 27 | */ |
27 | 28 | ||
28 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/errno.h> | ||
32 | #include <linux/list.h> | ||
33 | #include <linux/clk.h> | ||
34 | #include <linux/delay.h> | ||
29 | #include <asm/hardware.h> | 35 | #include <asm/hardware.h> |
30 | #include <asm/arch/dmtimer.h> | 36 | #include <asm/arch/dmtimer.h> |
31 | #include <asm/io.h> | 37 | #include <asm/io.h> |
32 | #include <asm/arch/irqs.h> | 38 | #include <asm/arch/irqs.h> |
33 | #include <linux/spinlock.h> | ||
34 | #include <linux/list.h> | ||
35 | |||
36 | #define OMAP_TIMER_COUNT 8 | ||
37 | 39 | ||
40 | /* register offsets */ | ||
38 | #define OMAP_TIMER_ID_REG 0x00 | 41 | #define OMAP_TIMER_ID_REG 0x00 |
39 | #define OMAP_TIMER_OCP_CFG_REG 0x10 | 42 | #define OMAP_TIMER_OCP_CFG_REG 0x10 |
40 | #define OMAP_TIMER_SYS_STAT_REG 0x14 | 43 | #define OMAP_TIMER_SYS_STAT_REG 0x14 |
@@ -50,52 +53,184 @@ | |||
50 | #define OMAP_TIMER_CAPTURE_REG 0x3c | 53 | #define OMAP_TIMER_CAPTURE_REG 0x3c |
51 | #define OMAP_TIMER_IF_CTRL_REG 0x40 | 54 | #define OMAP_TIMER_IF_CTRL_REG 0x40 |
52 | 55 | ||
56 | /* timer control reg bits */ | ||
57 | #define OMAP_TIMER_CTRL_GPOCFG (1 << 14) | ||
58 | #define OMAP_TIMER_CTRL_CAPTMODE (1 << 13) | ||
59 | #define OMAP_TIMER_CTRL_PT (1 << 12) | ||
60 | #define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8) | ||
61 | #define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8) | ||
62 | #define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8) | ||
63 | #define OMAP_TIMER_CTRL_SCPWM (1 << 7) | ||
64 | #define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */ | ||
65 | #define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */ | ||
66 | #define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* how much to shift the prescaler value */ | ||
67 | #define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */ | ||
68 | #define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */ | ||
69 | |||
70 | struct omap_dm_timer { | ||
71 | unsigned long phys_base; | ||
72 | int irq; | ||
73 | #ifdef CONFIG_ARCH_OMAP2 | ||
74 | struct clk *iclk, *fclk; | ||
75 | #endif | ||
76 | void __iomem *io_base; | ||
77 | unsigned reserved:1; | ||
78 | }; | ||
79 | |||
80 | #ifdef CONFIG_ARCH_OMAP1 | ||
81 | |||
82 | static struct omap_dm_timer dm_timers[] = { | ||
83 | { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 }, | ||
84 | { .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 }, | ||
85 | { .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 }, | ||
86 | { .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 }, | ||
87 | { .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 }, | ||
88 | { .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 }, | ||
89 | { .phys_base = 0xfffb4400, .irq = INT_1610_GPTIMER7 }, | ||
90 | { .phys_base = 0xfffb4c00, .irq = INT_1610_GPTIMER8 }, | ||
91 | }; | ||
53 | 92 | ||
54 | static struct dmtimer_info_struct { | 93 | #elif defined(CONFIG_ARCH_OMAP2) |
55 | struct list_head unused_timers; | ||
56 | struct list_head reserved_timers; | ||
57 | } dm_timer_info; | ||
58 | 94 | ||
59 | static struct omap_dm_timer dm_timers[] = { | 95 | static struct omap_dm_timer dm_timers[] = { |
60 | { .base=0xfffb1400, .irq=INT_1610_GPTIMER1 }, | 96 | { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 }, |
61 | { .base=0xfffb1c00, .irq=INT_1610_GPTIMER2 }, | 97 | { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 }, |
62 | { .base=0xfffb2400, .irq=INT_1610_GPTIMER3 }, | 98 | { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 }, |
63 | { .base=0xfffb2c00, .irq=INT_1610_GPTIMER4 }, | 99 | { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 }, |
64 | { .base=0xfffb3400, .irq=INT_1610_GPTIMER5 }, | 100 | { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 }, |
65 | { .base=0xfffb3c00, .irq=INT_1610_GPTIMER6 }, | 101 | { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 }, |
66 | { .base=0xfffb4400, .irq=INT_1610_GPTIMER7 }, | 102 | { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 }, |
67 | { .base=0xfffb4c00, .irq=INT_1610_GPTIMER8 }, | 103 | { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 }, |
68 | { .base=0x0 }, | 104 | { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 }, |
105 | { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 }, | ||
106 | { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 }, | ||
107 | { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 }, | ||
69 | }; | 108 | }; |
70 | 109 | ||
110 | #else | ||
111 | |||
112 | #error OMAP architecture not supported! | ||
113 | |||
114 | #endif | ||
115 | |||
116 | static const int dm_timer_count = ARRAY_SIZE(dm_timers); | ||
71 | 117 | ||
72 | static spinlock_t dm_timer_lock; | 118 | static spinlock_t dm_timer_lock; |
73 | 119 | ||
120 | static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) | ||
121 | { | ||
122 | return readl(timer->io_base + reg); | ||
123 | } | ||
74 | 124 | ||
75 | inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) | 125 | static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) |
76 | { | 126 | { |
77 | omap_writel(value, timer->base + reg); | 127 | writel(value, timer->io_base + reg); |
78 | while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG)) | 128 | while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG)) |
79 | ; | 129 | ; |
80 | } | 130 | } |
81 | 131 | ||
82 | u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) | 132 | static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) |
83 | { | 133 | { |
84 | return omap_readl(timer->base + reg); | 134 | int c; |
135 | |||
136 | c = 0; | ||
137 | while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) { | ||
138 | c++; | ||
139 | if (c > 100000) { | ||
140 | printk(KERN_ERR "Timer failed to reset\n"); | ||
141 | return; | ||
142 | } | ||
143 | } | ||
85 | } | 144 | } |
86 | 145 | ||
87 | int omap_dm_timers_active(void) | 146 | static void omap_dm_timer_reset(struct omap_dm_timer *timer) |
147 | { | ||
148 | u32 l; | ||
149 | |||
150 | omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); | ||
151 | omap_dm_timer_wait_for_reset(timer); | ||
152 | |||
153 | omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_SYS_CLK); | ||
154 | |||
155 | /* Set to smart-idle mode */ | ||
156 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG); | ||
157 | l |= 0x02 << 3; | ||
158 | omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l); | ||
159 | } | ||
160 | |||
161 | static void omap_dm_timer_reserve(struct omap_dm_timer *timer) | ||
162 | { | ||
163 | timer->reserved = 1; | ||
164 | #ifdef CONFIG_ARCH_OMAP2 | ||
165 | clk_enable(timer->iclk); | ||
166 | clk_enable(timer->fclk); | ||
167 | #endif | ||
168 | omap_dm_timer_reset(timer); | ||
169 | } | ||
170 | |||
171 | struct omap_dm_timer *omap_dm_timer_request(void) | ||
172 | { | ||
173 | struct omap_dm_timer *timer = NULL; | ||
174 | unsigned long flags; | ||
175 | int i; | ||
176 | |||
177 | spin_lock_irqsave(&dm_timer_lock, flags); | ||
178 | for (i = 0; i < dm_timer_count; i++) { | ||
179 | if (dm_timers[i].reserved) | ||
180 | continue; | ||
181 | |||
182 | timer = &dm_timers[i]; | ||
183 | omap_dm_timer_reserve(timer); | ||
184 | break; | ||
185 | } | ||
186 | spin_unlock_irqrestore(&dm_timer_lock, flags); | ||
187 | |||
188 | return timer; | ||
189 | } | ||
190 | |||
191 | struct omap_dm_timer *omap_dm_timer_request_specific(int id) | ||
88 | { | 192 | { |
89 | struct omap_dm_timer *timer; | 193 | struct omap_dm_timer *timer; |
194 | unsigned long flags; | ||
90 | 195 | ||
91 | for (timer = &dm_timers[0]; timer->base; ++timer) | 196 | spin_lock_irqsave(&dm_timer_lock, flags); |
92 | if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & | 197 | if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) { |
93 | OMAP_TIMER_CTRL_ST) | 198 | spin_unlock_irqrestore(&dm_timer_lock, flags); |
94 | return 1; | 199 | printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n", |
200 | __FILE__, __LINE__, __FUNCTION__, id); | ||
201 | dump_stack(); | ||
202 | return NULL; | ||
203 | } | ||
95 | 204 | ||
96 | return 0; | 205 | timer = &dm_timers[id-1]; |
206 | omap_dm_timer_reserve(timer); | ||
207 | spin_unlock_irqrestore(&dm_timer_lock, flags); | ||
208 | |||
209 | return timer; | ||
97 | } | 210 | } |
98 | 211 | ||
212 | void omap_dm_timer_free(struct omap_dm_timer *timer) | ||
213 | { | ||
214 | omap_dm_timer_reset(timer); | ||
215 | #ifdef CONFIG_ARCH_OMAP2 | ||
216 | clk_disable(timer->iclk); | ||
217 | clk_disable(timer->fclk); | ||
218 | #endif | ||
219 | WARN_ON(!timer->reserved); | ||
220 | timer->reserved = 0; | ||
221 | } | ||
222 | |||
223 | int omap_dm_timer_get_irq(struct omap_dm_timer *timer) | ||
224 | { | ||
225 | return timer->irq; | ||
226 | } | ||
227 | |||
228 | #if defined(CONFIG_ARCH_OMAP1) | ||
229 | |||
230 | struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) | ||
231 | { | ||
232 | BUG(); | ||
233 | } | ||
99 | 234 | ||
100 | /** | 235 | /** |
101 | * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR | 236 | * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR |
@@ -103,184 +238,226 @@ int omap_dm_timers_active(void) | |||
103 | */ | 238 | */ |
104 | __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) | 239 | __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) |
105 | { | 240 | { |
106 | int n; | 241 | int i; |
107 | 242 | ||
108 | /* If ARMXOR cannot be idled this function call is unnecessary */ | 243 | /* If ARMXOR cannot be idled this function call is unnecessary */ |
109 | if (!(inputmask & (1 << 1))) | 244 | if (!(inputmask & (1 << 1))) |
110 | return inputmask; | 245 | return inputmask; |
111 | 246 | ||
112 | /* If any active timer is using ARMXOR return modified mask */ | 247 | /* If any active timer is using ARMXOR return modified mask */ |
113 | for (n = 0; dm_timers[n].base; ++n) | 248 | for (i = 0; i < dm_timer_count; i++) { |
114 | if (omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG)& | 249 | u32 l; |
115 | OMAP_TIMER_CTRL_ST) { | 250 | |
116 | if (((omap_readl(MOD_CONF_CTRL_1)>>(n*2)) & 0x03) == 0) | 251 | l = omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG); |
252 | if (l & OMAP_TIMER_CTRL_ST) { | ||
253 | if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0) | ||
117 | inputmask &= ~(1 << 1); | 254 | inputmask &= ~(1 << 1); |
118 | else | 255 | else |
119 | inputmask &= ~(1 << 2); | 256 | inputmask &= ~(1 << 2); |
120 | } | 257 | } |
258 | } | ||
121 | 259 | ||
122 | return inputmask; | 260 | return inputmask; |
123 | } | 261 | } |
124 | 262 | ||
263 | #elif defined(CONFIG_ARCH_OMAP2) | ||
125 | 264 | ||
126 | void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) | 265 | struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) |
127 | { | 266 | { |
128 | int n = (timer - dm_timers) << 1; | 267 | return timer->fclk; |
129 | u32 l; | 268 | } |
130 | 269 | ||
131 | l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n); | 270 | __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) |
132 | l |= source << n; | 271 | { |
133 | omap_writel(l, MOD_CONF_CTRL_1); | 272 | BUG(); |
134 | } | 273 | } |
135 | 274 | ||
275 | #endif | ||
136 | 276 | ||
137 | static void omap_dm_timer_reset(struct omap_dm_timer *timer) | 277 | void omap_dm_timer_trigger(struct omap_dm_timer *timer) |
138 | { | 278 | { |
139 | /* Reset and set posted mode */ | 279 | omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); |
140 | omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); | ||
141 | omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, 0x02); | ||
142 | |||
143 | omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR); | ||
144 | } | 280 | } |
145 | 281 | ||
282 | void omap_dm_timer_start(struct omap_dm_timer *timer) | ||
283 | { | ||
284 | u32 l; | ||
146 | 285 | ||
286 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | ||
287 | if (!(l & OMAP_TIMER_CTRL_ST)) { | ||
288 | l |= OMAP_TIMER_CTRL_ST; | ||
289 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | ||
290 | } | ||
291 | } | ||
147 | 292 | ||
148 | struct omap_dm_timer * omap_dm_timer_request(void) | 293 | void omap_dm_timer_stop(struct omap_dm_timer *timer) |
149 | { | 294 | { |
150 | struct omap_dm_timer *timer = NULL; | 295 | u32 l; |
151 | unsigned long flags; | ||
152 | 296 | ||
153 | spin_lock_irqsave(&dm_timer_lock, flags); | 297 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
154 | if (!list_empty(&dm_timer_info.unused_timers)) { | 298 | if (l & OMAP_TIMER_CTRL_ST) { |
155 | timer = (struct omap_dm_timer *) | 299 | l &= ~0x1; |
156 | dm_timer_info.unused_timers.next; | 300 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
157 | list_move_tail((struct list_head *)timer, | ||
158 | &dm_timer_info.reserved_timers); | ||
159 | } | 301 | } |
160 | spin_unlock_irqrestore(&dm_timer_lock, flags); | ||
161 | |||
162 | return timer; | ||
163 | } | 302 | } |
164 | 303 | ||
304 | #ifdef CONFIG_ARCH_OMAP1 | ||
165 | 305 | ||
166 | void omap_dm_timer_free(struct omap_dm_timer *timer) | 306 | void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) |
167 | { | 307 | { |
168 | unsigned long flags; | 308 | int n = (timer - dm_timers) << 1; |
169 | 309 | u32 l; | |
170 | omap_dm_timer_reset(timer); | ||
171 | 310 | ||
172 | spin_lock_irqsave(&dm_timer_lock, flags); | 311 | l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n); |
173 | list_move_tail((struct list_head *)timer, &dm_timer_info.unused_timers); | 312 | l |= source << n; |
174 | spin_unlock_irqrestore(&dm_timer_lock, flags); | 313 | omap_writel(l, MOD_CONF_CTRL_1); |
175 | } | 314 | } |
176 | 315 | ||
177 | void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, | 316 | #else |
178 | unsigned int value) | ||
179 | { | ||
180 | omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); | ||
181 | } | ||
182 | 317 | ||
183 | unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) | 318 | void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) |
184 | { | 319 | { |
185 | return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); | 320 | static const char *source_timers[] = { |
321 | "sys_ck", | ||
322 | "func_32k_ck", | ||
323 | "alt_ck" | ||
324 | }; | ||
325 | struct clk *parent; | ||
326 | |||
327 | if (source < 0 || source >= 3) | ||
328 | return; | ||
329 | |||
330 | parent = clk_get(NULL, source_timers[source]); | ||
331 | clk_disable(timer->fclk); | ||
332 | clk_set_parent(timer->fclk, parent); | ||
333 | clk_enable(timer->fclk); | ||
334 | clk_put(parent); | ||
335 | |||
336 | /* When the functional clock disappears, too quick writes seem to | ||
337 | * cause an abort. */ | ||
338 | udelay(50); | ||
186 | } | 339 | } |
187 | 340 | ||
188 | void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) | 341 | #endif |
189 | { | ||
190 | omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); | ||
191 | } | ||
192 | 342 | ||
193 | void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer) | 343 | void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, |
344 | unsigned int load) | ||
194 | { | 345 | { |
195 | u32 l; | 346 | u32 l; |
347 | |||
196 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 348 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
197 | l |= OMAP_TIMER_CTRL_AR; | 349 | if (autoreload) |
350 | l |= OMAP_TIMER_CTRL_AR; | ||
351 | else | ||
352 | l &= ~OMAP_TIMER_CTRL_AR; | ||
198 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | 353 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
354 | omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); | ||
355 | omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); | ||
199 | } | 356 | } |
200 | 357 | ||
201 | void omap_dm_timer_trigger(struct omap_dm_timer *timer) | 358 | void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, |
202 | { | 359 | unsigned int match) |
203 | omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1); | ||
204 | } | ||
205 | |||
206 | void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value) | ||
207 | { | 360 | { |
208 | u32 l; | 361 | u32 l; |
209 | 362 | ||
210 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 363 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
211 | l |= value & 0x3; | 364 | if (enable) |
365 | l |= OMAP_TIMER_CTRL_CE; | ||
366 | else | ||
367 | l &= ~OMAP_TIMER_CTRL_CE; | ||
212 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | 368 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
369 | omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); | ||
213 | } | 370 | } |
214 | 371 | ||
215 | void omap_dm_timer_start(struct omap_dm_timer *timer) | 372 | |
373 | void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, | ||
374 | int toggle, int trigger) | ||
216 | { | 375 | { |
217 | u32 l; | 376 | u32 l; |
218 | 377 | ||
219 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 378 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
220 | l |= OMAP_TIMER_CTRL_ST; | 379 | l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM | |
380 | OMAP_TIMER_CTRL_PT | (0x03 << 10)); | ||
381 | if (def_on) | ||
382 | l |= OMAP_TIMER_CTRL_SCPWM; | ||
383 | if (toggle) | ||
384 | l |= OMAP_TIMER_CTRL_PT; | ||
385 | l |= trigger << 10; | ||
221 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | 386 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
222 | } | 387 | } |
223 | 388 | ||
224 | void omap_dm_timer_stop(struct omap_dm_timer *timer) | 389 | void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler) |
225 | { | 390 | { |
226 | u32 l; | 391 | u32 l; |
227 | 392 | ||
228 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 393 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
229 | l &= ~0x1; | 394 | l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2)); |
395 | if (prescaler >= 0x00 && prescaler <= 0x07) { | ||
396 | l |= OMAP_TIMER_CTRL_PRE; | ||
397 | l |= prescaler << 2; | ||
398 | } | ||
230 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | 399 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
231 | } | 400 | } |
232 | 401 | ||
233 | unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) | 402 | void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, |
403 | unsigned int value) | ||
234 | { | 404 | { |
235 | return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); | 405 | omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); |
236 | } | 406 | } |
237 | 407 | ||
238 | void omap_dm_timer_reset_counter(struct omap_dm_timer *timer) | 408 | unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) |
239 | { | 409 | { |
240 | omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0); | 410 | return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); |
241 | } | 411 | } |
242 | 412 | ||
243 | void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load) | 413 | void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) |
244 | { | 414 | { |
245 | omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); | 415 | omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); |
246 | } | 416 | } |
247 | 417 | ||
248 | void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match) | 418 | unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) |
249 | { | 419 | { |
250 | omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); | 420 | return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); |
251 | } | 421 | } |
252 | 422 | ||
253 | void omap_dm_timer_enable_compare(struct omap_dm_timer *timer) | 423 | int omap_dm_timers_active(void) |
254 | { | 424 | { |
255 | u32 l; | 425 | int i; |
256 | 426 | ||
257 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 427 | for (i = 0; i < dm_timer_count; i++) { |
258 | l |= OMAP_TIMER_CTRL_CE; | 428 | struct omap_dm_timer *timer; |
259 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | ||
260 | } | ||
261 | 429 | ||
430 | timer = &dm_timers[i]; | ||
431 | if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & | ||
432 | OMAP_TIMER_CTRL_ST) | ||
433 | return 1; | ||
434 | } | ||
435 | return 0; | ||
436 | } | ||
262 | 437 | ||
263 | static inline void __dm_timer_init(void) | 438 | int omap_dm_timer_init(void) |
264 | { | 439 | { |
265 | struct omap_dm_timer *timer; | 440 | struct omap_dm_timer *timer; |
441 | int i; | ||
442 | |||
443 | if (!(cpu_is_omap16xx() || cpu_is_omap24xx())) | ||
444 | return -ENODEV; | ||
266 | 445 | ||
267 | spin_lock_init(&dm_timer_lock); | 446 | spin_lock_init(&dm_timer_lock); |
268 | INIT_LIST_HEAD(&dm_timer_info.unused_timers); | 447 | for (i = 0; i < dm_timer_count; i++) { |
269 | INIT_LIST_HEAD(&dm_timer_info.reserved_timers); | 448 | #ifdef CONFIG_ARCH_OMAP2 |
270 | 449 | char clk_name[16]; | |
271 | timer = &dm_timers[0]; | 450 | #endif |
272 | while (timer->base) { | 451 | |
273 | list_add_tail((struct list_head *)timer, &dm_timer_info.unused_timers); | 452 | timer = &dm_timers[i]; |
274 | omap_dm_timer_reset(timer); | 453 | timer->io_base = (void __iomem *) io_p2v(timer->phys_base); |
275 | timer++; | 454 | #ifdef CONFIG_ARCH_OMAP2 |
455 | sprintf(clk_name, "gpt%d_ick", i + 1); | ||
456 | timer->iclk = clk_get(NULL, clk_name); | ||
457 | sprintf(clk_name, "gpt%d_fck", i + 1); | ||
458 | timer->fclk = clk_get(NULL, clk_name); | ||
459 | #endif | ||
276 | } | 460 | } |
277 | } | ||
278 | 461 | ||
279 | static int __init omap_dm_timer_init(void) | ||
280 | { | ||
281 | if (cpu_is_omap16xx()) | ||
282 | __dm_timer_init(); | ||
283 | return 0; | 462 | return 0; |
284 | } | 463 | } |
285 | |||
286 | arch_initcall(omap_dm_timer_init); | ||
diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c index 3461a6c9665c..f028e182215a 100644 --- a/arch/arm/plat-omap/timer32k.c +++ b/arch/arm/plat-omap/timer32k.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * Partial timer rewrite and additional dynamic tick timer support by | 7 | * Partial timer rewrite and additional dynamic tick timer support by |
8 | * Tony Lindgen <tony@atomide.com> and | 8 | * Tony Lindgen <tony@atomide.com> and |
9 | * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | 9 | * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> |
10 | * OMAP Dual-mode timer framework support by Timo Teras | ||
10 | * | 11 | * |
11 | * MPU timer code based on the older MPU timer code for OMAP | 12 | * MPU timer code based on the older MPU timer code for OMAP |
12 | * Copyright (C) 2000 RidgeRun, Inc. | 13 | * Copyright (C) 2000 RidgeRun, Inc. |
@@ -79,18 +80,6 @@ struct sys_timer omap_timer; | |||
79 | #define OMAP1_32K_TIMER_TVR 0x00 | 80 | #define OMAP1_32K_TIMER_TVR 0x00 |
80 | #define OMAP1_32K_TIMER_TCR 0x04 | 81 | #define OMAP1_32K_TIMER_TCR 0x04 |
81 | 82 | ||
82 | /* 24xx specific defines */ | ||
83 | #define OMAP2_GP_TIMER_BASE 0x48028000 | ||
84 | #define CM_CLKSEL_WKUP 0x48008440 | ||
85 | #define GP_TIMER_TIDR 0x00 | ||
86 | #define GP_TIMER_TISR 0x18 | ||
87 | #define GP_TIMER_TIER 0x1c | ||
88 | #define GP_TIMER_TCLR 0x24 | ||
89 | #define GP_TIMER_TCRR 0x28 | ||
90 | #define GP_TIMER_TLDR 0x2c | ||
91 | #define GP_TIMER_TTGR 0x30 | ||
92 | #define GP_TIMER_TSICR 0x40 | ||
93 | |||
94 | #define OMAP_32K_TICKS_PER_HZ (32768 / HZ) | 83 | #define OMAP_32K_TICKS_PER_HZ (32768 / HZ) |
95 | 84 | ||
96 | /* | 85 | /* |
@@ -102,54 +91,64 @@ struct sys_timer omap_timer; | |||
102 | #define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ | 91 | #define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ |
103 | (((nr_jiffies) * (clock_rate)) / HZ) | 92 | (((nr_jiffies) * (clock_rate)) / HZ) |
104 | 93 | ||
94 | #if defined(CONFIG_ARCH_OMAP1) | ||
95 | |||
105 | static inline void omap_32k_timer_write(int val, int reg) | 96 | static inline void omap_32k_timer_write(int val, int reg) |
106 | { | 97 | { |
107 | if (cpu_class_is_omap1()) | 98 | omap_writew(val, OMAP1_32K_TIMER_BASE + reg); |
108 | omap_writew(val, OMAP1_32K_TIMER_BASE + reg); | ||
109 | |||
110 | if (cpu_is_omap24xx()) | ||
111 | omap_writel(val, OMAP2_GP_TIMER_BASE + reg); | ||
112 | } | 99 | } |
113 | 100 | ||
114 | static inline unsigned long omap_32k_timer_read(int reg) | 101 | static inline unsigned long omap_32k_timer_read(int reg) |
115 | { | 102 | { |
116 | if (cpu_class_is_omap1()) | 103 | return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff; |
117 | return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff; | 104 | } |
118 | 105 | ||
119 | if (cpu_is_omap24xx()) | 106 | static inline void omap_32k_timer_start(unsigned long load_val) |
120 | return omap_readl(OMAP2_GP_TIMER_BASE + reg); | 107 | { |
108 | omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR); | ||
109 | omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR); | ||
121 | } | 110 | } |
122 | 111 | ||
123 | /* | 112 | static inline void omap_32k_timer_stop(void) |
124 | * The 32KHz synchronized timer is an additional timer on 16xx. | ||
125 | * It is always running. | ||
126 | */ | ||
127 | static inline unsigned long omap_32k_sync_timer_read(void) | ||
128 | { | 113 | { |
129 | return omap_readl(TIMER_32K_SYNCHRONIZED); | 114 | omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR); |
130 | } | 115 | } |
131 | 116 | ||
117 | #define omap_32k_timer_ack_irq() | ||
118 | |||
119 | #elif defined(CONFIG_ARCH_OMAP2) | ||
120 | |||
121 | #include <asm/arch/dmtimer.h> | ||
122 | |||
123 | static struct omap_dm_timer *gptimer; | ||
124 | |||
132 | static inline void omap_32k_timer_start(unsigned long load_val) | 125 | static inline void omap_32k_timer_start(unsigned long load_val) |
133 | { | 126 | { |
134 | if (cpu_class_is_omap1()) { | 127 | omap_dm_timer_set_load(gptimer, 1, 0xffffffff - load_val); |
135 | omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR); | 128 | omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW); |
136 | omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR); | 129 | omap_dm_timer_start(gptimer); |
137 | } | ||
138 | |||
139 | if (cpu_is_omap24xx()) { | ||
140 | omap_32k_timer_write(0xffffffff - load_val, GP_TIMER_TCRR); | ||
141 | omap_32k_timer_write((1 << 1), GP_TIMER_TIER); | ||
142 | omap_32k_timer_write((1 << 1) | 1, GP_TIMER_TCLR); | ||
143 | } | ||
144 | } | 130 | } |
145 | 131 | ||
146 | static inline void omap_32k_timer_stop(void) | 132 | static inline void omap_32k_timer_stop(void) |
147 | { | 133 | { |
148 | if (cpu_class_is_omap1()) | 134 | omap_dm_timer_stop(gptimer); |
149 | omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR); | 135 | } |
150 | 136 | ||
151 | if (cpu_is_omap24xx()) | 137 | static inline void omap_32k_timer_ack_irq(void) |
152 | omap_32k_timer_write(0x0, GP_TIMER_TCLR); | 138 | { |
139 | u32 status = omap_dm_timer_read_status(gptimer); | ||
140 | omap_dm_timer_write_status(gptimer, status); | ||
141 | } | ||
142 | |||
143 | #endif | ||
144 | |||
145 | /* | ||
146 | * The 32KHz synchronized timer is an additional timer on 16xx. | ||
147 | * It is always running. | ||
148 | */ | ||
149 | static inline unsigned long omap_32k_sync_timer_read(void) | ||
150 | { | ||
151 | return omap_readl(TIMER_32K_SYNCHRONIZED); | ||
153 | } | 152 | } |
154 | 153 | ||
155 | /* | 154 | /* |
@@ -203,11 +202,7 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, | |||
203 | 202 | ||
204 | write_seqlock_irqsave(&xtime_lock, flags); | 203 | write_seqlock_irqsave(&xtime_lock, flags); |
205 | 204 | ||
206 | if (cpu_is_omap24xx()) { | 205 | omap_32k_timer_ack_irq(); |
207 | u32 status = omap_32k_timer_read(GP_TIMER_TISR); | ||
208 | omap_32k_timer_write(status, GP_TIMER_TISR); | ||
209 | } | ||
210 | |||
211 | now = omap_32k_sync_timer_read(); | 206 | now = omap_32k_sync_timer_read(); |
212 | 207 | ||
213 | while ((signed long)(now - omap_32k_last_tick) | 208 | while ((signed long)(now - omap_32k_last_tick) |
@@ -269,9 +264,6 @@ static struct irqaction omap_32k_timer_irq = { | |||
269 | .handler = omap_32k_timer_interrupt, | 264 | .handler = omap_32k_timer_interrupt, |
270 | }; | 265 | }; |
271 | 266 | ||
272 | static struct clk * gpt1_ick; | ||
273 | static struct clk * gpt1_fck; | ||
274 | |||
275 | static __init void omap_init_32k_timer(void) | 267 | static __init void omap_init_32k_timer(void) |
276 | { | 268 | { |
277 | #ifdef CONFIG_NO_IDLE_HZ | 269 | #ifdef CONFIG_NO_IDLE_HZ |
@@ -280,31 +272,19 @@ static __init void omap_init_32k_timer(void) | |||
280 | 272 | ||
281 | if (cpu_class_is_omap1()) | 273 | if (cpu_class_is_omap1()) |
282 | setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); | 274 | setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); |
283 | if (cpu_is_omap24xx()) | ||
284 | setup_irq(37, &omap_32k_timer_irq); | ||
285 | omap_timer.offset = omap_32k_timer_gettimeoffset; | 275 | omap_timer.offset = omap_32k_timer_gettimeoffset; |
286 | omap_32k_last_tick = omap_32k_sync_timer_read(); | 276 | omap_32k_last_tick = omap_32k_sync_timer_read(); |
287 | 277 | ||
288 | /* REVISIT: Check 24xx TIOCP_CFG settings after idle works */ | 278 | /* REVISIT: Check 24xx TIOCP_CFG settings after idle works */ |
289 | if (cpu_is_omap24xx()) { | 279 | if (cpu_is_omap24xx()) { |
290 | omap_32k_timer_write(0, GP_TIMER_TCLR); | 280 | gptimer = omap_dm_timer_request_specific(1); |
291 | omap_writel(0, CM_CLKSEL_WKUP); /* 32KHz clock source */ | 281 | BUG_ON(gptimer == NULL); |
292 | 282 | ||
293 | gpt1_ick = clk_get(NULL, "gpt1_ick"); | 283 | omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_32_KHZ); |
294 | if (IS_ERR(gpt1_ick)) | 284 | setup_irq(omap_dm_timer_get_irq(gptimer), &omap_32k_timer_irq); |
295 | printk(KERN_ERR "Could not get gpt1_ick\n"); | 285 | omap_dm_timer_set_int_enable(gptimer, |
296 | else | 286 | OMAP_TIMER_INT_CAPTURE | OMAP_TIMER_INT_OVERFLOW | |
297 | clk_enable(gpt1_ick); | 287 | OMAP_TIMER_INT_MATCH); |
298 | |||
299 | gpt1_fck = clk_get(NULL, "gpt1_fck"); | ||
300 | if (IS_ERR(gpt1_fck)) | ||
301 | printk(KERN_ERR "Could not get gpt1_fck\n"); | ||
302 | else | ||
303 | clk_enable(gpt1_fck); | ||
304 | |||
305 | mdelay(100); /* Wait for clocks to stabilize */ | ||
306 | |||
307 | omap_32k_timer_write(0x7, GP_TIMER_TISR); | ||
308 | } | 288 | } |
309 | 289 | ||
310 | omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); | 290 | omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); |
@@ -317,6 +297,9 @@ static __init void omap_init_32k_timer(void) | |||
317 | */ | 297 | */ |
318 | static void __init omap_timer_init(void) | 298 | static void __init omap_timer_init(void) |
319 | { | 299 | { |
300 | #ifdef CONFIG_OMAP_DM_TIMER | ||
301 | omap_dm_timer_init(); | ||
302 | #endif | ||
320 | omap_init_32k_timer(); | 303 | omap_init_32k_timer(); |
321 | } | 304 | } |
322 | 305 | ||
diff --git a/include/asm-arm/arch-omap/dmtimer.h b/include/asm-arm/arch-omap/dmtimer.h index e6522e6a3834..5b58e3d62742 100644 --- a/include/asm-arm/arch-omap/dmtimer.h +++ b/include/asm-arm/arch-omap/dmtimer.h | |||
@@ -5,6 +5,7 @@ | |||
5 | * | 5 | * |
6 | * Copyright (C) 2005 Nokia Corporation | 6 | * Copyright (C) 2005 Nokia Corporation |
7 | * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com> | 7 | * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com> |
8 | * PWM and clock framwork support by Timo Teras. | ||
8 | * | 9 | * |
9 | * This program is free software; you can redistribute it and/or modify it | 10 | * This program is free software; you can redistribute it and/or modify it |
10 | * under the terms of the GNU General Public License as published by the | 11 | * under the terms of the GNU General Public License as published by the |
@@ -25,69 +26,55 @@ | |||
25 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
26 | */ | 27 | */ |
27 | 28 | ||
28 | #ifndef __ASM_ARCH_TIMER_H | 29 | #ifndef __ASM_ARCH_DMTIMER_H |
29 | #define __ASM_ARCH_TIMER_H | 30 | #define __ASM_ARCH_DMTIMER_H |
30 | |||
31 | #include <linux/list.h> | ||
32 | |||
33 | #define OMAP_TIMER_SRC_ARMXOR 0x00 | ||
34 | #define OMAP_TIMER_SRC_32_KHZ 0x01 | ||
35 | #define OMAP_TIMER_SRC_EXT_CLK 0x02 | ||
36 | |||
37 | /* timer control reg bits */ | ||
38 | #define OMAP_TIMER_CTRL_CAPTMODE (1 << 13) | ||
39 | #define OMAP_TIMER_CTRL_PT (1 << 12) | ||
40 | #define OMAP_TIMER_CTRL_TRG_OVERFLOW (0x1 << 10) | ||
41 | #define OMAP_TIMER_CTRL_TRG_OFANDMATCH (0x2 << 10) | ||
42 | #define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8) | ||
43 | #define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8) | ||
44 | #define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8) | ||
45 | #define OMAP_TIMER_CTRL_SCPWM (1 << 7) | ||
46 | #define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */ | ||
47 | #define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */ | ||
48 | #define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* how much to shift the prescaler value */ | ||
49 | #define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */ | ||
50 | #define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */ | ||
51 | 31 | ||
52 | /* timer interrupt enable bits */ | 32 | /* clock sources */ |
53 | #define OMAP_TIMER_INT_CAPTURE (1 << 2) | 33 | #define OMAP_TIMER_SRC_SYS_CLK 0x00 |
54 | #define OMAP_TIMER_INT_OVERFLOW (1 << 1) | 34 | #define OMAP_TIMER_SRC_32_KHZ 0x01 |
55 | #define OMAP_TIMER_INT_MATCH (1 << 0) | 35 | #define OMAP_TIMER_SRC_EXT_CLK 0x02 |
56 | 36 | ||
37 | /* timer interrupt enable bits */ | ||
38 | #define OMAP_TIMER_INT_CAPTURE (1 << 2) | ||
39 | #define OMAP_TIMER_INT_OVERFLOW (1 << 1) | ||
40 | #define OMAP_TIMER_INT_MATCH (1 << 0) | ||
57 | 41 | ||
58 | struct omap_dm_timer { | 42 | /* trigger types */ |
59 | struct list_head timer_list; | 43 | #define OMAP_TIMER_TRIGGER_NONE 0x00 |
44 | #define OMAP_TIMER_TRIGGER_OVERFLOW 0x01 | ||
45 | #define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02 | ||
60 | 46 | ||
61 | u32 base; | 47 | struct omap_dm_timer; |
62 | unsigned int irq; | 48 | struct clk; |
63 | }; | ||
64 | 49 | ||
65 | u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg); | 50 | int omap_dm_timer_init(void); |
66 | void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value); | ||
67 | 51 | ||
68 | struct omap_dm_timer * omap_dm_timer_request(void); | 52 | struct omap_dm_timer *omap_dm_timer_request(void); |
53 | struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id); | ||
69 | void omap_dm_timer_free(struct omap_dm_timer *timer); | 54 | void omap_dm_timer_free(struct omap_dm_timer *timer); |
70 | void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source); | ||
71 | 55 | ||
72 | void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value); | 56 | int omap_dm_timer_get_irq(struct omap_dm_timer *timer); |
73 | void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value); | 57 | |
74 | void omap_dm_timer_enable_compare(struct omap_dm_timer *timer); | 58 | u32 omap_dm_timer_modify_idlect_mask(u32 inputmask); |
75 | void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer); | 59 | struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer); |
76 | 60 | ||
77 | void omap_dm_timer_trigger(struct omap_dm_timer *timer); | 61 | void omap_dm_timer_trigger(struct omap_dm_timer *timer); |
78 | void omap_dm_timer_start(struct omap_dm_timer *timer); | 62 | void omap_dm_timer_start(struct omap_dm_timer *timer); |
79 | void omap_dm_timer_stop(struct omap_dm_timer *timer); | 63 | void omap_dm_timer_stop(struct omap_dm_timer *timer); |
80 | 64 | ||
81 | void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load); | 65 | void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source); |
82 | void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match); | 66 | void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, unsigned int value); |
67 | void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, unsigned int match); | ||
68 | void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, int trigger); | ||
69 | void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler); | ||
70 | |||
71 | void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value); | ||
83 | 72 | ||
84 | unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer); | 73 | unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer); |
85 | void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value); | 74 | void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value); |
86 | |||
87 | unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer); | 75 | unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer); |
88 | void omap_dm_timer_reset_counter(struct omap_dm_timer *timer); | ||
89 | 76 | ||
90 | int omap_dm_timers_active(void); | 77 | int omap_dm_timers_active(void); |
91 | u32 omap_dm_timer_modify_idlect_mask(u32 inputmask); | ||
92 | 78 | ||
93 | #endif /* __ASM_ARCH_TIMER_H */ | 79 | |
80 | #endif /* __ASM_ARCH_DMTIMER_H */ | ||
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h index 42098d99f302..46f2f06eae0c 100644 --- a/include/asm-arm/arch-omap/irqs.h +++ b/include/asm-arm/arch-omap/irqs.h | |||
@@ -242,6 +242,18 @@ | |||
242 | #define INT_24XX_GPIO_BANK2 30 | 242 | #define INT_24XX_GPIO_BANK2 30 |
243 | #define INT_24XX_GPIO_BANK3 31 | 243 | #define INT_24XX_GPIO_BANK3 31 |
244 | #define INT_24XX_GPIO_BANK4 32 | 244 | #define INT_24XX_GPIO_BANK4 32 |
245 | #define INT_24XX_GPTIMER1 37 | ||
246 | #define INT_24XX_GPTIMER2 38 | ||
247 | #define INT_24XX_GPTIMER3 39 | ||
248 | #define INT_24XX_GPTIMER4 40 | ||
249 | #define INT_24XX_GPTIMER5 41 | ||
250 | #define INT_24XX_GPTIMER6 42 | ||
251 | #define INT_24XX_GPTIMER7 43 | ||
252 | #define INT_24XX_GPTIMER8 44 | ||
253 | #define INT_24XX_GPTIMER9 45 | ||
254 | #define INT_24XX_GPTIMER10 46 | ||
255 | #define INT_24XX_GPTIMER11 47 | ||
256 | #define INT_24XX_GPTIMER12 48 | ||
245 | #define INT_24XX_MCBSP1_IRQ_TX 59 | 257 | #define INT_24XX_MCBSP1_IRQ_TX 59 |
246 | #define INT_24XX_MCBSP1_IRQ_RX 60 | 258 | #define INT_24XX_MCBSP1_IRQ_RX 60 |
247 | #define INT_24XX_MCBSP2_IRQ_TX 62 | 259 | #define INT_24XX_MCBSP2_IRQ_TX 62 |