dmtimer.c 18.5 KB
Newer Older
1 2 3 4 5
/*
 * linux/arch/arm/plat-omap/dmtimer.c
 *
 * OMAP Dual-Mode Timers
 *
6 7 8 9 10 11
 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
 * Tarun Kanti DebBarma <tarun.kanti@ti.com>
 * Thara Gopinath <thara@ti.com>
 *
 * dmtimer adaptation to platform_driver.
 *
12
 * Copyright (C) 2005 Nokia Corporation
13 14
 * OMAP2 support by Juha Yrjola
 * API improvements and OMAP2 clock framework support by Timo Teras
15
 *
16 17 18
 * Copyright (C) 2009 Texas Instruments
 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
 *
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * You should have received a copy of the  GNU General Public License along
 * with this program; if not, write  to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 */

38
#include <linux/io.h>
39
#include <linux/slab.h>
40
#include <linux/err.h>
41
#include <linux/pm_runtime.h>
42

43
#include <plat/dmtimer.h>
44

45
static LIST_HEAD(omap_timer_list);
46
static DEFINE_SPINLOCK(dm_timer_lock);
47

48 49 50 51 52 53 54 55
/**
 * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
 * @timer:      timer pointer over which read operation to perform
 * @reg:        lowest byte holds the register offset
 *
 * The posted mode bit is encoded in reg. Note that in posted mode write
 * pending bit must be checked. Otherwise a read of a non completed write
 * will produce an error.
56 57
 */
static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
58
{
59 60
	WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
	return __omap_dm_timer_read(timer, reg, timer->posted);
61
}
62

63 64 65 66 67 68 69 70 71
/**
 * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
 * @timer:      timer pointer over which write operation is to perform
 * @reg:        lowest byte holds the register offset
 * @value:      data to write into the register
 *
 * The posted mode bit is encoded in reg. Note that in posted mode the write
 * pending bit must be checked. Otherwise a write on a register which has a
 * pending write will be lost.
72 73 74
 */
static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
						u32 value)
75
{
76 77
	WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
	__omap_dm_timer_write(timer, reg, value, timer->posted);
78 79
}

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
static void omap_timer_restore_context(struct omap_dm_timer *timer)
{
	omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_OFFSET,
				timer->context.tiocp_cfg);
	if (timer->revision > 1)
		__raw_writel(timer->context.tistat, timer->sys_stat);

	__raw_writel(timer->context.tisr, timer->irq_stat);
	omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
				timer->context.twer);
	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
				timer->context.tcrr);
	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
				timer->context.tldr);
	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
				timer->context.tmar);
	omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
				timer->context.tsicr);
	__raw_writel(timer->context.tier, timer->irq_ena);
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
				timer->context.tclr);
}

103
static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
104
{
105 106
	int c;

107 108 109
	if (!timer->sys_stat)
		return;

110
	c = 0;
111
	while (!(__raw_readl(timer->sys_stat) & 1)) {
112 113 114 115 116 117
		c++;
		if (c > 100000) {
			printk(KERN_ERR "Timer failed to reset\n");
			return;
		}
	}
118 119
}

120 121
static void omap_dm_timer_reset(struct omap_dm_timer *timer)
{
122
	omap_dm_timer_enable(timer);
123
	if (timer->pdev->id != 1) {
124 125 126
		omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
		omap_dm_timer_wait_for_reset(timer);
	}
127

128
	__omap_dm_timer_reset(timer, 0, 0);
129
	omap_dm_timer_disable(timer);
130
	timer->posted = 1;
131 132
}

133
int omap_dm_timer_prepare(struct omap_dm_timer *timer)
134
{
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
	int ret;

	timer->fclk = clk_get(&timer->pdev->dev, "fck");
	if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
		timer->fclk = NULL;
		dev_err(&timer->pdev->dev, ": No fclk handle.\n");
		return -EINVAL;
	}

	if (pdata->needs_manual_reset)
		omap_dm_timer_reset(timer);

	ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);

	timer->posted = 1;
	return ret;
152 153 154 155
}

struct omap_dm_timer *omap_dm_timer_request(void)
{
156
	struct omap_dm_timer *timer = NULL, *t;
157
	unsigned long flags;
158
	int ret = 0;
159 160

	spin_lock_irqsave(&dm_timer_lock, flags);
161 162
	list_for_each_entry(t, &omap_timer_list, node) {
		if (t->reserved)
163 164
			continue;

165
		timer = t;
T
Timo Teras 已提交
166
		timer->reserved = 1;
167 168
		break;
	}
169 170 171 172 173 174 175 176

	if (timer) {
		ret = omap_dm_timer_prepare(timer);
		if (ret) {
			timer->reserved = 0;
			timer = NULL;
		}
	}
177 178
	spin_unlock_irqrestore(&dm_timer_lock, flags);

179 180
	if (!timer)
		pr_debug("%s: timer request failed!\n", __func__);
T
Timo Teras 已提交
181

182 183
	return timer;
}
184
EXPORT_SYMBOL_GPL(omap_dm_timer_request);
185 186

struct omap_dm_timer *omap_dm_timer_request_specific(int id)
187
{
188
	struct omap_dm_timer *timer = NULL, *t;
189
	unsigned long flags;
190
	int ret = 0;
191

192
	spin_lock_irqsave(&dm_timer_lock, flags);
193 194 195 196 197 198
	list_for_each_entry(t, &omap_timer_list, node) {
		if (t->pdev->id == id && !t->reserved) {
			timer = t;
			timer->reserved = 1;
			break;
		}
199
	}
200

201 202 203 204 205 206 207
	if (timer) {
		ret = omap_dm_timer_prepare(timer);
		if (ret) {
			timer->reserved = 0;
			timer = NULL;
		}
	}
208 209
	spin_unlock_irqrestore(&dm_timer_lock, flags);

210 211
	if (!timer)
		pr_debug("%s: timer%d request failed!\n", __func__, id);
T
Timo Teras 已提交
212

213
	return timer;
214
}
215
EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
216

217
int omap_dm_timer_free(struct omap_dm_timer *timer)
218
{
219 220 221
	if (unlikely(!timer))
		return -EINVAL;

222
	clk_put(timer->fclk);
223

224 225
	WARN_ON(!timer->reserved);
	timer->reserved = 0;
226
	return 0;
227
}
228
EXPORT_SYMBOL_GPL(omap_dm_timer_free);
229

230 231
void omap_dm_timer_enable(struct omap_dm_timer *timer)
{
232
	pm_runtime_get_sync(&timer->pdev->dev);
233
}
234
EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
235 236 237

void omap_dm_timer_disable(struct omap_dm_timer *timer)
{
238
	pm_runtime_put(&timer->pdev->dev);
239
}
240
EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
241

242 243
int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
{
244 245 246
	if (timer)
		return timer->irq;
	return -EINVAL;
247
}
248
EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
249 250 251

#if defined(CONFIG_ARCH_OMAP1)

252 253 254 255 256 257
/**
 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
 * @inputmask: current value of idlect mask
 */
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
{
258 259 260
	int i = 0;
	struct omap_dm_timer *timer = NULL;
	unsigned long flags;
261 262 263 264 265 266

	/* If ARMXOR cannot be idled this function call is unnecessary */
	if (!(inputmask & (1 << 1)))
		return inputmask;

	/* If any active timer is using ARMXOR return modified mask */
267 268
	spin_lock_irqsave(&dm_timer_lock, flags);
	list_for_each_entry(timer, &omap_timer_list, node) {
269 270
		u32 l;

271
		l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
272 273
		if (l & OMAP_TIMER_CTRL_ST) {
			if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
274 275 276 277
				inputmask &= ~(1 << 1);
			else
				inputmask &= ~(1 << 2);
		}
278
		i++;
279
	}
280
	spin_unlock_irqrestore(&dm_timer_lock, flags);
281 282 283

	return inputmask;
}
284
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
285

286
#else
287

288
struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
289
{
290 291 292
	if (timer)
		return timer->fclk;
	return NULL;
293
}
294
EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
295

296 297 298
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
{
	BUG();
299 300

	return 0;
301
}
302
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
303

304
#endif
305

306
int omap_dm_timer_trigger(struct omap_dm_timer *timer)
307
{
308 309 310
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
		return -EINVAL;
311 312
	}

313
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
314
	return 0;
315
}
316
EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
317

318
int omap_dm_timer_start(struct omap_dm_timer *timer)
319 320
{
	u32 l;
321

322 323 324
	if (unlikely(!timer))
		return -EINVAL;

325 326 327 328 329 330 331 332 333
	omap_dm_timer_enable(timer);

	if (timer->loses_context) {
		u32 ctx_loss_cnt_after =
			timer->get_context_loss_count(&timer->pdev->dev);
		if (ctx_loss_cnt_after != timer->ctx_loss_count)
			omap_timer_restore_context(timer);
	}

334 335 336 337 338
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
	if (!(l & OMAP_TIMER_CTRL_ST)) {
		l |= OMAP_TIMER_CTRL_ST;
		omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
	}
339 340 341

	/* Save the context */
	timer->context.tclr = l;
342
	return 0;
343
}
344
EXPORT_SYMBOL_GPL(omap_dm_timer_start);
345

346
int omap_dm_timer_stop(struct omap_dm_timer *timer)
347
{
348
	unsigned long rate = 0;
349
	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
350

351 352 353
	if (unlikely(!timer))
		return -EINVAL;

354 355
	if (!pdata->needs_manual_reset)
		rate = clk_get_rate(timer->fclk);
356

357
	__omap_dm_timer_stop(timer, timer->posted, rate);
358 359

	return 0;
360
}
361
EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
362

363
int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
364
{
365
	int ret;
366 367 368 369 370 371
	struct dmtimer_platform_data *pdata;

	if (unlikely(!timer))
		return -EINVAL;

	pdata = timer->pdev->dev.platform_data;
372

373
	if (source < 0 || source >= 3)
374
		return -EINVAL;
375

376 377 378
	ret = pdata->set_timer_src(timer->pdev, source);

	return ret;
379
}
380
EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
381

382
int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
383
			    unsigned int load)
384 385
{
	u32 l;
386

387 388 389
	if (unlikely(!timer))
		return -EINVAL;

390
	omap_dm_timer_enable(timer);
391
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
392 393 394 395
	if (autoreload)
		l |= OMAP_TIMER_CTRL_AR;
	else
		l &= ~OMAP_TIMER_CTRL_AR;
396
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
397
	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
398

399
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
400 401 402 403
	/* Save the context */
	timer->context.tclr = l;
	timer->context.tldr = load;
	omap_dm_timer_disable(timer);
404
	return 0;
405
}
406
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
407

408
/* Optimized set_load which removes costly spin wait in timer_start */
409
int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
410 411 412 413
                            unsigned int load)
{
	u32 l;

414 415 416
	if (unlikely(!timer))
		return -EINVAL;

417 418 419 420 421 422 423 424 425
	omap_dm_timer_enable(timer);

	if (timer->loses_context) {
		u32 ctx_loss_cnt_after =
			timer->get_context_loss_count(&timer->pdev->dev);
		if (ctx_loss_cnt_after != timer->ctx_loss_count)
			omap_timer_restore_context(timer);
	}

426
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
427
	if (autoreload) {
428
		l |= OMAP_TIMER_CTRL_AR;
429 430
		omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
	} else {
431
		l &= ~OMAP_TIMER_CTRL_AR;
432
	}
433 434
	l |= OMAP_TIMER_CTRL_ST;

435
	__omap_dm_timer_load_start(timer, l, load, timer->posted);
436 437 438 439 440

	/* Save the context */
	timer->context.tclr = l;
	timer->context.tldr = load;
	timer->context.tcrr = load;
441
	return 0;
442
}
443
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
444

445
int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
446
			     unsigned int match)
447 448 449
{
	u32 l;

450 451 452
	if (unlikely(!timer))
		return -EINVAL;

453
	omap_dm_timer_enable(timer);
454
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
T
Timo Teras 已提交
455
	if (enable)
456 457 458
		l |= OMAP_TIMER_CTRL_CE;
	else
		l &= ~OMAP_TIMER_CTRL_CE;
459
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
460
	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
461 462 463 464 465

	/* Save the context */
	timer->context.tclr = l;
	timer->context.tmar = match;
	omap_dm_timer_disable(timer);
466
	return 0;
467
}
468
EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
469

470
int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
471
			   int toggle, int trigger)
472 473 474
{
	u32 l;

475 476 477
	if (unlikely(!timer))
		return -EINVAL;

478
	omap_dm_timer_enable(timer);
479
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
480 481 482 483 484 485 486
	l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
	       OMAP_TIMER_CTRL_PT | (0x03 << 10));
	if (def_on)
		l |= OMAP_TIMER_CTRL_SCPWM;
	if (toggle)
		l |= OMAP_TIMER_CTRL_PT;
	l |= trigger << 10;
487
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
488 489 490 491

	/* Save the context */
	timer->context.tclr = l;
	omap_dm_timer_disable(timer);
492
	return 0;
493
}
494
EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
495

496
int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
497 498 499
{
	u32 l;

500 501 502
	if (unlikely(!timer))
		return -EINVAL;

503
	omap_dm_timer_enable(timer);
504
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
505 506 507 508 509
	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
	if (prescaler >= 0x00 && prescaler <= 0x07) {
		l |= OMAP_TIMER_CTRL_PRE;
		l |= prescaler << 2;
	}
510
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
511 512 513 514

	/* Save the context */
	timer->context.tclr = l;
	omap_dm_timer_disable(timer);
515
	return 0;
516
}
517
EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
518

519
int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
520
				  unsigned int value)
521
{
522 523 524
	if (unlikely(!timer))
		return -EINVAL;

525
	omap_dm_timer_enable(timer);
526
	__omap_dm_timer_int_enable(timer, value);
527 528 529 530 531

	/* Save the context */
	timer->context.tier = value;
	timer->context.twer = value;
	omap_dm_timer_disable(timer);
532
	return 0;
533
}
534
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
535

536
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
537
{
538 539
	unsigned int l;

540 541
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
542 543 544
		return 0;
	}

545
	l = __raw_readl(timer->irq_stat);
546 547

	return l;
548
}
549
EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
550

551
int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
552
{
553 554 555
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
		return -EINVAL;

556
	__omap_dm_timer_write_status(timer, value);
557 558
	/* Save the context */
	timer->context.tisr = value;
559
	return 0;
560
}
561
EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
562

563
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
564
{
565 566
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not iavailable or enabled.\n", __func__);
567 568 569
		return 0;
	}

570
	return __omap_dm_timer_read_counter(timer, timer->posted);
571
}
572
EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
573

574
int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
T
Timo Teras 已提交
575
{
576 577 578
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
		return -EINVAL;
579 580
	}

581
	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
582 583 584

	/* Save the context */
	timer->context.tcrr = value;
585
	return 0;
T
Timo Teras 已提交
586
}
587
EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
T
Timo Teras 已提交
588

589
int omap_dm_timers_active(void)
590
{
591
	struct omap_dm_timer *timer;
592

593
	list_for_each_entry(timer, &omap_timer_list, node) {
594
		if (!timer->reserved)
595 596
			continue;

597
		if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
598
		    OMAP_TIMER_CTRL_ST) {
599
			return 1;
600
		}
601 602 603
	}
	return 0;
}
604
EXPORT_SYMBOL_GPL(omap_dm_timers_active);
605

606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
/**
 * omap_dm_timer_probe - probe function called for every registered device
 * @pdev:	pointer to current timer platform device
 *
 * Called by driver framework at the end of device registration for all
 * timer devices.
 */
static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
{
	int ret;
	unsigned long flags;
	struct omap_dm_timer *timer;
	struct resource *mem, *irq, *ioarea;
	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;

	if (!pdata) {
		dev_err(&pdev->dev, "%s: no platform data.\n", __func__);
		return -ENODEV;
	}

	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (unlikely(!irq)) {
		dev_err(&pdev->dev, "%s: no IRQ resource.\n", __func__);
		return -ENODEV;
	}

	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (unlikely(!mem)) {
		dev_err(&pdev->dev, "%s: no memory resource.\n", __func__);
		return -ENODEV;
	}

	ioarea = request_mem_region(mem->start, resource_size(mem),
			pdev->name);
	if (!ioarea) {
		dev_err(&pdev->dev, "%s: region already claimed.\n", __func__);
		return -EBUSY;
	}

	timer = kzalloc(sizeof(struct omap_dm_timer), GFP_KERNEL);
	if (!timer) {
		dev_err(&pdev->dev, "%s: no memory for omap_dm_timer.\n",
			__func__);
		ret = -ENOMEM;
		goto err_free_ioregion;
	}

	timer->io_base = ioremap(mem->start, resource_size(mem));
	if (!timer->io_base) {
		dev_err(&pdev->dev, "%s: ioremap failed.\n", __func__);
		ret = -ENOMEM;
		goto err_free_mem;
	}

	timer->id = pdev->id;
	timer->irq = irq->start;
662
	timer->reserved = pdata->reserved;
663
	timer->pdev = pdev;
664 665
	timer->loses_context = pdata->loses_context;
	timer->get_context_loss_count = pdata->get_context_loss_count;
666

667 668 669 670 671 672
	/* Skip pm_runtime_enable for OMAP1 */
	if (!pdata->needs_manual_reset) {
		pm_runtime_enable(&pdev->dev);
		pm_runtime_irq_safe(&pdev->dev);
	}

673 674 675 676 677 678
	if (!timer->reserved) {
		pm_runtime_get_sync(&pdev->dev);
		__omap_dm_timer_init_regs(timer);
		pm_runtime_put(&pdev->dev);
	}

679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
	/* add the timer element to the list */
	spin_lock_irqsave(&dm_timer_lock, flags);
	list_add_tail(&timer->node, &omap_timer_list);
	spin_unlock_irqrestore(&dm_timer_lock, flags);

	dev_dbg(&pdev->dev, "Device Probed.\n");

	return 0;

err_free_mem:
	kfree(timer);

err_free_ioregion:
	release_mem_region(mem->start, resource_size(mem));

	return ret;
}

/**
 * omap_dm_timer_remove - cleanup a registered timer device
 * @pdev:	pointer to current timer platform device
 *
 * Called by driver framework whenever a timer device is unregistered.
 * In addition to freeing platform resources it also deletes the timer
 * entry from the local list.
 */
static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
{
	struct omap_dm_timer *timer;
	unsigned long flags;
	int ret = -EINVAL;

	spin_lock_irqsave(&dm_timer_lock, flags);
	list_for_each_entry(timer, &omap_timer_list, node)
		if (timer->pdev->id == pdev->id) {
			list_del(&timer->node);
			kfree(timer);
			ret = 0;
			break;
		}
	spin_unlock_irqrestore(&dm_timer_lock, flags);

	return ret;
}

static struct platform_driver omap_dm_timer_driver = {
	.probe  = omap_dm_timer_probe,
726
	.remove = __devexit_p(omap_dm_timer_remove),
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
	.driver = {
		.name   = "omap_timer",
	},
};

static int __init omap_dm_timer_driver_init(void)
{
	return platform_driver_register(&omap_dm_timer_driver);
}

static void __exit omap_dm_timer_driver_exit(void)
{
	platform_driver_unregister(&omap_dm_timer_driver);
}

early_platform_init("earlytimer", &omap_dm_timer_driver);
module_init(omap_dm_timer_driver_init);
module_exit(omap_dm_timer_driver_exit);

MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_AUTHOR("Texas Instruments Inc");