dmtimer.c 20.0 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/device.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 u32 omap_reserved_systimers;
49
static LIST_HEAD(omap_timer_list);
50
static DEFINE_SPINLOCK(dm_timer_lock);
51

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

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

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

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

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

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

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

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

135
int omap_dm_timer_prepare(struct omap_dm_timer *timer)
136
{
137 138
	int ret;

J
Jon Hunter 已提交
139 140 141 142 143 144 145 146 147 148 149
	/*
	 * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
	 * do not call clk_get() for these devices.
	 */
	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
		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;
		}
150 151
	}

152
	if (timer->capability & OMAP_TIMER_NEEDS_RESET)
153 154 155 156 157 158
		omap_dm_timer_reset(timer);

	ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);

	timer->posted = 1;
	return ret;
159 160
}

161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
static inline u32 omap_dm_timer_reserved_systimer(int id)
{
	return (omap_reserved_systimers & (1 << (id - 1))) ? 1 : 0;
}

int omap_dm_timer_reserve_systimer(int id)
{
	if (omap_dm_timer_reserved_systimer(id))
		return -ENODEV;

	omap_reserved_systimers |= (1 << (id - 1));

	return 0;
}

176 177
struct omap_dm_timer *omap_dm_timer_request(void)
{
178
	struct omap_dm_timer *timer = NULL, *t;
179
	unsigned long flags;
180
	int ret = 0;
181 182

	spin_lock_irqsave(&dm_timer_lock, flags);
183 184
	list_for_each_entry(t, &omap_timer_list, node) {
		if (t->reserved)
185 186
			continue;

187
		timer = t;
T
Timo Teras 已提交
188
		timer->reserved = 1;
189 190
		break;
	}
191
	spin_unlock_irqrestore(&dm_timer_lock, flags);
192 193 194 195 196 197 198 199

	if (timer) {
		ret = omap_dm_timer_prepare(timer);
		if (ret) {
			timer->reserved = 0;
			timer = NULL;
		}
	}
200

201 202
	if (!timer)
		pr_debug("%s: timer request failed!\n", __func__);
T
Timo Teras 已提交
203

204 205
	return timer;
}
206
EXPORT_SYMBOL_GPL(omap_dm_timer_request);
207 208

struct omap_dm_timer *omap_dm_timer_request_specific(int id)
209
{
210
	struct omap_dm_timer *timer = NULL, *t;
211
	unsigned long flags;
212
	int ret = 0;
213

214
	spin_lock_irqsave(&dm_timer_lock, flags);
215 216 217 218 219 220
	list_for_each_entry(t, &omap_timer_list, node) {
		if (t->pdev->id == id && !t->reserved) {
			timer = t;
			timer->reserved = 1;
			break;
		}
221
	}
222
	spin_unlock_irqrestore(&dm_timer_lock, flags);
223

224 225 226 227 228 229 230
	if (timer) {
		ret = omap_dm_timer_prepare(timer);
		if (ret) {
			timer->reserved = 0;
			timer = NULL;
		}
	}
231

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

235
	return timer;
236
}
237
EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
238

239
int omap_dm_timer_free(struct omap_dm_timer *timer)
240
{
241 242 243
	if (unlikely(!timer))
		return -EINVAL;

244
	clk_put(timer->fclk);
245

246 247
	WARN_ON(!timer->reserved);
	timer->reserved = 0;
248
	return 0;
249
}
250
EXPORT_SYMBOL_GPL(omap_dm_timer_free);
251

252 253
void omap_dm_timer_enable(struct omap_dm_timer *timer)
{
254
	pm_runtime_get_sync(&timer->pdev->dev);
255
}
256
EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
257 258 259

void omap_dm_timer_disable(struct omap_dm_timer *timer)
{
260
	pm_runtime_put_sync(&timer->pdev->dev);
261
}
262
EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
263

264 265
int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
{
266 267 268
	if (timer)
		return timer->irq;
	return -EINVAL;
269
}
270
EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
271 272 273

#if defined(CONFIG_ARCH_OMAP1)

274 275 276 277 278 279
/**
 * 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)
{
280 281 282
	int i = 0;
	struct omap_dm_timer *timer = NULL;
	unsigned long flags;
283 284 285 286 287 288

	/* 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 */
289 290
	spin_lock_irqsave(&dm_timer_lock, flags);
	list_for_each_entry(timer, &omap_timer_list, node) {
291 292
		u32 l;

293
		l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
294 295
		if (l & OMAP_TIMER_CTRL_ST) {
			if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
296 297 298 299
				inputmask &= ~(1 << 1);
			else
				inputmask &= ~(1 << 2);
		}
300
		i++;
301
	}
302
	spin_unlock_irqrestore(&dm_timer_lock, flags);
303 304 305

	return inputmask;
}
306
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
307

308
#else
309

310
struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
311
{
312 313 314
	if (timer)
		return timer->fclk;
	return NULL;
315
}
316
EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
317

318 319 320
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
{
	BUG();
321 322

	return 0;
323
}
324
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
325

326
#endif
327

328
int omap_dm_timer_trigger(struct omap_dm_timer *timer)
329
{
330 331 332
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
		return -EINVAL;
333 334
	}

335
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
336
	return 0;
337
}
338
EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
339

340
int omap_dm_timer_start(struct omap_dm_timer *timer)
341 342
{
	u32 l;
343

344 345 346
	if (unlikely(!timer))
		return -EINVAL;

347 348
	omap_dm_timer_enable(timer);

349
	if (!(timer->capability & OMAP_TIMER_ALWON)) {
350 351
		if (timer->get_context_loss_count &&
			timer->get_context_loss_count(&timer->pdev->dev) !=
352
				timer->ctx_loss_count)
353 354 355
			omap_timer_restore_context(timer);
	}

356 357 358 359 360
	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);
	}
361 362 363

	/* Save the context */
	timer->context.tclr = l;
364
	return 0;
365
}
366
EXPORT_SYMBOL_GPL(omap_dm_timer_start);
367

368
int omap_dm_timer_stop(struct omap_dm_timer *timer)
369
{
370
	unsigned long rate = 0;
371

372 373 374
	if (unlikely(!timer))
		return -EINVAL;

375
	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
376
		rate = clk_get_rate(timer->fclk);
377

378
	__omap_dm_timer_stop(timer, timer->posted, rate);
379

380 381 382 383 384
	if (!(timer->capability & OMAP_TIMER_ALWON)) {
		if (timer->get_context_loss_count)
			timer->ctx_loss_count =
				timer->get_context_loss_count(&timer->pdev->dev);
	}
385 386 387 388 389 390 391 392 393 394

	/*
	 * 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);
395
	return 0;
396
}
397
EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
398

399
int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
400
{
401
	int ret;
402 403
	char *parent_name = NULL;
	struct clk *fclk, *parent;
404 405 406 407 408 409
	struct dmtimer_platform_data *pdata;

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

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

411
	if (source < 0 || source >= 3)
412
		return -EINVAL;
413

414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
	/*
	 * FIXME: Used for OMAP1 devices only because they do not currently
	 * use the clock framework to set the parent clock. To be removed
	 * once OMAP1 migrated to using clock framework for dmtimers
	 */
	if (pdata->set_timer_src)
		return pdata->set_timer_src(timer->pdev, source);

	fclk = clk_get(&timer->pdev->dev, "fck");
	if (IS_ERR_OR_NULL(fclk)) {
		pr_err("%s: fck not found\n", __func__);
		return -EINVAL;
	}

	switch (source) {
	case OMAP_TIMER_SRC_SYS_CLK:
430
		parent_name = "timer_sys_ck";
431 432 433
		break;

	case OMAP_TIMER_SRC_32_KHZ:
434
		parent_name = "timer_32k_ck";
435 436 437
		break;

	case OMAP_TIMER_SRC_EXT_CLK:
438
		parent_name = "timer_ext_ck";
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
		break;
	}

	parent = clk_get(&timer->pdev->dev, parent_name);
	if (IS_ERR_OR_NULL(parent)) {
		pr_err("%s: %s not found\n", __func__, parent_name);
		ret = -EINVAL;
		goto out;
	}

	ret = clk_set_parent(fclk, parent);
	if (IS_ERR_VALUE(ret))
		pr_err("%s: failed to set %s as parent\n", __func__,
			parent_name);

	clk_put(parent);
out:
	clk_put(fclk);
457 458

	return ret;
459
}
460
EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
461

462
int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
463
			    unsigned int load)
464 465
{
	u32 l;
466

467 468 469
	if (unlikely(!timer))
		return -EINVAL;

470
	omap_dm_timer_enable(timer);
471
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
472 473 474 475
	if (autoreload)
		l |= OMAP_TIMER_CTRL_AR;
	else
		l &= ~OMAP_TIMER_CTRL_AR;
476
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
477
	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
478

479
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
480 481 482 483
	/* Save the context */
	timer->context.tclr = l;
	timer->context.tldr = load;
	omap_dm_timer_disable(timer);
484
	return 0;
485
}
486
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
487

488
/* Optimized set_load which removes costly spin wait in timer_start */
489
int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
490 491 492 493
                            unsigned int load)
{
	u32 l;

494 495 496
	if (unlikely(!timer))
		return -EINVAL;

497 498
	omap_dm_timer_enable(timer);

499
	if (!(timer->capability & OMAP_TIMER_ALWON)) {
500 501
		if (timer->get_context_loss_count &&
			timer->get_context_loss_count(&timer->pdev->dev) !=
502
				timer->ctx_loss_count)
503 504 505
			omap_timer_restore_context(timer);
	}

506
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
507
	if (autoreload) {
508
		l |= OMAP_TIMER_CTRL_AR;
509 510
		omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
	} else {
511
		l &= ~OMAP_TIMER_CTRL_AR;
512
	}
513 514
	l |= OMAP_TIMER_CTRL_ST;

515
	__omap_dm_timer_load_start(timer, l, load, timer->posted);
516 517 518 519 520

	/* Save the context */
	timer->context.tclr = l;
	timer->context.tldr = load;
	timer->context.tcrr = load;
521
	return 0;
522
}
523
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
524

525
int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
526
			     unsigned int match)
527 528 529
{
	u32 l;

530 531 532
	if (unlikely(!timer))
		return -EINVAL;

533
	omap_dm_timer_enable(timer);
534
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
T
Timo Teras 已提交
535
	if (enable)
536 537 538
		l |= OMAP_TIMER_CTRL_CE;
	else
		l &= ~OMAP_TIMER_CTRL_CE;
539
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
540
	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
541 542 543 544 545

	/* Save the context */
	timer->context.tclr = l;
	timer->context.tmar = match;
	omap_dm_timer_disable(timer);
546
	return 0;
547
}
548
EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
549

550
int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
551
			   int toggle, int trigger)
552 553 554
{
	u32 l;

555 556 557
	if (unlikely(!timer))
		return -EINVAL;

558
	omap_dm_timer_enable(timer);
559
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
560 561 562 563 564 565 566
	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;
567
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
568 569 570 571

	/* Save the context */
	timer->context.tclr = l;
	omap_dm_timer_disable(timer);
572
	return 0;
573
}
574
EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
575

576
int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
577 578 579
{
	u32 l;

580 581 582
	if (unlikely(!timer))
		return -EINVAL;

583
	omap_dm_timer_enable(timer);
584
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
585 586 587 588 589
	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
	if (prescaler >= 0x00 && prescaler <= 0x07) {
		l |= OMAP_TIMER_CTRL_PRE;
		l |= prescaler << 2;
	}
590
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
591 592 593 594

	/* Save the context */
	timer->context.tclr = l;
	omap_dm_timer_disable(timer);
595
	return 0;
596
}
597
EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
598

599
int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
600
				  unsigned int value)
601
{
602 603 604
	if (unlikely(!timer))
		return -EINVAL;

605
	omap_dm_timer_enable(timer);
606
	__omap_dm_timer_int_enable(timer, value);
607 608 609 610 611

	/* Save the context */
	timer->context.tier = value;
	timer->context.twer = value;
	omap_dm_timer_disable(timer);
612
	return 0;
613
}
614
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
615

616
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
617
{
618 619
	unsigned int l;

620 621
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
622 623 624
		return 0;
	}

625
	l = __raw_readl(timer->irq_stat);
626 627

	return l;
628
}
629
EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
630

631
int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
632
{
633 634 635
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
		return -EINVAL;

636
	__omap_dm_timer_write_status(timer, value);
637 638
	/* Save the context */
	timer->context.tisr = value;
639
	return 0;
640
}
641
EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
642

643
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
644
{
645 646
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not iavailable or enabled.\n", __func__);
647 648 649
		return 0;
	}

650
	return __omap_dm_timer_read_counter(timer, timer->posted);
651
}
652
EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
653

654
int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
T
Timo Teras 已提交
655
{
656 657 658
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
		return -EINVAL;
659 660
	}

661
	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
662 663 664

	/* Save the context */
	timer->context.tcrr = value;
665
	return 0;
T
Timo Teras 已提交
666
}
667
EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
T
Timo Teras 已提交
668

669
int omap_dm_timers_active(void)
670
{
671
	struct omap_dm_timer *timer;
672

673
	list_for_each_entry(timer, &omap_timer_list, node) {
674
		if (!timer->reserved)
675 676
			continue;

677
		if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
678
		    OMAP_TIMER_CTRL_ST) {
679
			return 1;
680
		}
681 682 683
	}
	return 0;
}
684
EXPORT_SYMBOL_GPL(omap_dm_timers_active);
685

686 687 688 689 690 691 692 693 694 695 696
/**
 * 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)
{
	unsigned long flags;
	struct omap_dm_timer *timer;
697 698
	struct resource *mem, *irq;
	struct device *dev = &pdev->dev;
699 700 701
	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;

	if (!pdata) {
702
		dev_err(dev, "%s: no platform data.\n", __func__);
703 704 705 706 707
		return -ENODEV;
	}

	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (unlikely(!irq)) {
708
		dev_err(dev, "%s: no IRQ resource.\n", __func__);
709 710 711 712 713
		return -ENODEV;
	}

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

718
	timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL);
719
	if (!timer) {
720 721
		dev_err(dev, "%s: memory alloc failed!\n", __func__);
		return  -ENOMEM;
722 723
	}

724
	timer->io_base = devm_request_and_ioremap(dev, mem);
725
	if (!timer->io_base) {
726 727
		dev_err(dev, "%s: region already claimed.\n", __func__);
		return -ENOMEM;
728 729 730 731
	}

	timer->id = pdev->id;
	timer->irq = irq->start;
732
	timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
733
	timer->pdev = pdev;
734
	timer->capability = pdata->timer_capability;
735
	timer->get_context_loss_count = pdata->get_context_loss_count;
736

737
	/* Skip pm_runtime_enable for OMAP1 */
738
	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
739 740
		pm_runtime_enable(dev);
		pm_runtime_irq_safe(dev);
741 742
	}

743
	if (!timer->reserved) {
744
		pm_runtime_get_sync(dev);
745
		__omap_dm_timer_init_regs(timer);
746
		pm_runtime_put(dev);
747 748
	}

749 750 751 752 753
	/* 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);

754
	dev_dbg(dev, "Device Probed.\n");
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786

	return 0;
}

/**
 * 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);
			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,
787
	.remove = __devexit_p(omap_dm_timer_remove),
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
	.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");