diff options
Diffstat (limited to 'arch/arm/plat-omap/dmtimer.c')
-rw-r--r-- | arch/arm/plat-omap/dmtimer.c | 713 |
1 files changed, 411 insertions, 302 deletions
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 75a847dd776a..2def4e1990ed 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c | |||
@@ -3,6 +3,12 @@ | |||
3 | * | 3 | * |
4 | * OMAP Dual-Mode Timers | 4 | * OMAP Dual-Mode Timers |
5 | * | 5 | * |
6 | * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ | ||
7 | * Tarun Kanti DebBarma <tarun.kanti@ti.com> | ||
8 | * Thara Gopinath <thara@ti.com> | ||
9 | * | ||
10 | * dmtimer adaptation to platform_driver. | ||
11 | * | ||
6 | * Copyright (C) 2005 Nokia Corporation | 12 | * Copyright (C) 2005 Nokia Corporation |
7 | * OMAP2 support by Juha Yrjola | 13 | * OMAP2 support by Juha Yrjola |
8 | * API improvements and OMAP2 clock framework support by Timo Teras | 14 | * API improvements and OMAP2 clock framework support by Timo Teras |
@@ -29,168 +35,80 @@ | |||
29 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 35 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
30 | */ | 36 | */ |
31 | 37 | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/spinlock.h> | ||
34 | #include <linux/errno.h> | ||
35 | #include <linux/list.h> | ||
36 | #include <linux/clk.h> | ||
37 | #include <linux/delay.h> | ||
38 | #include <linux/io.h> | 38 | #include <linux/io.h> |
39 | #include <linux/module.h> | 39 | #include <linux/slab.h> |
40 | #include <mach/hardware.h> | 40 | #include <linux/err.h> |
41 | #include <plat/dmtimer.h> | 41 | #include <linux/pm_runtime.h> |
42 | #include <mach/irqs.h> | ||
43 | |||
44 | static int dm_timer_count; | ||
45 | |||
46 | #ifdef CONFIG_ARCH_OMAP1 | ||
47 | static struct omap_dm_timer omap1_dm_timers[] = { | ||
48 | { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 }, | ||
49 | { .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 }, | ||
50 | { .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 }, | ||
51 | { .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 }, | ||
52 | { .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 }, | ||
53 | { .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 }, | ||
54 | { .phys_base = 0xfffb7400, .irq = INT_1610_GPTIMER7 }, | ||
55 | { .phys_base = 0xfffbd400, .irq = INT_1610_GPTIMER8 }, | ||
56 | }; | ||
57 | |||
58 | static const int omap1_dm_timer_count = ARRAY_SIZE(omap1_dm_timers); | ||
59 | |||
60 | #else | ||
61 | #define omap1_dm_timers NULL | ||
62 | #define omap1_dm_timer_count 0 | ||
63 | #endif /* CONFIG_ARCH_OMAP1 */ | ||
64 | |||
65 | #ifdef CONFIG_ARCH_OMAP2 | ||
66 | static struct omap_dm_timer omap2_dm_timers[] = { | ||
67 | { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 }, | ||
68 | { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 }, | ||
69 | { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 }, | ||
70 | { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 }, | ||
71 | { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 }, | ||
72 | { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 }, | ||
73 | { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 }, | ||
74 | { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 }, | ||
75 | { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 }, | ||
76 | { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 }, | ||
77 | { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 }, | ||
78 | { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 }, | ||
79 | }; | ||
80 | |||
81 | static const char *omap2_dm_source_names[] __initdata = { | ||
82 | "sys_ck", | ||
83 | "func_32k_ck", | ||
84 | "alt_ck", | ||
85 | NULL | ||
86 | }; | ||
87 | |||
88 | static struct clk *omap2_dm_source_clocks[3]; | ||
89 | static const int omap2_dm_timer_count = ARRAY_SIZE(omap2_dm_timers); | ||
90 | |||
91 | #else | ||
92 | #define omap2_dm_timers NULL | ||
93 | #define omap2_dm_timer_count 0 | ||
94 | #define omap2_dm_source_names NULL | ||
95 | #define omap2_dm_source_clocks NULL | ||
96 | #endif /* CONFIG_ARCH_OMAP2 */ | ||
97 | |||
98 | #ifdef CONFIG_ARCH_OMAP3 | ||
99 | static struct omap_dm_timer omap3_dm_timers[] = { | ||
100 | { .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 }, | ||
101 | { .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 }, | ||
102 | { .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 }, | ||
103 | { .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 }, | ||
104 | { .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 }, | ||
105 | { .phys_base = 0x4903A000, .irq = INT_24XX_GPTIMER6 }, | ||
106 | { .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 }, | ||
107 | { .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 }, | ||
108 | { .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 }, | ||
109 | { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 }, | ||
110 | { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 }, | ||
111 | { .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ }, | ||
112 | }; | ||
113 | |||
114 | static const char *omap3_dm_source_names[] __initdata = { | ||
115 | "sys_ck", | ||
116 | "omap_32k_fck", | ||
117 | NULL | ||
118 | }; | ||
119 | |||
120 | static struct clk *omap3_dm_source_clocks[2]; | ||
121 | static const int omap3_dm_timer_count = ARRAY_SIZE(omap3_dm_timers); | ||
122 | 42 | ||
123 | #else | 43 | #include <plat/dmtimer.h> |
124 | #define omap3_dm_timers NULL | ||
125 | #define omap3_dm_timer_count 0 | ||
126 | #define omap3_dm_source_names NULL | ||
127 | #define omap3_dm_source_clocks NULL | ||
128 | #endif /* CONFIG_ARCH_OMAP3 */ | ||
129 | |||
130 | #ifdef CONFIG_ARCH_OMAP4 | ||
131 | static struct omap_dm_timer omap4_dm_timers[] = { | ||
132 | { .phys_base = 0x4a318000, .irq = OMAP44XX_IRQ_GPT1 }, | ||
133 | { .phys_base = 0x48032000, .irq = OMAP44XX_IRQ_GPT2 }, | ||
134 | { .phys_base = 0x48034000, .irq = OMAP44XX_IRQ_GPT3 }, | ||
135 | { .phys_base = 0x48036000, .irq = OMAP44XX_IRQ_GPT4 }, | ||
136 | { .phys_base = 0x40138000, .irq = OMAP44XX_IRQ_GPT5 }, | ||
137 | { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT6 }, | ||
138 | { .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT7 }, | ||
139 | { .phys_base = 0x4013e000, .irq = OMAP44XX_IRQ_GPT8 }, | ||
140 | { .phys_base = 0x4803e000, .irq = OMAP44XX_IRQ_GPT9 }, | ||
141 | { .phys_base = 0x48086000, .irq = OMAP44XX_IRQ_GPT10 }, | ||
142 | { .phys_base = 0x48088000, .irq = OMAP44XX_IRQ_GPT11 }, | ||
143 | { .phys_base = 0x4a320000, .irq = OMAP44XX_IRQ_GPT12 }, | ||
144 | }; | ||
145 | static const char *omap4_dm_source_names[] __initdata = { | ||
146 | "sys_clkin_ck", | ||
147 | "sys_32k_ck", | ||
148 | NULL | ||
149 | }; | ||
150 | static struct clk *omap4_dm_source_clocks[2]; | ||
151 | static const int omap4_dm_timer_count = ARRAY_SIZE(omap4_dm_timers); | ||
152 | |||
153 | #else | ||
154 | #define omap4_dm_timers NULL | ||
155 | #define omap4_dm_timer_count 0 | ||
156 | #define omap4_dm_source_names NULL | ||
157 | #define omap4_dm_source_clocks NULL | ||
158 | #endif /* CONFIG_ARCH_OMAP4 */ | ||
159 | |||
160 | static struct omap_dm_timer *dm_timers; | ||
161 | static const char **dm_source_names; | ||
162 | static struct clk **dm_source_clocks; | ||
163 | 44 | ||
164 | static spinlock_t dm_timer_lock; | 45 | static LIST_HEAD(omap_timer_list); |
46 | static DEFINE_SPINLOCK(dm_timer_lock); | ||
165 | 47 | ||
166 | /* | 48 | /** |
167 | * Reads timer registers in posted and non-posted mode. The posted mode bit | 49 | * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode |
168 | * is encoded in reg. Note that in posted mode write pending bit must be | 50 | * @timer: timer pointer over which read operation to perform |
169 | * checked. Otherwise a read of a non completed write will produce an error. | 51 | * @reg: lowest byte holds the register offset |
52 | * | ||
53 | * The posted mode bit is encoded in reg. Note that in posted mode write | ||
54 | * pending bit must be checked. Otherwise a read of a non completed write | ||
55 | * will produce an error. | ||
170 | */ | 56 | */ |
171 | static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) | 57 | static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) |
172 | { | 58 | { |
173 | return __omap_dm_timer_read(timer->io_base, reg, timer->posted); | 59 | WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET); |
60 | return __omap_dm_timer_read(timer, reg, timer->posted); | ||
174 | } | 61 | } |
175 | 62 | ||
176 | /* | 63 | /** |
177 | * Writes timer registers in posted and non-posted mode. The posted mode bit | 64 | * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode |
178 | * is encoded in reg. Note that in posted mode the write pending bit must be | 65 | * @timer: timer pointer over which write operation is to perform |
179 | * checked. Otherwise a write on a register which has a pending write will be | 66 | * @reg: lowest byte holds the register offset |
180 | * lost. | 67 | * @value: data to write into the register |
68 | * | ||
69 | * The posted mode bit is encoded in reg. Note that in posted mode the write | ||
70 | * pending bit must be checked. Otherwise a write on a register which has a | ||
71 | * pending write will be lost. | ||
181 | */ | 72 | */ |
182 | static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, | 73 | static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, |
183 | u32 value) | 74 | u32 value) |
184 | { | 75 | { |
185 | __omap_dm_timer_write(timer->io_base, reg, value, timer->posted); | 76 | WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET); |
77 | __omap_dm_timer_write(timer, reg, value, timer->posted); | ||
78 | } | ||
79 | |||
80 | static void omap_timer_restore_context(struct omap_dm_timer *timer) | ||
81 | { | ||
82 | omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET, | ||
83 | timer->context.tiocp_cfg); | ||
84 | if (timer->revision > 1) | ||
85 | __raw_writel(timer->context.tistat, timer->sys_stat); | ||
86 | |||
87 | __raw_writel(timer->context.tisr, timer->irq_stat); | ||
88 | omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, | ||
89 | timer->context.twer); | ||
90 | omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, | ||
91 | timer->context.tcrr); | ||
92 | omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, | ||
93 | timer->context.tldr); | ||
94 | omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, | ||
95 | timer->context.tmar); | ||
96 | omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, | ||
97 | timer->context.tsicr); | ||
98 | __raw_writel(timer->context.tier, timer->irq_ena); | ||
99 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, | ||
100 | timer->context.tclr); | ||
186 | } | 101 | } |
187 | 102 | ||
188 | static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) | 103 | static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) |
189 | { | 104 | { |
190 | int c; | 105 | int c; |
191 | 106 | ||
107 | if (!timer->sys_stat) | ||
108 | return; | ||
109 | |||
192 | c = 0; | 110 | c = 0; |
193 | while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) { | 111 | while (!(__raw_readl(timer->sys_stat) & 1)) { |
194 | c++; | 112 | c++; |
195 | if (c > 100000) { | 113 | if (c > 100000) { |
196 | printk(KERN_ERR "Timer failed to reset\n"); | 114 | printk(KERN_ERR "Timer failed to reset\n"); |
@@ -201,53 +119,65 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) | |||
201 | 119 | ||
202 | static void omap_dm_timer_reset(struct omap_dm_timer *timer) | 120 | static void omap_dm_timer_reset(struct omap_dm_timer *timer) |
203 | { | 121 | { |
204 | int autoidle = 0, wakeup = 0; | 122 | omap_dm_timer_enable(timer); |
205 | 123 | if (timer->pdev->id != 1) { | |
206 | if (!cpu_class_is_omap2() || timer != &dm_timers[0]) { | ||
207 | omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); | 124 | omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); |
208 | omap_dm_timer_wait_for_reset(timer); | 125 | omap_dm_timer_wait_for_reset(timer); |
209 | } | 126 | } |
210 | omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); | ||
211 | |||
212 | /* Enable autoidle on OMAP2+ */ | ||
213 | if (cpu_class_is_omap2()) | ||
214 | autoidle = 1; | ||
215 | |||
216 | /* | ||
217 | * Enable wake-up on OMAP2 CPUs. | ||
218 | */ | ||
219 | if (cpu_class_is_omap2()) | ||
220 | wakeup = 1; | ||
221 | 127 | ||
222 | __omap_dm_timer_reset(timer->io_base, autoidle, wakeup); | 128 | __omap_dm_timer_reset(timer, 0, 0); |
129 | omap_dm_timer_disable(timer); | ||
223 | timer->posted = 1; | 130 | timer->posted = 1; |
224 | } | 131 | } |
225 | 132 | ||
226 | void omap_dm_timer_prepare(struct omap_dm_timer *timer) | 133 | int omap_dm_timer_prepare(struct omap_dm_timer *timer) |
227 | { | 134 | { |
228 | omap_dm_timer_enable(timer); | 135 | struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data; |
229 | omap_dm_timer_reset(timer); | 136 | int ret; |
137 | |||
138 | timer->fclk = clk_get(&timer->pdev->dev, "fck"); | ||
139 | if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) { | ||
140 | timer->fclk = NULL; | ||
141 | dev_err(&timer->pdev->dev, ": No fclk handle.\n"); | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | |||
145 | if (pdata->needs_manual_reset) | ||
146 | omap_dm_timer_reset(timer); | ||
147 | |||
148 | ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); | ||
149 | |||
150 | timer->posted = 1; | ||
151 | return ret; | ||
230 | } | 152 | } |
231 | 153 | ||
232 | struct omap_dm_timer *omap_dm_timer_request(void) | 154 | struct omap_dm_timer *omap_dm_timer_request(void) |
233 | { | 155 | { |
234 | struct omap_dm_timer *timer = NULL; | 156 | struct omap_dm_timer *timer = NULL, *t; |
235 | unsigned long flags; | 157 | unsigned long flags; |
236 | int i; | 158 | int ret = 0; |
237 | 159 | ||
238 | spin_lock_irqsave(&dm_timer_lock, flags); | 160 | spin_lock_irqsave(&dm_timer_lock, flags); |
239 | for (i = 0; i < dm_timer_count; i++) { | 161 | list_for_each_entry(t, &omap_timer_list, node) { |
240 | if (dm_timers[i].reserved) | 162 | if (t->reserved) |
241 | continue; | 163 | continue; |
242 | 164 | ||
243 | timer = &dm_timers[i]; | 165 | timer = t; |
244 | timer->reserved = 1; | 166 | timer->reserved = 1; |
245 | break; | 167 | break; |
246 | } | 168 | } |
169 | |||
170 | if (timer) { | ||
171 | ret = omap_dm_timer_prepare(timer); | ||
172 | if (ret) { | ||
173 | timer->reserved = 0; | ||
174 | timer = NULL; | ||
175 | } | ||
176 | } | ||
247 | spin_unlock_irqrestore(&dm_timer_lock, flags); | 177 | spin_unlock_irqrestore(&dm_timer_lock, flags); |
248 | 178 | ||
249 | if (timer != NULL) | 179 | if (!timer) |
250 | omap_dm_timer_prepare(timer); | 180 | pr_debug("%s: timer request failed!\n", __func__); |
251 | 181 | ||
252 | return timer; | 182 | return timer; |
253 | } | 183 | } |
@@ -255,74 +185,65 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request); | |||
255 | 185 | ||
256 | struct omap_dm_timer *omap_dm_timer_request_specific(int id) | 186 | struct omap_dm_timer *omap_dm_timer_request_specific(int id) |
257 | { | 187 | { |
258 | struct omap_dm_timer *timer; | 188 | struct omap_dm_timer *timer = NULL, *t; |
259 | unsigned long flags; | 189 | unsigned long flags; |
190 | int ret = 0; | ||
260 | 191 | ||
261 | spin_lock_irqsave(&dm_timer_lock, flags); | 192 | spin_lock_irqsave(&dm_timer_lock, flags); |
262 | if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) { | 193 | list_for_each_entry(t, &omap_timer_list, node) { |
263 | spin_unlock_irqrestore(&dm_timer_lock, flags); | 194 | if (t->pdev->id == id && !t->reserved) { |
264 | printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n", | 195 | timer = t; |
265 | __FILE__, __LINE__, __func__, id); | 196 | timer->reserved = 1; |
266 | dump_stack(); | 197 | break; |
267 | return NULL; | 198 | } |
268 | } | 199 | } |
269 | 200 | ||
270 | timer = &dm_timers[id-1]; | 201 | if (timer) { |
271 | timer->reserved = 1; | 202 | ret = omap_dm_timer_prepare(timer); |
203 | if (ret) { | ||
204 | timer->reserved = 0; | ||
205 | timer = NULL; | ||
206 | } | ||
207 | } | ||
272 | spin_unlock_irqrestore(&dm_timer_lock, flags); | 208 | spin_unlock_irqrestore(&dm_timer_lock, flags); |
273 | 209 | ||
274 | omap_dm_timer_prepare(timer); | 210 | if (!timer) |
211 | pr_debug("%s: timer%d request failed!\n", __func__, id); | ||
275 | 212 | ||
276 | return timer; | 213 | return timer; |
277 | } | 214 | } |
278 | EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); | 215 | EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); |
279 | 216 | ||
280 | void omap_dm_timer_free(struct omap_dm_timer *timer) | 217 | int omap_dm_timer_free(struct omap_dm_timer *timer) |
281 | { | 218 | { |
282 | omap_dm_timer_enable(timer); | 219 | if (unlikely(!timer)) |
283 | omap_dm_timer_reset(timer); | 220 | return -EINVAL; |
284 | omap_dm_timer_disable(timer); | 221 | |
222 | clk_put(timer->fclk); | ||
285 | 223 | ||
286 | WARN_ON(!timer->reserved); | 224 | WARN_ON(!timer->reserved); |
287 | timer->reserved = 0; | 225 | timer->reserved = 0; |
226 | return 0; | ||
288 | } | 227 | } |
289 | EXPORT_SYMBOL_GPL(omap_dm_timer_free); | 228 | EXPORT_SYMBOL_GPL(omap_dm_timer_free); |
290 | 229 | ||
291 | void omap_dm_timer_enable(struct omap_dm_timer *timer) | 230 | void omap_dm_timer_enable(struct omap_dm_timer *timer) |
292 | { | 231 | { |
293 | if (timer->enabled) | 232 | pm_runtime_get_sync(&timer->pdev->dev); |
294 | return; | ||
295 | |||
296 | #ifdef CONFIG_ARCH_OMAP2PLUS | ||
297 | if (cpu_class_is_omap2()) { | ||
298 | clk_enable(timer->fclk); | ||
299 | clk_enable(timer->iclk); | ||
300 | } | ||
301 | #endif | ||
302 | |||
303 | timer->enabled = 1; | ||
304 | } | 233 | } |
305 | EXPORT_SYMBOL_GPL(omap_dm_timer_enable); | 234 | EXPORT_SYMBOL_GPL(omap_dm_timer_enable); |
306 | 235 | ||
307 | void omap_dm_timer_disable(struct omap_dm_timer *timer) | 236 | void omap_dm_timer_disable(struct omap_dm_timer *timer) |
308 | { | 237 | { |
309 | if (!timer->enabled) | 238 | pm_runtime_put(&timer->pdev->dev); |
310 | return; | ||
311 | |||
312 | #ifdef CONFIG_ARCH_OMAP2PLUS | ||
313 | if (cpu_class_is_omap2()) { | ||
314 | clk_disable(timer->iclk); | ||
315 | clk_disable(timer->fclk); | ||
316 | } | ||
317 | #endif | ||
318 | |||
319 | timer->enabled = 0; | ||
320 | } | 239 | } |
321 | EXPORT_SYMBOL_GPL(omap_dm_timer_disable); | 240 | EXPORT_SYMBOL_GPL(omap_dm_timer_disable); |
322 | 241 | ||
323 | int omap_dm_timer_get_irq(struct omap_dm_timer *timer) | 242 | int omap_dm_timer_get_irq(struct omap_dm_timer *timer) |
324 | { | 243 | { |
325 | return timer->irq; | 244 | if (timer) |
245 | return timer->irq; | ||
246 | return -EINVAL; | ||
326 | } | 247 | } |
327 | EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq); | 248 | EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq); |
328 | 249 | ||
@@ -334,24 +255,29 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq); | |||
334 | */ | 255 | */ |
335 | __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) | 256 | __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) |
336 | { | 257 | { |
337 | int i; | 258 | int i = 0; |
259 | struct omap_dm_timer *timer = NULL; | ||
260 | unsigned long flags; | ||
338 | 261 | ||
339 | /* If ARMXOR cannot be idled this function call is unnecessary */ | 262 | /* If ARMXOR cannot be idled this function call is unnecessary */ |
340 | if (!(inputmask & (1 << 1))) | 263 | if (!(inputmask & (1 << 1))) |
341 | return inputmask; | 264 | return inputmask; |
342 | 265 | ||
343 | /* If any active timer is using ARMXOR return modified mask */ | 266 | /* If any active timer is using ARMXOR return modified mask */ |
344 | for (i = 0; i < dm_timer_count; i++) { | 267 | spin_lock_irqsave(&dm_timer_lock, flags); |
268 | list_for_each_entry(timer, &omap_timer_list, node) { | ||
345 | u32 l; | 269 | u32 l; |
346 | 270 | ||
347 | l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG); | 271 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
348 | if (l & OMAP_TIMER_CTRL_ST) { | 272 | if (l & OMAP_TIMER_CTRL_ST) { |
349 | if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0) | 273 | if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0) |
350 | inputmask &= ~(1 << 1); | 274 | inputmask &= ~(1 << 1); |
351 | else | 275 | else |
352 | inputmask &= ~(1 << 2); | 276 | inputmask &= ~(1 << 2); |
353 | } | 277 | } |
278 | i++; | ||
354 | } | 279 | } |
280 | spin_unlock_irqrestore(&dm_timer_lock, flags); | ||
355 | 281 | ||
356 | return inputmask; | 282 | return inputmask; |
357 | } | 283 | } |
@@ -361,7 +287,9 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask); | |||
361 | 287 | ||
362 | struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) | 288 | struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) |
363 | { | 289 | { |
364 | return timer->fclk; | 290 | if (timer) |
291 | return timer->fclk; | ||
292 | return NULL; | ||
365 | } | 293 | } |
366 | EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk); | 294 | EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk); |
367 | 295 | ||
@@ -375,70 +303,91 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask); | |||
375 | 303 | ||
376 | #endif | 304 | #endif |
377 | 305 | ||
378 | void omap_dm_timer_trigger(struct omap_dm_timer *timer) | 306 | int omap_dm_timer_trigger(struct omap_dm_timer *timer) |
379 | { | 307 | { |
308 | if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { | ||
309 | pr_err("%s: timer not available or enabled.\n", __func__); | ||
310 | return -EINVAL; | ||
311 | } | ||
312 | |||
380 | omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); | 313 | omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); |
314 | return 0; | ||
381 | } | 315 | } |
382 | EXPORT_SYMBOL_GPL(omap_dm_timer_trigger); | 316 | EXPORT_SYMBOL_GPL(omap_dm_timer_trigger); |
383 | 317 | ||
384 | void omap_dm_timer_start(struct omap_dm_timer *timer) | 318 | int omap_dm_timer_start(struct omap_dm_timer *timer) |
385 | { | 319 | { |
386 | u32 l; | 320 | u32 l; |
387 | 321 | ||
322 | if (unlikely(!timer)) | ||
323 | return -EINVAL; | ||
324 | |||
325 | omap_dm_timer_enable(timer); | ||
326 | |||
327 | if (timer->loses_context) { | ||
328 | u32 ctx_loss_cnt_after = | ||
329 | timer->get_context_loss_count(&timer->pdev->dev); | ||
330 | if (ctx_loss_cnt_after != timer->ctx_loss_count) | ||
331 | omap_timer_restore_context(timer); | ||
332 | } | ||
333 | |||
388 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 334 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
389 | if (!(l & OMAP_TIMER_CTRL_ST)) { | 335 | if (!(l & OMAP_TIMER_CTRL_ST)) { |
390 | l |= OMAP_TIMER_CTRL_ST; | 336 | l |= OMAP_TIMER_CTRL_ST; |
391 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | 337 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
392 | } | 338 | } |
339 | |||
340 | /* Save the context */ | ||
341 | timer->context.tclr = l; | ||
342 | return 0; | ||
393 | } | 343 | } |
394 | EXPORT_SYMBOL_GPL(omap_dm_timer_start); | 344 | EXPORT_SYMBOL_GPL(omap_dm_timer_start); |
395 | 345 | ||
396 | void omap_dm_timer_stop(struct omap_dm_timer *timer) | 346 | int omap_dm_timer_stop(struct omap_dm_timer *timer) |
397 | { | 347 | { |
398 | unsigned long rate = 0; | 348 | unsigned long rate = 0; |
349 | struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data; | ||
399 | 350 | ||
400 | #ifdef CONFIG_ARCH_OMAP2PLUS | 351 | if (unlikely(!timer)) |
401 | rate = clk_get_rate(timer->fclk); | 352 | return -EINVAL; |
402 | #endif | ||
403 | 353 | ||
404 | __omap_dm_timer_stop(timer->io_base, timer->posted, rate); | 354 | if (!pdata->needs_manual_reset) |
355 | rate = clk_get_rate(timer->fclk); | ||
356 | |||
357 | __omap_dm_timer_stop(timer, timer->posted, rate); | ||
358 | |||
359 | return 0; | ||
405 | } | 360 | } |
406 | EXPORT_SYMBOL_GPL(omap_dm_timer_stop); | 361 | EXPORT_SYMBOL_GPL(omap_dm_timer_stop); |
407 | 362 | ||
408 | #ifdef CONFIG_ARCH_OMAP1 | ||
409 | |||
410 | int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) | 363 | int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) |
411 | { | 364 | { |
412 | int n = (timer - dm_timers) << 1; | 365 | int ret; |
413 | u32 l; | 366 | struct dmtimer_platform_data *pdata; |
414 | |||
415 | l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n); | ||
416 | l |= source << n; | ||
417 | omap_writel(l, MOD_CONF_CTRL_1); | ||
418 | 367 | ||
419 | return 0; | 368 | if (unlikely(!timer)) |
420 | } | 369 | return -EINVAL; |
421 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); | ||
422 | 370 | ||
423 | #else | 371 | pdata = timer->pdev->dev.platform_data; |
424 | 372 | ||
425 | int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) | ||
426 | { | ||
427 | if (source < 0 || source >= 3) | 373 | if (source < 0 || source >= 3) |
428 | return -EINVAL; | 374 | return -EINVAL; |
429 | 375 | ||
430 | return __omap_dm_timer_set_source(timer->fclk, | 376 | ret = pdata->set_timer_src(timer->pdev, source); |
431 | dm_source_clocks[source]); | 377 | |
378 | return ret; | ||
432 | } | 379 | } |
433 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); | 380 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); |
434 | 381 | ||
435 | #endif | 382 | int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, |
436 | |||
437 | void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, | ||
438 | unsigned int load) | 383 | unsigned int load) |
439 | { | 384 | { |
440 | u32 l; | 385 | u32 l; |
441 | 386 | ||
387 | if (unlikely(!timer)) | ||
388 | return -EINVAL; | ||
389 | |||
390 | omap_dm_timer_enable(timer); | ||
442 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 391 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
443 | if (autoreload) | 392 | if (autoreload) |
444 | l |= OMAP_TIMER_CTRL_AR; | 393 | l |= OMAP_TIMER_CTRL_AR; |
@@ -448,15 +397,32 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, | |||
448 | omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); | 397 | omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); |
449 | 398 | ||
450 | omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); | 399 | omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); |
400 | /* Save the context */ | ||
401 | timer->context.tclr = l; | ||
402 | timer->context.tldr = load; | ||
403 | omap_dm_timer_disable(timer); | ||
404 | return 0; | ||
451 | } | 405 | } |
452 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_load); | 406 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_load); |
453 | 407 | ||
454 | /* Optimized set_load which removes costly spin wait in timer_start */ | 408 | /* Optimized set_load which removes costly spin wait in timer_start */ |
455 | void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, | 409 | int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, |
456 | unsigned int load) | 410 | unsigned int load) |
457 | { | 411 | { |
458 | u32 l; | 412 | u32 l; |
459 | 413 | ||
414 | if (unlikely(!timer)) | ||
415 | return -EINVAL; | ||
416 | |||
417 | omap_dm_timer_enable(timer); | ||
418 | |||
419 | if (timer->loses_context) { | ||
420 | u32 ctx_loss_cnt_after = | ||
421 | timer->get_context_loss_count(&timer->pdev->dev); | ||
422 | if (ctx_loss_cnt_after != timer->ctx_loss_count) | ||
423 | omap_timer_restore_context(timer); | ||
424 | } | ||
425 | |||
460 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 426 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
461 | if (autoreload) { | 427 | if (autoreload) { |
462 | l |= OMAP_TIMER_CTRL_AR; | 428 | l |= OMAP_TIMER_CTRL_AR; |
@@ -466,15 +432,25 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, | |||
466 | } | 432 | } |
467 | l |= OMAP_TIMER_CTRL_ST; | 433 | l |= OMAP_TIMER_CTRL_ST; |
468 | 434 | ||
469 | __omap_dm_timer_load_start(timer->io_base, l, load, timer->posted); | 435 | __omap_dm_timer_load_start(timer, l, load, timer->posted); |
436 | |||
437 | /* Save the context */ | ||
438 | timer->context.tclr = l; | ||
439 | timer->context.tldr = load; | ||
440 | timer->context.tcrr = load; | ||
441 | return 0; | ||
470 | } | 442 | } |
471 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start); | 443 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start); |
472 | 444 | ||
473 | void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, | 445 | int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, |
474 | unsigned int match) | 446 | unsigned int match) |
475 | { | 447 | { |
476 | u32 l; | 448 | u32 l; |
477 | 449 | ||
450 | if (unlikely(!timer)) | ||
451 | return -EINVAL; | ||
452 | |||
453 | omap_dm_timer_enable(timer); | ||
478 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 454 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
479 | if (enable) | 455 | if (enable) |
480 | l |= OMAP_TIMER_CTRL_CE; | 456 | l |= OMAP_TIMER_CTRL_CE; |
@@ -482,14 +458,24 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, | |||
482 | l &= ~OMAP_TIMER_CTRL_CE; | 458 | l &= ~OMAP_TIMER_CTRL_CE; |
483 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | 459 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
484 | omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); | 460 | omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); |
461 | |||
462 | /* Save the context */ | ||
463 | timer->context.tclr = l; | ||
464 | timer->context.tmar = match; | ||
465 | omap_dm_timer_disable(timer); | ||
466 | return 0; | ||
485 | } | 467 | } |
486 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_match); | 468 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_match); |
487 | 469 | ||
488 | void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, | 470 | int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, |
489 | int toggle, int trigger) | 471 | int toggle, int trigger) |
490 | { | 472 | { |
491 | u32 l; | 473 | u32 l; |
492 | 474 | ||
475 | if (unlikely(!timer)) | ||
476 | return -EINVAL; | ||
477 | |||
478 | omap_dm_timer_enable(timer); | ||
493 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 479 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
494 | l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM | | 480 | l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM | |
495 | OMAP_TIMER_CTRL_PT | (0x03 << 10)); | 481 | OMAP_TIMER_CTRL_PT | (0x03 << 10)); |
@@ -499,13 +485,22 @@ void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, | |||
499 | l |= OMAP_TIMER_CTRL_PT; | 485 | l |= OMAP_TIMER_CTRL_PT; |
500 | l |= trigger << 10; | 486 | l |= trigger << 10; |
501 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | 487 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
488 | |||
489 | /* Save the context */ | ||
490 | timer->context.tclr = l; | ||
491 | omap_dm_timer_disable(timer); | ||
492 | return 0; | ||
502 | } | 493 | } |
503 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm); | 494 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm); |
504 | 495 | ||
505 | void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler) | 496 | int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler) |
506 | { | 497 | { |
507 | u32 l; | 498 | u32 l; |
508 | 499 | ||
500 | if (unlikely(!timer)) | ||
501 | return -EINVAL; | ||
502 | |||
503 | omap_dm_timer_enable(timer); | ||
509 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); | 504 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
510 | l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2)); | 505 | l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2)); |
511 | if (prescaler >= 0x00 && prescaler <= 0x07) { | 506 | if (prescaler >= 0x00 && prescaler <= 0x07) { |
@@ -513,13 +508,28 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler) | |||
513 | l |= prescaler << 2; | 508 | l |= prescaler << 2; |
514 | } | 509 | } |
515 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); | 510 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
511 | |||
512 | /* Save the context */ | ||
513 | timer->context.tclr = l; | ||
514 | omap_dm_timer_disable(timer); | ||
515 | return 0; | ||
516 | } | 516 | } |
517 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler); | 517 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler); |
518 | 518 | ||
519 | void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, | 519 | int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, |
520 | unsigned int value) | 520 | unsigned int value) |
521 | { | 521 | { |
522 | __omap_dm_timer_int_enable(timer->io_base, value); | 522 | if (unlikely(!timer)) |
523 | return -EINVAL; | ||
524 | |||
525 | omap_dm_timer_enable(timer); | ||
526 | __omap_dm_timer_int_enable(timer, value); | ||
527 | |||
528 | /* Save the context */ | ||
529 | timer->context.tier = value; | ||
530 | timer->context.twer = value; | ||
531 | omap_dm_timer_disable(timer); | ||
532 | return 0; | ||
523 | } | 533 | } |
524 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); | 534 | EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); |
525 | 535 | ||
@@ -527,40 +537,61 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) | |||
527 | { | 537 | { |
528 | unsigned int l; | 538 | unsigned int l; |
529 | 539 | ||
530 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); | 540 | if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { |
541 | pr_err("%s: timer not available or enabled.\n", __func__); | ||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | l = __raw_readl(timer->irq_stat); | ||
531 | 546 | ||
532 | return l; | 547 | return l; |
533 | } | 548 | } |
534 | EXPORT_SYMBOL_GPL(omap_dm_timer_read_status); | 549 | EXPORT_SYMBOL_GPL(omap_dm_timer_read_status); |
535 | 550 | ||
536 | void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) | 551 | int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) |
537 | { | 552 | { |
538 | __omap_dm_timer_write_status(timer->io_base, value); | 553 | if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) |
554 | return -EINVAL; | ||
555 | |||
556 | __omap_dm_timer_write_status(timer, value); | ||
557 | /* Save the context */ | ||
558 | timer->context.tisr = value; | ||
559 | return 0; | ||
539 | } | 560 | } |
540 | EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); | 561 | EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); |
541 | 562 | ||
542 | unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) | 563 | unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) |
543 | { | 564 | { |
544 | return __omap_dm_timer_read_counter(timer->io_base, timer->posted); | 565 | if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { |
566 | pr_err("%s: timer not iavailable or enabled.\n", __func__); | ||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | return __omap_dm_timer_read_counter(timer, timer->posted); | ||
545 | } | 571 | } |
546 | EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter); | 572 | EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter); |
547 | 573 | ||
548 | void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value) | 574 | int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value) |
549 | { | 575 | { |
576 | if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { | ||
577 | pr_err("%s: timer not available or enabled.\n", __func__); | ||
578 | return -EINVAL; | ||
579 | } | ||
580 | |||
550 | omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value); | 581 | omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value); |
582 | |||
583 | /* Save the context */ | ||
584 | timer->context.tcrr = value; | ||
585 | return 0; | ||
551 | } | 586 | } |
552 | EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter); | 587 | EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter); |
553 | 588 | ||
554 | int omap_dm_timers_active(void) | 589 | int omap_dm_timers_active(void) |
555 | { | 590 | { |
556 | int i; | 591 | struct omap_dm_timer *timer; |
557 | |||
558 | for (i = 0; i < dm_timer_count; i++) { | ||
559 | struct omap_dm_timer *timer; | ||
560 | |||
561 | timer = &dm_timers[i]; | ||
562 | 592 | ||
563 | if (!timer->enabled) | 593 | list_for_each_entry(timer, &omap_timer_list, node) { |
594 | if (!timer->reserved) | ||
564 | continue; | 595 | continue; |
565 | 596 | ||
566 | if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & | 597 | if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & |
@@ -572,69 +603,147 @@ int omap_dm_timers_active(void) | |||
572 | } | 603 | } |
573 | EXPORT_SYMBOL_GPL(omap_dm_timers_active); | 604 | EXPORT_SYMBOL_GPL(omap_dm_timers_active); |
574 | 605 | ||
575 | static int __init omap_dm_timer_init(void) | 606 | /** |
607 | * omap_dm_timer_probe - probe function called for every registered device | ||
608 | * @pdev: pointer to current timer platform device | ||
609 | * | ||
610 | * Called by driver framework at the end of device registration for all | ||
611 | * timer devices. | ||
612 | */ | ||
613 | static int __devinit omap_dm_timer_probe(struct platform_device *pdev) | ||
576 | { | 614 | { |
615 | int ret; | ||
616 | unsigned long flags; | ||
577 | struct omap_dm_timer *timer; | 617 | struct omap_dm_timer *timer; |
578 | int i, map_size = SZ_8K; /* Module 4KB + L4 4KB except on omap1 */ | 618 | struct resource *mem, *irq, *ioarea; |
619 | struct dmtimer_platform_data *pdata = pdev->dev.platform_data; | ||
579 | 620 | ||
580 | if (!(cpu_is_omap16xx() || cpu_class_is_omap2())) | 621 | if (!pdata) { |
622 | dev_err(&pdev->dev, "%s: no platform data.\n", __func__); | ||
581 | return -ENODEV; | 623 | return -ENODEV; |
624 | } | ||
582 | 625 | ||
583 | spin_lock_init(&dm_timer_lock); | 626 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
584 | 627 | if (unlikely(!irq)) { | |
585 | if (cpu_class_is_omap1()) { | 628 | dev_err(&pdev->dev, "%s: no IRQ resource.\n", __func__); |
586 | dm_timers = omap1_dm_timers; | 629 | return -ENODEV; |
587 | dm_timer_count = omap1_dm_timer_count; | ||
588 | map_size = SZ_2K; | ||
589 | } else if (cpu_is_omap24xx()) { | ||
590 | dm_timers = omap2_dm_timers; | ||
591 | dm_timer_count = omap2_dm_timer_count; | ||
592 | dm_source_names = omap2_dm_source_names; | ||
593 | dm_source_clocks = omap2_dm_source_clocks; | ||
594 | } else if (cpu_is_omap34xx()) { | ||
595 | dm_timers = omap3_dm_timers; | ||
596 | dm_timer_count = omap3_dm_timer_count; | ||
597 | dm_source_names = omap3_dm_source_names; | ||
598 | dm_source_clocks = omap3_dm_source_clocks; | ||
599 | } else if (cpu_is_omap44xx()) { | ||
600 | dm_timers = omap4_dm_timers; | ||
601 | dm_timer_count = omap4_dm_timer_count; | ||
602 | dm_source_names = omap4_dm_source_names; | ||
603 | dm_source_clocks = omap4_dm_source_clocks; | ||
604 | } | 630 | } |
605 | 631 | ||
606 | if (cpu_class_is_omap2()) | 632 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
607 | for (i = 0; dm_source_names[i] != NULL; i++) | 633 | if (unlikely(!mem)) { |
608 | dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]); | 634 | dev_err(&pdev->dev, "%s: no memory resource.\n", __func__); |
635 | return -ENODEV; | ||
636 | } | ||
609 | 637 | ||
610 | if (cpu_is_omap243x()) | 638 | ioarea = request_mem_region(mem->start, resource_size(mem), |
611 | dm_timers[0].phys_base = 0x49018000; | 639 | pdev->name); |
640 | if (!ioarea) { | ||
641 | dev_err(&pdev->dev, "%s: region already claimed.\n", __func__); | ||
642 | return -EBUSY; | ||
643 | } | ||
612 | 644 | ||
613 | for (i = 0; i < dm_timer_count; i++) { | 645 | timer = kzalloc(sizeof(struct omap_dm_timer), GFP_KERNEL); |
614 | timer = &dm_timers[i]; | 646 | if (!timer) { |
647 | dev_err(&pdev->dev, "%s: no memory for omap_dm_timer.\n", | ||
648 | __func__); | ||
649 | ret = -ENOMEM; | ||
650 | goto err_free_ioregion; | ||
651 | } | ||
615 | 652 | ||
616 | /* Static mapping, never released */ | 653 | timer->io_base = ioremap(mem->start, resource_size(mem)); |
617 | timer->io_base = ioremap(timer->phys_base, map_size); | 654 | if (!timer->io_base) { |
618 | BUG_ON(!timer->io_base); | 655 | dev_err(&pdev->dev, "%s: ioremap failed.\n", __func__); |
656 | ret = -ENOMEM; | ||
657 | goto err_free_mem; | ||
658 | } | ||
619 | 659 | ||
620 | #ifdef CONFIG_ARCH_OMAP2PLUS | 660 | timer->id = pdev->id; |
621 | if (cpu_class_is_omap2()) { | 661 | timer->irq = irq->start; |
622 | char clk_name[16]; | 662 | timer->reserved = pdata->reserved; |
623 | sprintf(clk_name, "gpt%d_ick", i + 1); | 663 | timer->pdev = pdev; |
624 | timer->iclk = clk_get(NULL, clk_name); | 664 | timer->loses_context = pdata->loses_context; |
625 | sprintf(clk_name, "gpt%d_fck", i + 1); | 665 | timer->get_context_loss_count = pdata->get_context_loss_count; |
626 | timer->fclk = clk_get(NULL, clk_name); | 666 | |
627 | } | 667 | /* Skip pm_runtime_enable for OMAP1 */ |
668 | if (!pdata->needs_manual_reset) { | ||
669 | pm_runtime_enable(&pdev->dev); | ||
670 | pm_runtime_irq_safe(&pdev->dev); | ||
671 | } | ||
628 | 672 | ||
629 | /* One or two timers may be set up early for sys_timer */ | 673 | if (!timer->reserved) { |
630 | if (sys_timer_reserved & (1 << i)) { | 674 | pm_runtime_get_sync(&pdev->dev); |
631 | timer->reserved = 1; | 675 | __omap_dm_timer_init_regs(timer); |
632 | timer->posted = 1; | 676 | pm_runtime_put(&pdev->dev); |
633 | } | ||
634 | #endif | ||
635 | } | 677 | } |
636 | 678 | ||
679 | /* add the timer element to the list */ | ||
680 | spin_lock_irqsave(&dm_timer_lock, flags); | ||
681 | list_add_tail(&timer->node, &omap_timer_list); | ||
682 | spin_unlock_irqrestore(&dm_timer_lock, flags); | ||
683 | |||
684 | dev_dbg(&pdev->dev, "Device Probed.\n"); | ||
685 | |||
637 | return 0; | 686 | return 0; |
687 | |||
688 | err_free_mem: | ||
689 | kfree(timer); | ||
690 | |||
691 | err_free_ioregion: | ||
692 | release_mem_region(mem->start, resource_size(mem)); | ||
693 | |||
694 | return ret; | ||
638 | } | 695 | } |
639 | 696 | ||
640 | arch_initcall(omap_dm_timer_init); | 697 | /** |
698 | * omap_dm_timer_remove - cleanup a registered timer device | ||
699 | * @pdev: pointer to current timer platform device | ||
700 | * | ||
701 | * Called by driver framework whenever a timer device is unregistered. | ||
702 | * In addition to freeing platform resources it also deletes the timer | ||
703 | * entry from the local list. | ||
704 | */ | ||
705 | static int __devexit omap_dm_timer_remove(struct platform_device *pdev) | ||
706 | { | ||
707 | struct omap_dm_timer *timer; | ||
708 | unsigned long flags; | ||
709 | int ret = -EINVAL; | ||
710 | |||
711 | spin_lock_irqsave(&dm_timer_lock, flags); | ||
712 | list_for_each_entry(timer, &omap_timer_list, node) | ||
713 | if (timer->pdev->id == pdev->id) { | ||
714 | list_del(&timer->node); | ||
715 | kfree(timer); | ||
716 | ret = 0; | ||
717 | break; | ||
718 | } | ||
719 | spin_unlock_irqrestore(&dm_timer_lock, flags); | ||
720 | |||
721 | return ret; | ||
722 | } | ||
723 | |||
724 | static struct platform_driver omap_dm_timer_driver = { | ||
725 | .probe = omap_dm_timer_probe, | ||
726 | .remove = __devexit_p(omap_dm_timer_remove), | ||
727 | .driver = { | ||
728 | .name = "omap_timer", | ||
729 | }, | ||
730 | }; | ||
731 | |||
732 | static int __init omap_dm_timer_driver_init(void) | ||
733 | { | ||
734 | return platform_driver_register(&omap_dm_timer_driver); | ||
735 | } | ||
736 | |||
737 | static void __exit omap_dm_timer_driver_exit(void) | ||
738 | { | ||
739 | platform_driver_unregister(&omap_dm_timer_driver); | ||
740 | } | ||
741 | |||
742 | early_platform_init("earlytimer", &omap_dm_timer_driver); | ||
743 | module_init(omap_dm_timer_driver_init); | ||
744 | module_exit(omap_dm_timer_driver_exit); | ||
745 | |||
746 | MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver"); | ||
747 | MODULE_LICENSE("GPL"); | ||
748 | MODULE_ALIAS("platform:" DRIVER_NAME); | ||
749 | MODULE_AUTHOR("Texas Instruments Inc"); | ||