dmtimer.c 23.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/clk.h>
39
#include <linux/module.h>
40
#include <linux/io.h>
41
#include <linux/device.h>
42
#include <linux/err.h>
43
#include <linux/pm_runtime.h>
44 45
#include <linux/of.h>
#include <linux/of_device.h>
46

47
#include <plat/dmtimer.h>
48

49
static u32 omap_reserved_systimers;
50
static LIST_HEAD(omap_timer_list);
51
static DEFINE_SPINLOCK(dm_timer_lock);
52

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

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

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

102
static int omap_dm_timer_reset(struct omap_dm_timer *timer)
103
{
104
	u32 l, timeout = 100000;
105

106 107
	if (timer->revision != 1)
		return -EINVAL;
108

109 110 111 112 113 114 115 116 117 118
	omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);

	do {
		l = __omap_dm_timer_read(timer,
					 OMAP_TIMER_V1_SYS_STAT_OFFSET, 0);
	} while (!l && timeout--);

	if (!timeout) {
		dev_err(&timer->pdev->dev, "Timer failed to reset\n");
		return -ETIMEDOUT;
119
	}
120

121 122 123 124 125 126 127 128
	/* Configure timer for smart-idle mode */
	l = __omap_dm_timer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET, 0);
	l |= 0x2 << 0x3;
	__omap_dm_timer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET, l, 0);

	timer->posted = 0;

	return 0;
129 130
}

131
int omap_dm_timer_prepare(struct omap_dm_timer *timer)
132
{
133 134
	int rc;

J
Jon Hunter 已提交
135 136 137 138 139 140 141 142 143 144 145
	/*
	 * 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;
		}
146 147
	}

148 149
	omap_dm_timer_enable(timer);

150 151 152 153 154 155 156
	if (timer->capability & OMAP_TIMER_NEEDS_RESET) {
		rc = omap_dm_timer_reset(timer);
		if (rc) {
			omap_dm_timer_disable(timer);
			return rc;
		}
	}
157

158 159
	__omap_dm_timer_enable_posted(timer);
	omap_dm_timer_disable(timer);
160

161
	return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
162 163
}

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
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;
}

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

	spin_lock_irqsave(&dm_timer_lock, flags);
186 187
	list_for_each_entry(t, &omap_timer_list, node) {
		if (t->reserved)
188 189
			continue;

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

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

204 205
	if (!timer)
		pr_debug("%s: timer request failed!\n", __func__);
T
Timo Teras 已提交
206

207 208
	return timer;
}
209
EXPORT_SYMBOL_GPL(omap_dm_timer_request);
210 211

struct omap_dm_timer *omap_dm_timer_request_specific(int id)
212
{
213
	struct omap_dm_timer *timer = NULL, *t;
214
	unsigned long flags;
215
	int ret = 0;
216

217 218 219 220 221 222 223
	/* Requesting timer by ID is not supported when device tree is used */
	if (of_have_populated_dt()) {
		pr_warn("%s: Please use omap_dm_timer_request_by_cap()\n",
			__func__);
		return NULL;
	}

224
	spin_lock_irqsave(&dm_timer_lock, flags);
225 226 227 228 229 230
	list_for_each_entry(t, &omap_timer_list, node) {
		if (t->pdev->id == id && !t->reserved) {
			timer = t;
			timer->reserved = 1;
			break;
		}
231
	}
232
	spin_unlock_irqrestore(&dm_timer_lock, flags);
233

234 235 236 237 238 239 240
	if (timer) {
		ret = omap_dm_timer_prepare(timer);
		if (ret) {
			timer->reserved = 0;
			timer = NULL;
		}
	}
241

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

245
	return timer;
246
}
247
EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
248

249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
/**
 * omap_dm_timer_request_by_cap - Request a timer by capability
 * @cap:	Bit mask of capabilities to match
 *
 * Find a timer based upon capabilities bit mask. Callers of this function
 * should use the definitions found in the plat/dmtimer.h file under the
 * comment "timer capabilities used in hwmod database". Returns pointer to
 * timer handle on success and a NULL pointer on failure.
 */
struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap)
{
	struct omap_dm_timer *timer = NULL, *t;
	unsigned long flags;

	if (!cap)
		return NULL;

	spin_lock_irqsave(&dm_timer_lock, flags);
	list_for_each_entry(t, &omap_timer_list, node) {
		if ((!t->reserved) && ((t->capability & cap) == cap)) {
			/*
			 * If timer is not NULL, we have already found one timer
			 * but it was not an exact match because it had more
			 * capabilites that what was required. Therefore,
			 * unreserve the last timer found and see if this one
			 * is a better match.
			 */
			if (timer)
				timer->reserved = 0;

			timer = t;
			timer->reserved = 1;

			/* Exit loop early if we find an exact match */
			if (t->capability == cap)
				break;
		}
	}
	spin_unlock_irqrestore(&dm_timer_lock, flags);

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

	if (!timer)
		pr_debug("%s: timer request failed!\n", __func__);

	return timer;
}
EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap);

301
int omap_dm_timer_free(struct omap_dm_timer *timer)
302
{
303 304 305
	if (unlikely(!timer))
		return -EINVAL;

306
	clk_put(timer->fclk);
307

308 309
	WARN_ON(!timer->reserved);
	timer->reserved = 0;
310
	return 0;
311
}
312
EXPORT_SYMBOL_GPL(omap_dm_timer_free);
313

314 315
void omap_dm_timer_enable(struct omap_dm_timer *timer)
{
316
	pm_runtime_get_sync(&timer->pdev->dev);
317
}
318
EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
319 320 321

void omap_dm_timer_disable(struct omap_dm_timer *timer)
{
322
	pm_runtime_put_sync(&timer->pdev->dev);
323
}
324
EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
325

326 327
int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
{
328 329 330
	if (timer)
		return timer->irq;
	return -EINVAL;
331
}
332
EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
333 334

#if defined(CONFIG_ARCH_OMAP1)
335
#include <mach/hardware.h>
336 337 338 339 340 341
/**
 * 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)
{
342 343 344
	int i = 0;
	struct omap_dm_timer *timer = NULL;
	unsigned long flags;
345 346 347 348 349 350

	/* 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 */
351 352
	spin_lock_irqsave(&dm_timer_lock, flags);
	list_for_each_entry(timer, &omap_timer_list, node) {
353 354
		u32 l;

355
		l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
356 357
		if (l & OMAP_TIMER_CTRL_ST) {
			if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
358 359 360 361
				inputmask &= ~(1 << 1);
			else
				inputmask &= ~(1 << 2);
		}
362
		i++;
363
	}
364
	spin_unlock_irqrestore(&dm_timer_lock, flags);
365 366 367

	return inputmask;
}
368
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
369

370
#else
371

372
struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
373
{
374 375 376
	if (timer)
		return timer->fclk;
	return NULL;
377
}
378
EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
379

380 381 382
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
{
	BUG();
383 384

	return 0;
385
}
386
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
387

388
#endif
389

390
int omap_dm_timer_trigger(struct omap_dm_timer *timer)
391
{
392 393 394
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
		return -EINVAL;
395 396
	}

397
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
398
	return 0;
399
}
400
EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
401

402
int omap_dm_timer_start(struct omap_dm_timer *timer)
403 404
{
	u32 l;
405

406 407 408
	if (unlikely(!timer))
		return -EINVAL;

409 410
	omap_dm_timer_enable(timer);

411
	if (!(timer->capability & OMAP_TIMER_ALWON)) {
412 413
		if (timer->get_context_loss_count &&
			timer->get_context_loss_count(&timer->pdev->dev) !=
414
				timer->ctx_loss_count)
415 416 417
			omap_timer_restore_context(timer);
	}

418 419 420 421 422
	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);
	}
423 424 425

	/* Save the context */
	timer->context.tclr = l;
426
	return 0;
427
}
428
EXPORT_SYMBOL_GPL(omap_dm_timer_start);
429

430
int omap_dm_timer_stop(struct omap_dm_timer *timer)
431
{
432
	unsigned long rate = 0;
433

434 435 436
	if (unlikely(!timer))
		return -EINVAL;

437
	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
438
		rate = clk_get_rate(timer->fclk);
439

440
	__omap_dm_timer_stop(timer, timer->posted, rate);
441

442 443 444 445 446
	if (!(timer->capability & OMAP_TIMER_ALWON)) {
		if (timer->get_context_loss_count)
			timer->ctx_loss_count =
				timer->get_context_loss_count(&timer->pdev->dev);
	}
447 448 449 450 451 452 453 454 455

	/*
	 * 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);
	omap_dm_timer_disable(timer);
456
	return 0;
457
}
458
EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
459

460
int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
461
{
462
	int ret;
463
	char *parent_name = NULL;
464
	struct clk *parent;
465 466 467 468 469 470
	struct dmtimer_platform_data *pdata;

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

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

472
	if (source < 0 || source >= 3)
473
		return -EINVAL;
474

475 476 477 478 479
	/*
	 * 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
	 */
480
	if (pdata && pdata->set_timer_src)
481 482
		return pdata->set_timer_src(timer->pdev, source);

483
	if (!timer->fclk)
484 485 486 487
		return -EINVAL;

	switch (source) {
	case OMAP_TIMER_SRC_SYS_CLK:
488
		parent_name = "timer_sys_ck";
489 490 491
		break;

	case OMAP_TIMER_SRC_32_KHZ:
492
		parent_name = "timer_32k_ck";
493 494 495
		break;

	case OMAP_TIMER_SRC_EXT_CLK:
496
		parent_name = "timer_ext_ck";
497 498 499 500 501 502
		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);
503
		return -EINVAL;
504 505
	}

506
	ret = clk_set_parent(timer->fclk, parent);
507 508 509 510 511
	if (IS_ERR_VALUE(ret))
		pr_err("%s: failed to set %s as parent\n", __func__,
			parent_name);

	clk_put(parent);
512 513

	return ret;
514
}
515
EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
516

517
int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
518
			    unsigned int load)
519 520
{
	u32 l;
521

522 523 524
	if (unlikely(!timer))
		return -EINVAL;

525
	omap_dm_timer_enable(timer);
526
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
527 528 529 530
	if (autoreload)
		l |= OMAP_TIMER_CTRL_AR;
	else
		l &= ~OMAP_TIMER_CTRL_AR;
531
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
532
	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
533

534
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
535 536 537 538
	/* Save the context */
	timer->context.tclr = l;
	timer->context.tldr = load;
	omap_dm_timer_disable(timer);
539
	return 0;
540
}
541
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
542

543
/* Optimized set_load which removes costly spin wait in timer_start */
544
int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
545 546 547 548
                            unsigned int load)
{
	u32 l;

549 550 551
	if (unlikely(!timer))
		return -EINVAL;

552 553
	omap_dm_timer_enable(timer);

554
	if (!(timer->capability & OMAP_TIMER_ALWON)) {
555 556
		if (timer->get_context_loss_count &&
			timer->get_context_loss_count(&timer->pdev->dev) !=
557
				timer->ctx_loss_count)
558 559 560
			omap_timer_restore_context(timer);
	}

561
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
562
	if (autoreload) {
563
		l |= OMAP_TIMER_CTRL_AR;
564 565
		omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
	} else {
566
		l &= ~OMAP_TIMER_CTRL_AR;
567
	}
568 569
	l |= OMAP_TIMER_CTRL_ST;

570
	__omap_dm_timer_load_start(timer, l, load, timer->posted);
571 572 573 574 575

	/* Save the context */
	timer->context.tclr = l;
	timer->context.tldr = load;
	timer->context.tcrr = load;
576
	return 0;
577
}
578
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
579

580
int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
581
			     unsigned int match)
582 583 584
{
	u32 l;

585 586 587
	if (unlikely(!timer))
		return -EINVAL;

588
	omap_dm_timer_enable(timer);
589
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
T
Timo Teras 已提交
590
	if (enable)
591 592 593 594
		l |= OMAP_TIMER_CTRL_CE;
	else
		l &= ~OMAP_TIMER_CTRL_CE;
	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
595
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
596 597 598 599 600

	/* Save the context */
	timer->context.tclr = l;
	timer->context.tmar = match;
	omap_dm_timer_disable(timer);
601
	return 0;
602
}
603
EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
604

605
int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
606
			   int toggle, int trigger)
607 608 609
{
	u32 l;

610 611 612
	if (unlikely(!timer))
		return -EINVAL;

613
	omap_dm_timer_enable(timer);
614
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
615 616 617 618 619 620 621
	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;
622
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
623 624 625 626

	/* Save the context */
	timer->context.tclr = l;
	omap_dm_timer_disable(timer);
627
	return 0;
628
}
629
EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
630

631
int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
632 633 634
{
	u32 l;

635 636 637
	if (unlikely(!timer))
		return -EINVAL;

638
	omap_dm_timer_enable(timer);
639
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
640 641 642 643 644
	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
	if (prescaler >= 0x00 && prescaler <= 0x07) {
		l |= OMAP_TIMER_CTRL_PRE;
		l |= prescaler << 2;
	}
645
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
646 647 648 649

	/* Save the context */
	timer->context.tclr = l;
	omap_dm_timer_disable(timer);
650
	return 0;
651
}
652
EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
653

654
int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
655
				  unsigned int value)
656
{
657 658 659
	if (unlikely(!timer))
		return -EINVAL;

660
	omap_dm_timer_enable(timer);
661
	__omap_dm_timer_int_enable(timer, value);
662 663 664 665 666

	/* Save the context */
	timer->context.tier = value;
	timer->context.twer = value;
	omap_dm_timer_disable(timer);
667
	return 0;
668
}
669
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
670

671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
/**
 * omap_dm_timer_set_int_disable - disable timer interrupts
 * @timer:	pointer to timer handle
 * @mask:	bit mask of interrupts to be disabled
 *
 * Disables the specified timer interrupts for a timer.
 */
int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
{
	u32 l = mask;

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

	omap_dm_timer_enable(timer);

	if (timer->revision == 1)
		l = __raw_readl(timer->irq_ena) & ~mask;

	__raw_writel(l, timer->irq_dis);
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask;
	omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l);

	/* Save the context */
	timer->context.tier &= ~mask;
	timer->context.twer &= ~mask;
	omap_dm_timer_disable(timer);
	return 0;
}
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_disable);

702
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
703
{
704 705
	unsigned int l;

706 707
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
708 709 710
		return 0;
	}

711
	l = __raw_readl(timer->irq_stat);
712 713

	return l;
714
}
715
EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
716

717
int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
718
{
719 720 721
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
		return -EINVAL;

722
	__omap_dm_timer_write_status(timer, value);
723

724
	return 0;
725
}
726
EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
727

728
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
729
{
730 731
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not iavailable or enabled.\n", __func__);
732 733 734
		return 0;
	}

735
	return __omap_dm_timer_read_counter(timer, timer->posted);
736
}
737
EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
738

739
int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
T
Timo Teras 已提交
740
{
741 742 743
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
		return -EINVAL;
744 745
	}

746
	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
747 748 749

	/* Save the context */
	timer->context.tcrr = value;
750
	return 0;
T
Timo Teras 已提交
751
}
752
EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
T
Timo Teras 已提交
753

754
int omap_dm_timers_active(void)
755
{
756
	struct omap_dm_timer *timer;
757

758
	list_for_each_entry(timer, &omap_timer_list, node) {
759
		if (!timer->reserved)
760 761
			continue;

762
		if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
763
		    OMAP_TIMER_CTRL_ST) {
764
			return 1;
765
		}
766 767 768
	}
	return 0;
}
769
EXPORT_SYMBOL_GPL(omap_dm_timers_active);
770

771 772 773 774 775 776 777 778 779 780 781
/**
 * 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;
782 783
	struct resource *mem, *irq;
	struct device *dev = &pdev->dev;
784 785
	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;

786
	if (!pdata && !dev->of_node) {
787
		dev_err(dev, "%s: no platform data.\n", __func__);
788 789 790 791 792
		return -ENODEV;
	}

	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (unlikely(!irq)) {
793
		dev_err(dev, "%s: no IRQ resource.\n", __func__);
794 795 796 797 798
		return -ENODEV;
	}

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

803
	timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL);
804
	if (!timer) {
805 806
		dev_err(dev, "%s: memory alloc failed!\n", __func__);
		return  -ENOMEM;
807 808
	}

809
	timer->io_base = devm_request_and_ioremap(dev, mem);
810
	if (!timer->io_base) {
811 812
		dev_err(dev, "%s: region already claimed.\n", __func__);
		return -ENOMEM;
813 814
	}

815 816 817 818 819 820 821 822 823 824 825
	if (dev->of_node) {
		if (of_find_property(dev->of_node, "ti,timer-alwon", NULL))
			timer->capability |= OMAP_TIMER_ALWON;
		if (of_find_property(dev->of_node, "ti,timer-dsp", NULL))
			timer->capability |= OMAP_TIMER_HAS_DSP_IRQ;
		if (of_find_property(dev->of_node, "ti,timer-pwm", NULL))
			timer->capability |= OMAP_TIMER_HAS_PWM;
		if (of_find_property(dev->of_node, "ti,timer-secure", NULL))
			timer->capability |= OMAP_TIMER_SECURE;
	} else {
		timer->id = pdev->id;
826
		timer->errata = pdata->timer_errata;
827 828
		timer->capability = pdata->timer_capability;
		timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
829
		timer->get_context_loss_count = pdata->get_context_loss_count;
830 831
	}

832 833 834
	timer->irq = irq->start;
	timer->pdev = pdev;

835
	/* Skip pm_runtime_enable for OMAP1 */
836
	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
837 838
		pm_runtime_enable(dev);
		pm_runtime_irq_safe(dev);
839 840
	}

841
	if (!timer->reserved) {
842
		pm_runtime_get_sync(dev);
843
		__omap_dm_timer_init_regs(timer);
844
		pm_runtime_put(dev);
845 846
	}

847 848 849 850 851
	/* 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);

852
	dev_dbg(dev, "Device Probed.\n");
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872

	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)
873 874
		if (!strcmp(dev_name(&timer->pdev->dev),
			    dev_name(&pdev->dev))) {
875 876 877 878 879 880 881 882 883
			list_del(&timer->node);
			ret = 0;
			break;
		}
	spin_unlock_irqrestore(&dm_timer_lock, flags);

	return ret;
}

884 885 886 887 888 889
static const struct of_device_id omap_timer_match[] = {
	{ .compatible = "ti,omap2-timer", },
	{},
};
MODULE_DEVICE_TABLE(of, omap_timer_match);

890 891
static struct platform_driver omap_dm_timer_driver = {
	.probe  = omap_dm_timer_probe,
892
	.remove = __devexit_p(omap_dm_timer_remove),
893 894
	.driver = {
		.name   = "omap_timer",
895
		.of_match_table = of_match_ptr(omap_timer_match),
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916
	},
};

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");