dmtimer.c 18.9 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/module.h>
39
#include <linux/io.h>
40
#include <linux/slab.h>
41
#include <linux/err.h>
42
#include <linux/pm_runtime.h>
43

44
#include <plat/dmtimer.h>
45

46 47
#include <mach/hardware.h>

48
static LIST_HEAD(omap_timer_list);
49
static DEFINE_SPINLOCK(dm_timer_lock);
50

51 52 53 54 55 56 57 58
/**
 * 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.
59 60
 */
static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
61
{
62 63
	WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
	return __omap_dm_timer_read(timer, reg, timer->posted);
64
}
65

66 67 68 69 70 71 72 73 74
/**
 * 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.
75 76 77
 */
static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
						u32 value)
78
{
79 80
	WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
	__omap_dm_timer_write(timer, reg, value, timer->posted);
81 82
}

83 84
static void omap_timer_restore_context(struct omap_dm_timer *timer)
{
85
	if (timer->revision == 1)
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
		__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);
}

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

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

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

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

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

134
int omap_dm_timer_prepare(struct omap_dm_timer *timer)
135
{
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
	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;
153 154 155 156
}

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

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

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

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

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

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

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

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

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

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

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

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

223
	clk_put(timer->fclk);
224

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

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

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

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

#if defined(CONFIG_ARCH_OMAP1)

253 254 255 256 257 258
/**
 * 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)
{
259 260 261
	int i = 0;
	struct omap_dm_timer *timer = NULL;
	unsigned long flags;
262 263 264 265 266 267

	/* 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 */
268 269
	spin_lock_irqsave(&dm_timer_lock, flags);
	list_for_each_entry(timer, &omap_timer_list, node) {
270 271
		u32 l;

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

	return inputmask;
}
285
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
286

287
#else
288

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

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

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

305
#endif
306

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

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

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

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

326 327 328 329 330 331 332 333 334
	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);
	}

335 336 337 338 339
	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);
	}
340 341 342

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

347
int omap_dm_timer_stop(struct omap_dm_timer *timer)
348
{
349
	unsigned long rate = 0;
350
	struct dmtimer_platform_data *pdata;
351

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

355
	pdata = timer->pdev->dev.platform_data;
356 357
	if (!pdata->needs_manual_reset)
		rate = clk_get_rate(timer->fclk);
358

359
	__omap_dm_timer_stop(timer, timer->posted, rate);
360

361 362 363 364 365 366 367 368 369 370 371 372 373
	if (timer->loses_context && timer->get_context_loss_count)
		timer->ctx_loss_count =
			timer->get_context_loss_count(&timer->pdev->dev);

	/*
	 * Since the register values are computed and written within
	 * __omap_dm_timer_stop, we need to use read to retrieve the
	 * context.
	 */
	timer->context.tclr =
			omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
	timer->context.tisr = __raw_readl(timer->irq_stat);
	omap_dm_timer_disable(timer);
374
	return 0;
375
}
376
EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
377

378
int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
379
{
380
	int ret;
381 382 383 384 385 386
	struct dmtimer_platform_data *pdata;

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

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

388
	if (source < 0 || source >= 3)
389
		return -EINVAL;
390

391 392 393
	ret = pdata->set_timer_src(timer->pdev, source);

	return ret;
394
}
395
EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
396

397
int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
398
			    unsigned int load)
399 400
{
	u32 l;
401

402 403 404
	if (unlikely(!timer))
		return -EINVAL;

405
	omap_dm_timer_enable(timer);
406
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
407 408 409 410
	if (autoreload)
		l |= OMAP_TIMER_CTRL_AR;
	else
		l &= ~OMAP_TIMER_CTRL_AR;
411
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
412
	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
413

414
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
415 416 417 418
	/* Save the context */
	timer->context.tclr = l;
	timer->context.tldr = load;
	omap_dm_timer_disable(timer);
419
	return 0;
420
}
421
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
422

423
/* Optimized set_load which removes costly spin wait in timer_start */
424
int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
425 426 427 428
                            unsigned int load)
{
	u32 l;

429 430 431
	if (unlikely(!timer))
		return -EINVAL;

432 433 434 435 436 437 438 439 440
	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);
	}

441
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
442
	if (autoreload) {
443
		l |= OMAP_TIMER_CTRL_AR;
444 445
		omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
	} else {
446
		l &= ~OMAP_TIMER_CTRL_AR;
447
	}
448 449
	l |= OMAP_TIMER_CTRL_ST;

450
	__omap_dm_timer_load_start(timer, l, load, timer->posted);
451 452 453 454 455

	/* Save the context */
	timer->context.tclr = l;
	timer->context.tldr = load;
	timer->context.tcrr = load;
456
	return 0;
457
}
458
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
459

460
int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
461
			     unsigned int match)
462 463 464
{
	u32 l;

465 466 467
	if (unlikely(!timer))
		return -EINVAL;

468
	omap_dm_timer_enable(timer);
469
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
T
Timo Teras 已提交
470
	if (enable)
471 472 473
		l |= OMAP_TIMER_CTRL_CE;
	else
		l &= ~OMAP_TIMER_CTRL_CE;
474
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
475
	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
476 477 478 479 480

	/* Save the context */
	timer->context.tclr = l;
	timer->context.tmar = match;
	omap_dm_timer_disable(timer);
481
	return 0;
482
}
483
EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
484

485
int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
486
			   int toggle, int trigger)
487 488 489
{
	u32 l;

490 491 492
	if (unlikely(!timer))
		return -EINVAL;

493
	omap_dm_timer_enable(timer);
494
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
495 496 497 498 499 500 501
	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;
502
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
503 504 505 506

	/* Save the context */
	timer->context.tclr = l;
	omap_dm_timer_disable(timer);
507
	return 0;
508
}
509
EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
510

511
int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
512 513 514
{
	u32 l;

515 516 517
	if (unlikely(!timer))
		return -EINVAL;

518
	omap_dm_timer_enable(timer);
519
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
520 521 522 523 524
	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
	if (prescaler >= 0x00 && prescaler <= 0x07) {
		l |= OMAP_TIMER_CTRL_PRE;
		l |= prescaler << 2;
	}
525
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
526 527 528 529

	/* Save the context */
	timer->context.tclr = l;
	omap_dm_timer_disable(timer);
530
	return 0;
531
}
532
EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
533

534
int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
535
				  unsigned int value)
536
{
537 538 539
	if (unlikely(!timer))
		return -EINVAL;

540
	omap_dm_timer_enable(timer);
541
	__omap_dm_timer_int_enable(timer, value);
542 543 544 545 546

	/* Save the context */
	timer->context.tier = value;
	timer->context.twer = value;
	omap_dm_timer_disable(timer);
547
	return 0;
548
}
549
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
550

551
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
552
{
553 554
	unsigned int l;

555 556
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
557 558 559
		return 0;
	}

560
	l = __raw_readl(timer->irq_stat);
561 562

	return l;
563
}
564
EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
565

566
int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
567
{
568 569 570
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
		return -EINVAL;

571
	__omap_dm_timer_write_status(timer, value);
572 573
	/* Save the context */
	timer->context.tisr = value;
574
	return 0;
575
}
576
EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
577

578
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
579
{
580 581
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not iavailable or enabled.\n", __func__);
582 583 584
		return 0;
	}

585
	return __omap_dm_timer_read_counter(timer, timer->posted);
586
}
587
EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
588

589
int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
T
Timo Teras 已提交
590
{
591 592 593
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
		return -EINVAL;
594 595
	}

596
	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
597 598 599

	/* Save the context */
	timer->context.tcrr = value;
600
	return 0;
T
Timo Teras 已提交
601
}
602
EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
T
Timo Teras 已提交
603

604
int omap_dm_timers_active(void)
605
{
606
	struct omap_dm_timer *timer;
607

608
	list_for_each_entry(timer, &omap_timer_list, node) {
609
		if (!timer->reserved)
610 611
			continue;

612
		if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
613
		    OMAP_TIMER_CTRL_ST) {
614
			return 1;
615
		}
616 617 618
	}
	return 0;
}
619
EXPORT_SYMBOL_GPL(omap_dm_timers_active);
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 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676
/**
 * 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;
677
	timer->reserved = pdata->reserved;
678
	timer->pdev = pdev;
679 680
	timer->loses_context = pdata->loses_context;
	timer->get_context_loss_count = pdata->get_context_loss_count;
681

682 683 684 685 686 687
	/* Skip pm_runtime_enable for OMAP1 */
	if (!pdata->needs_manual_reset) {
		pm_runtime_enable(&pdev->dev);
		pm_runtime_irq_safe(&pdev->dev);
	}

688 689 690 691 692 693
	if (!timer->reserved) {
		pm_runtime_get_sync(&pdev->dev);
		__omap_dm_timer_init_regs(timer);
		pm_runtime_put(&pdev->dev);
	}

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 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
	/* 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,
741
	.remove = __devexit_p(omap_dm_timer_remove),
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
	.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");