blob: 6510e5e7b7e3df10bd99fc68738125534ce94fd7 [file] [log] [blame]
Tony Lindgren92105bb2005-09-07 17:20:26 +01001/*
2 * linux/arch/arm/plat-omap/dmtimer.c
3 *
4 * OMAP Dual-Mode Timers
5 *
Tarun Kanti DebBarma97933d62011-09-20 17:00:17 +05306 * 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 *
Tony Lindgren92105bb2005-09-07 17:20:26 +010012 * Copyright (C) 2005 Nokia Corporation
Timo Teras77900a22006-06-26 16:16:12 -070013 * OMAP2 support by Juha Yrjola
14 * API improvements and OMAP2 clock framework support by Timo Teras
Tony Lindgren92105bb2005-09-07 17:20:26 +010015 *
Santosh Shilimkar44169072009-05-28 14:16:04 -070016 * Copyright (C) 2009 Texas Instruments
17 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
18 *
Tony Lindgren92105bb2005-09-07 17:20:26 +010019 * This program is free software; you can redistribute it and/or modify it
20 * under the terms of the GNU General Public License as published by the
21 * Free Software Foundation; either version 2 of the License, or (at your
22 * option) any later version.
23 *
24 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
27 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * You should have received a copy of the GNU General Public License along
34 * with this program; if not, write to the Free Software Foundation, Inc.,
35 * 675 Mass Ave, Cambridge, MA 02139, USA.
36 */
37
Axel Lin869dec12011-11-02 09:49:46 +080038#include <linux/module.h>
Russell Kingfced80c2008-09-06 12:10:45 +010039#include <linux/io.h>
Tarun Kanti DebBarmadf284722011-09-20 17:00:19 +053040#include <linux/slab.h>
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +053041#include <linux/err.h>
Tarun Kanti DebBarmaffe07ce2011-09-20 17:00:21 +053042#include <linux/pm_runtime.h>
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +053043
Tony Lindgrence491cf2009-10-20 09:40:47 -070044#include <plat/dmtimer.h>
Jon Hunter0b30ec12012-06-05 12:34:56 -050045#include <plat/omap-pm.h>
Tony Lindgren92105bb2005-09-07 17:20:26 +010046
Tony Lindgren2c799ce2012-02-24 10:34:35 -080047#include <mach/hardware.h>
48
Jon Hunterb7b4ff72012-06-05 12:34:51 -050049static u32 omap_reserved_systimers;
Tarun Kanti DebBarmadf284722011-09-20 17:00:19 +053050static LIST_HEAD(omap_timer_list);
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +053051static DEFINE_SPINLOCK(dm_timer_lock);
Tony Lindgren92105bb2005-09-07 17:20:26 +010052
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +053053/**
54 * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
55 * @timer: timer pointer over which read operation to perform
56 * @reg: lowest byte holds the register offset
57 *
58 * The posted mode bit is encoded in reg. Note that in posted mode write
59 * pending bit must be checked. Otherwise a read of a non completed write
60 * will produce an error.
Richard Woodruff0f0d0802008-07-03 12:24:30 +030061 */
62static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
Tony Lindgren92105bb2005-09-07 17:20:26 +010063{
Tony Lindgrenee17f112011-09-16 15:44:20 -070064 WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
65 return __omap_dm_timer_read(timer, reg, timer->posted);
Timo Teras77900a22006-06-26 16:16:12 -070066}
67
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +053068/**
69 * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
70 * @timer: timer pointer over which write operation is to perform
71 * @reg: lowest byte holds the register offset
72 * @value: data to write into the register
73 *
74 * The posted mode bit is encoded in reg. Note that in posted mode the write
75 * pending bit must be checked. Otherwise a write on a register which has a
76 * pending write will be lost.
Richard Woodruff0f0d0802008-07-03 12:24:30 +030077 */
78static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
79 u32 value)
Timo Teras77900a22006-06-26 16:16:12 -070080{
Tony Lindgrenee17f112011-09-16 15:44:20 -070081 WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
82 __omap_dm_timer_write(timer, reg, value, timer->posted);
Tony Lindgren92105bb2005-09-07 17:20:26 +010083}
84
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +053085static void omap_timer_restore_context(struct omap_dm_timer *timer)
86{
Tarun Kanti DebBarmadffc9da2012-03-05 16:11:00 -080087 if (timer->revision == 1)
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +053088 __raw_writel(timer->context.tistat, timer->sys_stat);
89
90 __raw_writel(timer->context.tisr, timer->irq_stat);
91 omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
92 timer->context.twer);
93 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
94 timer->context.tcrr);
95 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
96 timer->context.tldr);
97 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
98 timer->context.tmar);
99 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
100 timer->context.tsicr);
101 __raw_writel(timer->context.tier, timer->irq_ena);
102 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
103 timer->context.tclr);
104}
105
Timo Teras77900a22006-06-26 16:16:12 -0700106static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
Tony Lindgren92105bb2005-09-07 17:20:26 +0100107{
Timo Teras77900a22006-06-26 16:16:12 -0700108 int c;
109
Tony Lindgrenee17f112011-09-16 15:44:20 -0700110 if (!timer->sys_stat)
111 return;
112
Timo Teras77900a22006-06-26 16:16:12 -0700113 c = 0;
Tony Lindgrenee17f112011-09-16 15:44:20 -0700114 while (!(__raw_readl(timer->sys_stat) & 1)) {
Timo Teras77900a22006-06-26 16:16:12 -0700115 c++;
116 if (c > 100000) {
117 printk(KERN_ERR "Timer failed to reset\n");
118 return;
119 }
120 }
Tony Lindgren92105bb2005-09-07 17:20:26 +0100121}
122
Timo Teras77900a22006-06-26 16:16:12 -0700123static void omap_dm_timer_reset(struct omap_dm_timer *timer)
124{
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530125 omap_dm_timer_enable(timer);
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530126 if (timer->pdev->id != 1) {
Timo Terase32f7ec2006-06-26 16:16:13 -0700127 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
128 omap_dm_timer_wait_for_reset(timer);
129 }
Timo Teras77900a22006-06-26 16:16:12 -0700130
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530131 __omap_dm_timer_reset(timer, 0, 0);
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530132 omap_dm_timer_disable(timer);
Richard Woodruff0f0d0802008-07-03 12:24:30 +0300133 timer->posted = 1;
Timo Teras77900a22006-06-26 16:16:12 -0700134}
135
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530136int omap_dm_timer_prepare(struct omap_dm_timer *timer)
Timo Teras77900a22006-06-26 16:16:12 -0700137{
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530138 int ret;
139
Jon Hunterbca45802012-06-05 12:34:58 -0500140 /*
141 * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
142 * do not call clk_get() for these devices.
143 */
144 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
145 timer->fclk = clk_get(&timer->pdev->dev, "fck");
146 if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
147 timer->fclk = NULL;
148 dev_err(&timer->pdev->dev, ": No fclk handle.\n");
149 return -EINVAL;
150 }
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530151 }
152
Jon Hunter66159752012-06-05 12:34:57 -0500153 if (timer->capability & OMAP_TIMER_NEEDS_RESET)
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530154 omap_dm_timer_reset(timer);
155
156 ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
157
158 timer->posted = 1;
159 return ret;
Timo Teras77900a22006-06-26 16:16:12 -0700160}
161
Jon Hunterb7b4ff72012-06-05 12:34:51 -0500162static inline u32 omap_dm_timer_reserved_systimer(int id)
163{
164 return (omap_reserved_systimers & (1 << (id - 1))) ? 1 : 0;
165}
166
167int omap_dm_timer_reserve_systimer(int id)
168{
169 if (omap_dm_timer_reserved_systimer(id))
170 return -ENODEV;
171
172 omap_reserved_systimers |= (1 << (id - 1));
173
174 return 0;
175}
176
Timo Teras77900a22006-06-26 16:16:12 -0700177struct omap_dm_timer *omap_dm_timer_request(void)
178{
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530179 struct omap_dm_timer *timer = NULL, *t;
Timo Teras77900a22006-06-26 16:16:12 -0700180 unsigned long flags;
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530181 int ret = 0;
Timo Teras77900a22006-06-26 16:16:12 -0700182
183 spin_lock_irqsave(&dm_timer_lock, flags);
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530184 list_for_each_entry(t, &omap_timer_list, node) {
185 if (t->reserved)
Timo Teras77900a22006-06-26 16:16:12 -0700186 continue;
187
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530188 timer = t;
Timo Teras83379c82006-06-26 16:16:23 -0700189 timer->reserved = 1;
Timo Teras77900a22006-06-26 16:16:12 -0700190 break;
191 }
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530192
193 if (timer) {
194 ret = omap_dm_timer_prepare(timer);
195 if (ret) {
196 timer->reserved = 0;
197 timer = NULL;
198 }
199 }
Timo Teras77900a22006-06-26 16:16:12 -0700200 spin_unlock_irqrestore(&dm_timer_lock, flags);
201
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530202 if (!timer)
203 pr_debug("%s: timer request failed!\n", __func__);
Timo Teras83379c82006-06-26 16:16:23 -0700204
Timo Teras77900a22006-06-26 16:16:12 -0700205 return timer;
206}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700207EXPORT_SYMBOL_GPL(omap_dm_timer_request);
Timo Teras77900a22006-06-26 16:16:12 -0700208
209struct omap_dm_timer *omap_dm_timer_request_specific(int id)
Tony Lindgren92105bb2005-09-07 17:20:26 +0100210{
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530211 struct omap_dm_timer *timer = NULL, *t;
Timo Teras77900a22006-06-26 16:16:12 -0700212 unsigned long flags;
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530213 int ret = 0;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100214
Timo Teras77900a22006-06-26 16:16:12 -0700215 spin_lock_irqsave(&dm_timer_lock, flags);
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530216 list_for_each_entry(t, &omap_timer_list, node) {
217 if (t->pdev->id == id && !t->reserved) {
218 timer = t;
219 timer->reserved = 1;
220 break;
221 }
Timo Teras77900a22006-06-26 16:16:12 -0700222 }
Tony Lindgren92105bb2005-09-07 17:20:26 +0100223
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530224 if (timer) {
225 ret = omap_dm_timer_prepare(timer);
226 if (ret) {
227 timer->reserved = 0;
228 timer = NULL;
229 }
230 }
Timo Teras77900a22006-06-26 16:16:12 -0700231 spin_unlock_irqrestore(&dm_timer_lock, flags);
232
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530233 if (!timer)
234 pr_debug("%s: timer%d request failed!\n", __func__, id);
Timo Teras83379c82006-06-26 16:16:23 -0700235
Timo Teras77900a22006-06-26 16:16:12 -0700236 return timer;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100237}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700238EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100239
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530240int omap_dm_timer_free(struct omap_dm_timer *timer)
Timo Teras77900a22006-06-26 16:16:12 -0700241{
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530242 if (unlikely(!timer))
243 return -EINVAL;
244
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530245 clk_put(timer->fclk);
Timo Terasfa4bb622006-09-25 12:41:35 +0300246
Timo Teras77900a22006-06-26 16:16:12 -0700247 WARN_ON(!timer->reserved);
248 timer->reserved = 0;
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530249 return 0;
Timo Teras77900a22006-06-26 16:16:12 -0700250}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700251EXPORT_SYMBOL_GPL(omap_dm_timer_free);
Timo Teras77900a22006-06-26 16:16:12 -0700252
Timo Teras12583a72006-09-25 12:41:42 +0300253void omap_dm_timer_enable(struct omap_dm_timer *timer)
254{
Tarun Kanti DebBarmaffe07ce2011-09-20 17:00:21 +0530255 pm_runtime_get_sync(&timer->pdev->dev);
Timo Teras12583a72006-09-25 12:41:42 +0300256}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700257EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
Timo Teras12583a72006-09-25 12:41:42 +0300258
259void omap_dm_timer_disable(struct omap_dm_timer *timer)
260{
Tarun Kanti DebBarmaffe07ce2011-09-20 17:00:21 +0530261 pm_runtime_put(&timer->pdev->dev);
Timo Teras12583a72006-09-25 12:41:42 +0300262}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700263EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
Timo Teras12583a72006-09-25 12:41:42 +0300264
Timo Teras77900a22006-06-26 16:16:12 -0700265int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
266{
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530267 if (timer)
268 return timer->irq;
269 return -EINVAL;
Timo Teras77900a22006-06-26 16:16:12 -0700270}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700271EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
Timo Teras77900a22006-06-26 16:16:12 -0700272
273#if defined(CONFIG_ARCH_OMAP1)
274
Tony Lindgrena569c6e2006-04-02 17:46:21 +0100275/**
276 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
277 * @inputmask: current value of idlect mask
278 */
279__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
280{
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530281 int i = 0;
282 struct omap_dm_timer *timer = NULL;
283 unsigned long flags;
Tony Lindgrena569c6e2006-04-02 17:46:21 +0100284
285 /* If ARMXOR cannot be idled this function call is unnecessary */
286 if (!(inputmask & (1 << 1)))
287 return inputmask;
288
289 /* If any active timer is using ARMXOR return modified mask */
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530290 spin_lock_irqsave(&dm_timer_lock, flags);
291 list_for_each_entry(timer, &omap_timer_list, node) {
Timo Teras77900a22006-06-26 16:16:12 -0700292 u32 l;
293
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530294 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
Timo Teras77900a22006-06-26 16:16:12 -0700295 if (l & OMAP_TIMER_CTRL_ST) {
296 if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
Tony Lindgrena569c6e2006-04-02 17:46:21 +0100297 inputmask &= ~(1 << 1);
298 else
299 inputmask &= ~(1 << 2);
300 }
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530301 i++;
Timo Teras77900a22006-06-26 16:16:12 -0700302 }
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530303 spin_unlock_irqrestore(&dm_timer_lock, flags);
Tony Lindgrena569c6e2006-04-02 17:46:21 +0100304
305 return inputmask;
306}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700307EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
Tony Lindgrena569c6e2006-04-02 17:46:21 +0100308
Tony Lindgren140455f2010-02-12 12:26:48 -0800309#else
Timo Teras77900a22006-06-26 16:16:12 -0700310
311struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
312{
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530313 if (timer)
314 return timer->fclk;
315 return NULL;
Timo Teras77900a22006-06-26 16:16:12 -0700316}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700317EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
Timo Teras77900a22006-06-26 16:16:12 -0700318
319__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
320{
321 BUG();
Dirk Behme21218802006-12-06 17:14:00 -0800322
323 return 0;
Timo Teras77900a22006-06-26 16:16:12 -0700324}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700325EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
Timo Teras77900a22006-06-26 16:16:12 -0700326
327#endif
328
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530329int omap_dm_timer_trigger(struct omap_dm_timer *timer)
Timo Teras77900a22006-06-26 16:16:12 -0700330{
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530331 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
332 pr_err("%s: timer not available or enabled.\n", __func__);
333 return -EINVAL;
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530334 }
335
Timo Teras77900a22006-06-26 16:16:12 -0700336 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530337 return 0;
Timo Teras77900a22006-06-26 16:16:12 -0700338}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700339EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
Timo Teras77900a22006-06-26 16:16:12 -0700340
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530341int omap_dm_timer_start(struct omap_dm_timer *timer)
Timo Teras77900a22006-06-26 16:16:12 -0700342{
343 u32 l;
344
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530345 if (unlikely(!timer))
346 return -EINVAL;
347
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530348 omap_dm_timer_enable(timer);
349
Jon Hunter1c2d0762012-06-05 12:34:55 -0500350 if (!(timer->capability & OMAP_TIMER_ALWON)) {
Jon Hunter0b30ec12012-06-05 12:34:56 -0500351 if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) !=
352 timer->ctx_loss_count)
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530353 omap_timer_restore_context(timer);
354 }
355
Timo Teras77900a22006-06-26 16:16:12 -0700356 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
357 if (!(l & OMAP_TIMER_CTRL_ST)) {
358 l |= OMAP_TIMER_CTRL_ST;
359 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
360 }
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530361
362 /* Save the context */
363 timer->context.tclr = l;
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530364 return 0;
Timo Teras77900a22006-06-26 16:16:12 -0700365}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700366EXPORT_SYMBOL_GPL(omap_dm_timer_start);
Timo Teras77900a22006-06-26 16:16:12 -0700367
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530368int omap_dm_timer_stop(struct omap_dm_timer *timer)
Timo Teras77900a22006-06-26 16:16:12 -0700369{
Tony Lindgrencaf64f22011-03-29 15:54:48 -0700370 unsigned long rate = 0;
Timo Teras77900a22006-06-26 16:16:12 -0700371
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530372 if (unlikely(!timer))
373 return -EINVAL;
374
Jon Hunter66159752012-06-05 12:34:57 -0500375 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530376 rate = clk_get_rate(timer->fclk);
Tony Lindgrencaf64f22011-03-29 15:54:48 -0700377
Tony Lindgrenee17f112011-09-16 15:44:20 -0700378 __omap_dm_timer_stop(timer, timer->posted, rate);
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530379
Jon Hunter0b30ec12012-06-05 12:34:56 -0500380 if (!(timer->capability & OMAP_TIMER_ALWON))
Tarun Kanti DebBarmadffc9da2012-03-05 16:11:00 -0800381 timer->ctx_loss_count =
Jon Hunter0b30ec12012-06-05 12:34:56 -0500382 omap_pm_get_dev_context_loss_count(&timer->pdev->dev);
Tarun Kanti DebBarmadffc9da2012-03-05 16:11:00 -0800383
384 /*
385 * Since the register values are computed and written within
386 * __omap_dm_timer_stop, we need to use read to retrieve the
387 * context.
388 */
389 timer->context.tclr =
390 omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
391 timer->context.tisr = __raw_readl(timer->irq_stat);
392 omap_dm_timer_disable(timer);
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530393 return 0;
Timo Teras77900a22006-06-26 16:16:12 -0700394}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700395EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
Timo Teras77900a22006-06-26 16:16:12 -0700396
Paul Walmsleyf2480762009-04-23 21:11:10 -0600397int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
Tony Lindgren92105bb2005-09-07 17:20:26 +0100398{
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530399 int ret;
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530400 struct dmtimer_platform_data *pdata;
401
402 if (unlikely(!timer))
403 return -EINVAL;
404
405 pdata = timer->pdev->dev.platform_data;
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530406
Timo Teras77900a22006-06-26 16:16:12 -0700407 if (source < 0 || source >= 3)
Paul Walmsleyf2480762009-04-23 21:11:10 -0600408 return -EINVAL;
Timo Teras77900a22006-06-26 16:16:12 -0700409
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530410 ret = pdata->set_timer_src(timer->pdev, source);
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530411
412 return ret;
Timo Teras77900a22006-06-26 16:16:12 -0700413}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700414EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
Timo Teras77900a22006-06-26 16:16:12 -0700415
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530416int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
Timo Teras77900a22006-06-26 16:16:12 -0700417 unsigned int load)
418{
419 u32 l;
420
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530421 if (unlikely(!timer))
422 return -EINVAL;
423
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530424 omap_dm_timer_enable(timer);
Timo Teras77900a22006-06-26 16:16:12 -0700425 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
426 if (autoreload)
427 l |= OMAP_TIMER_CTRL_AR;
428 else
429 l &= ~OMAP_TIMER_CTRL_AR;
430 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
431 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
Richard Woodruff0f0d0802008-07-03 12:24:30 +0300432
Timo Teras77900a22006-06-26 16:16:12 -0700433 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530434 /* Save the context */
435 timer->context.tclr = l;
436 timer->context.tldr = load;
437 omap_dm_timer_disable(timer);
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530438 return 0;
Timo Teras77900a22006-06-26 16:16:12 -0700439}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700440EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
Timo Teras77900a22006-06-26 16:16:12 -0700441
Richard Woodruff3fddd092008-07-03 12:24:30 +0300442/* Optimized set_load which removes costly spin wait in timer_start */
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530443int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
Richard Woodruff3fddd092008-07-03 12:24:30 +0300444 unsigned int load)
445{
446 u32 l;
447
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530448 if (unlikely(!timer))
449 return -EINVAL;
450
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530451 omap_dm_timer_enable(timer);
452
Jon Hunter1c2d0762012-06-05 12:34:55 -0500453 if (!(timer->capability & OMAP_TIMER_ALWON)) {
Jon Hunter0b30ec12012-06-05 12:34:56 -0500454 if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) !=
455 timer->ctx_loss_count)
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530456 omap_timer_restore_context(timer);
457 }
458
Richard Woodruff3fddd092008-07-03 12:24:30 +0300459 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
Paul Walmsley64ce2902008-12-10 17:36:34 -0800460 if (autoreload) {
Richard Woodruff3fddd092008-07-03 12:24:30 +0300461 l |= OMAP_TIMER_CTRL_AR;
Paul Walmsley64ce2902008-12-10 17:36:34 -0800462 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
463 } else {
Richard Woodruff3fddd092008-07-03 12:24:30 +0300464 l &= ~OMAP_TIMER_CTRL_AR;
Paul Walmsley64ce2902008-12-10 17:36:34 -0800465 }
Richard Woodruff3fddd092008-07-03 12:24:30 +0300466 l |= OMAP_TIMER_CTRL_ST;
467
Tony Lindgrenee17f112011-09-16 15:44:20 -0700468 __omap_dm_timer_load_start(timer, l, load, timer->posted);
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530469
470 /* Save the context */
471 timer->context.tclr = l;
472 timer->context.tldr = load;
473 timer->context.tcrr = load;
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530474 return 0;
Richard Woodruff3fddd092008-07-03 12:24:30 +0300475}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700476EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
Richard Woodruff3fddd092008-07-03 12:24:30 +0300477
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530478int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
Timo Teras77900a22006-06-26 16:16:12 -0700479 unsigned int match)
480{
481 u32 l;
482
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530483 if (unlikely(!timer))
484 return -EINVAL;
485
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530486 omap_dm_timer_enable(timer);
Timo Teras77900a22006-06-26 16:16:12 -0700487 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
Timo Teras83379c82006-06-26 16:16:23 -0700488 if (enable)
Timo Teras77900a22006-06-26 16:16:12 -0700489 l |= OMAP_TIMER_CTRL_CE;
490 else
491 l &= ~OMAP_TIMER_CTRL_CE;
492 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
493 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530494
495 /* Save the context */
496 timer->context.tclr = l;
497 timer->context.tmar = match;
498 omap_dm_timer_disable(timer);
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530499 return 0;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100500}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700501EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100502
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530503int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
Timo Teras77900a22006-06-26 16:16:12 -0700504 int toggle, int trigger)
Tony Lindgren92105bb2005-09-07 17:20:26 +0100505{
Timo Teras77900a22006-06-26 16:16:12 -0700506 u32 l;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100507
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530508 if (unlikely(!timer))
509 return -EINVAL;
510
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530511 omap_dm_timer_enable(timer);
Timo Teras77900a22006-06-26 16:16:12 -0700512 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
513 l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
514 OMAP_TIMER_CTRL_PT | (0x03 << 10));
515 if (def_on)
516 l |= OMAP_TIMER_CTRL_SCPWM;
517 if (toggle)
518 l |= OMAP_TIMER_CTRL_PT;
519 l |= trigger << 10;
520 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530521
522 /* Save the context */
523 timer->context.tclr = l;
524 omap_dm_timer_disable(timer);
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530525 return 0;
Timo Teras77900a22006-06-26 16:16:12 -0700526}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700527EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
Timo Teras77900a22006-06-26 16:16:12 -0700528
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530529int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
Timo Teras77900a22006-06-26 16:16:12 -0700530{
531 u32 l;
532
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530533 if (unlikely(!timer))
534 return -EINVAL;
535
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530536 omap_dm_timer_enable(timer);
Timo Teras77900a22006-06-26 16:16:12 -0700537 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
538 l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
539 if (prescaler >= 0x00 && prescaler <= 0x07) {
540 l |= OMAP_TIMER_CTRL_PRE;
541 l |= prescaler << 2;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100542 }
Timo Teras77900a22006-06-26 16:16:12 -0700543 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530544
545 /* Save the context */
546 timer->context.tclr = l;
547 omap_dm_timer_disable(timer);
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530548 return 0;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100549}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700550EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100551
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530552int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
Timo Teras77900a22006-06-26 16:16:12 -0700553 unsigned int value)
Tony Lindgren92105bb2005-09-07 17:20:26 +0100554{
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530555 if (unlikely(!timer))
556 return -EINVAL;
557
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530558 omap_dm_timer_enable(timer);
Tony Lindgrenee17f112011-09-16 15:44:20 -0700559 __omap_dm_timer_int_enable(timer, value);
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530560
561 /* Save the context */
562 timer->context.tier = value;
563 timer->context.twer = value;
564 omap_dm_timer_disable(timer);
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530565 return 0;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100566}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700567EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100568
569unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
570{
Timo Terasfa4bb622006-09-25 12:41:35 +0300571 unsigned int l;
572
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530573 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
574 pr_err("%s: timer not available or enabled.\n", __func__);
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530575 return 0;
576 }
577
Tony Lindgrenee17f112011-09-16 15:44:20 -0700578 l = __raw_readl(timer->irq_stat);
Timo Terasfa4bb622006-09-25 12:41:35 +0300579
580 return l;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100581}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700582EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100583
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530584int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
Tony Lindgren92105bb2005-09-07 17:20:26 +0100585{
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530586 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
587 return -EINVAL;
588
Tony Lindgrenee17f112011-09-16 15:44:20 -0700589 __omap_dm_timer_write_status(timer, value);
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530590 /* Save the context */
591 timer->context.tisr = value;
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530592 return 0;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100593}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700594EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100595
Tony Lindgren92105bb2005-09-07 17:20:26 +0100596unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
597{
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530598 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
599 pr_err("%s: timer not iavailable or enabled.\n", __func__);
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530600 return 0;
601 }
602
Tony Lindgrenee17f112011-09-16 15:44:20 -0700603 return __omap_dm_timer_read_counter(timer, timer->posted);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100604}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700605EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100606
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530607int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
Timo Teras83379c82006-06-26 16:16:23 -0700608{
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530609 if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
610 pr_err("%s: timer not available or enabled.\n", __func__);
611 return -EINVAL;
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530612 }
613
Timo Terasfa4bb622006-09-25 12:41:35 +0300614 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
Tarun Kanti DebBarmab4811132011-09-20 17:00:24 +0530615
616 /* Save the context */
617 timer->context.tcrr = value;
Tarun Kanti DebBarmaab4eb8b2011-09-20 17:00:26 +0530618 return 0;
Timo Teras83379c82006-06-26 16:16:23 -0700619}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700620EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
Timo Teras83379c82006-06-26 16:16:23 -0700621
Timo Teras77900a22006-06-26 16:16:12 -0700622int omap_dm_timers_active(void)
Tony Lindgren92105bb2005-09-07 17:20:26 +0100623{
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530624 struct omap_dm_timer *timer;
Tony Lindgren92105bb2005-09-07 17:20:26 +0100625
Tarun Kanti DebBarma3392cdd2011-09-20 17:00:20 +0530626 list_for_each_entry(timer, &omap_timer_list, node) {
Tarun Kanti DebBarmaffe07ce2011-09-20 17:00:21 +0530627 if (!timer->reserved)
Timo Teras12583a72006-09-25 12:41:42 +0300628 continue;
629
Timo Teras77900a22006-06-26 16:16:12 -0700630 if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
Timo Terasfa4bb622006-09-25 12:41:35 +0300631 OMAP_TIMER_CTRL_ST) {
Timo Teras77900a22006-06-26 16:16:12 -0700632 return 1;
Timo Terasfa4bb622006-09-25 12:41:35 +0300633 }
Tony Lindgren92105bb2005-09-07 17:20:26 +0100634 }
Tony Lindgren92105bb2005-09-07 17:20:26 +0100635 return 0;
636}
Timo Kokkonen6c366e32009-03-23 18:07:46 -0700637EXPORT_SYMBOL_GPL(omap_dm_timers_active);
Tony Lindgren92105bb2005-09-07 17:20:26 +0100638
Tarun Kanti DebBarmadf284722011-09-20 17:00:19 +0530639/**
640 * omap_dm_timer_probe - probe function called for every registered device
641 * @pdev: pointer to current timer platform device
642 *
643 * Called by driver framework at the end of device registration for all
644 * timer devices.
645 */
646static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
647{
648 int ret;
649 unsigned long flags;
650 struct omap_dm_timer *timer;
651 struct resource *mem, *irq, *ioarea;
652 struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
653
654 if (!pdata) {
655 dev_err(&pdev->dev, "%s: no platform data.\n", __func__);
656 return -ENODEV;
657 }
658
659 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
660 if (unlikely(!irq)) {
661 dev_err(&pdev->dev, "%s: no IRQ resource.\n", __func__);
662 return -ENODEV;
663 }
664
665 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
666 if (unlikely(!mem)) {
667 dev_err(&pdev->dev, "%s: no memory resource.\n", __func__);
668 return -ENODEV;
669 }
670
671 ioarea = request_mem_region(mem->start, resource_size(mem),
672 pdev->name);
673 if (!ioarea) {
674 dev_err(&pdev->dev, "%s: region already claimed.\n", __func__);
675 return -EBUSY;
676 }
677
678 timer = kzalloc(sizeof(struct omap_dm_timer), GFP_KERNEL);
679 if (!timer) {
680 dev_err(&pdev->dev, "%s: no memory for omap_dm_timer.\n",
681 __func__);
682 ret = -ENOMEM;
683 goto err_free_ioregion;
684 }
685
686 timer->io_base = ioremap(mem->start, resource_size(mem));
687 if (!timer->io_base) {
688 dev_err(&pdev->dev, "%s: ioremap failed.\n", __func__);
689 ret = -ENOMEM;
690 goto err_free_mem;
691 }
692
693 timer->id = pdev->id;
694 timer->irq = irq->start;
Jon Hunterb7b4ff72012-06-05 12:34:51 -0500695 timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
Tarun Kanti DebBarmadf284722011-09-20 17:00:19 +0530696 timer->pdev = pdev;
Jon Hunterd1c16912012-06-05 12:34:52 -0500697 timer->capability = pdata->timer_capability;
Tarun Kanti DebBarmadf284722011-09-20 17:00:19 +0530698
Tarun Kanti DebBarmaffe07ce2011-09-20 17:00:21 +0530699 /* Skip pm_runtime_enable for OMAP1 */
Jon Hunter66159752012-06-05 12:34:57 -0500700 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
Tarun Kanti DebBarmaffe07ce2011-09-20 17:00:21 +0530701 pm_runtime_enable(&pdev->dev);
702 pm_runtime_irq_safe(&pdev->dev);
703 }
704
Tony Lindgren0dad9fa2011-09-21 16:38:51 -0700705 if (!timer->reserved) {
706 pm_runtime_get_sync(&pdev->dev);
707 __omap_dm_timer_init_regs(timer);
708 pm_runtime_put(&pdev->dev);
709 }
710
Tarun Kanti DebBarmadf284722011-09-20 17:00:19 +0530711 /* add the timer element to the list */
712 spin_lock_irqsave(&dm_timer_lock, flags);
713 list_add_tail(&timer->node, &omap_timer_list);
714 spin_unlock_irqrestore(&dm_timer_lock, flags);
715
716 dev_dbg(&pdev->dev, "Device Probed.\n");
717
718 return 0;
719
720err_free_mem:
721 kfree(timer);
722
723err_free_ioregion:
724 release_mem_region(mem->start, resource_size(mem));
725
726 return ret;
727}
728
729/**
730 * omap_dm_timer_remove - cleanup a registered timer device
731 * @pdev: pointer to current timer platform device
732 *
733 * Called by driver framework whenever a timer device is unregistered.
734 * In addition to freeing platform resources it also deletes the timer
735 * entry from the local list.
736 */
737static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
738{
739 struct omap_dm_timer *timer;
740 unsigned long flags;
741 int ret = -EINVAL;
742
743 spin_lock_irqsave(&dm_timer_lock, flags);
744 list_for_each_entry(timer, &omap_timer_list, node)
745 if (timer->pdev->id == pdev->id) {
746 list_del(&timer->node);
747 kfree(timer);
748 ret = 0;
749 break;
750 }
751 spin_unlock_irqrestore(&dm_timer_lock, flags);
752
753 return ret;
754}
755
756static struct platform_driver omap_dm_timer_driver = {
757 .probe = omap_dm_timer_probe,
Arnd Bergmann4c23c8d2011-10-01 18:42:47 +0200758 .remove = __devexit_p(omap_dm_timer_remove),
Tarun Kanti DebBarmadf284722011-09-20 17:00:19 +0530759 .driver = {
760 .name = "omap_timer",
761 },
762};
763
764static int __init omap_dm_timer_driver_init(void)
765{
766 return platform_driver_register(&omap_dm_timer_driver);
767}
768
769static void __exit omap_dm_timer_driver_exit(void)
770{
771 platform_driver_unregister(&omap_dm_timer_driver);
772}
773
774early_platform_init("earlytimer", &omap_dm_timer_driver);
775module_init(omap_dm_timer_driver_init);
776module_exit(omap_dm_timer_driver_exit);
777
778MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
779MODULE_LICENSE("GPL");
780MODULE_ALIAS("platform:" DRIVER_NAME);
781MODULE_AUTHOR("Texas Instruments Inc");