dmtimer.c 22.4 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 <linux/platform_device.h>
#include <linux/platform_data/dmtimer-omap.h>
48

49
#include <plat/dmtimer.h>
50

51
static u32 omap_reserved_systimers;
52
static LIST_HEAD(omap_timer_list);
53
static DEFINE_SPINLOCK(dm_timer_lock);
54

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

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

87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
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);
}

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

108 109
	if (timer->revision != 1)
		return -EINVAL;
110

111 112 113 114 115 116 117 118 119 120
	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;
121
	}
122

123 124 125 126 127 128 129 130
	/* 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;
131 132
}

133
static int omap_dm_timer_prepare(struct omap_dm_timer *timer)
134
{
135 136
	int rc;

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

150 151
	omap_dm_timer_enable(timer);

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

160 161
	__omap_dm_timer_enable_posted(timer);
	omap_dm_timer_disable(timer);
162

163
	return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
164 165
}

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

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

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

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

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

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

209 210
	return timer;
}
211
EXPORT_SYMBOL_GPL(omap_dm_timer_request);
212 213

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

219 220 221 222 223 224 225
	/* 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;
	}

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

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

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

247
	return timer;
248
}
249
EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
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 301 302
/**
 * 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);

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

308
	clk_put(timer->fclk);
309

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

316 317
void omap_dm_timer_enable(struct omap_dm_timer *timer)
{
318 319
	int c;

320
	pm_runtime_get_sync(&timer->pdev->dev);
321 322 323 324 325 326 327 328 329 330

	if (!(timer->capability & OMAP_TIMER_ALWON)) {
		if (timer->get_context_loss_count) {
			c = timer->get_context_loss_count(&timer->pdev->dev);
			if (c != timer->ctx_loss_count) {
				omap_timer_restore_context(timer);
				timer->ctx_loss_count = c;
			}
		}
	}
331
}
332
EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
333 334 335

void omap_dm_timer_disable(struct omap_dm_timer *timer)
{
336
	pm_runtime_put_sync(&timer->pdev->dev);
337
}
338
EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
339

340 341
int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
{
342 343 344
	if (timer)
		return timer->irq;
	return -EINVAL;
345
}
346
EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
347 348

#if defined(CONFIG_ARCH_OMAP1)
349
#include <mach/hardware.h>
350 351 352 353 354 355
/**
 * 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)
{
356 357 358
	int i = 0;
	struct omap_dm_timer *timer = NULL;
	unsigned long flags;
359 360 361 362 363 364

	/* 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 */
365 366
	spin_lock_irqsave(&dm_timer_lock, flags);
	list_for_each_entry(timer, &omap_timer_list, node) {
367 368
		u32 l;

369
		l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
370 371
		if (l & OMAP_TIMER_CTRL_ST) {
			if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
372 373 374 375
				inputmask &= ~(1 << 1);
			else
				inputmask &= ~(1 << 2);
		}
376
		i++;
377
	}
378
	spin_unlock_irqrestore(&dm_timer_lock, flags);
379 380 381

	return inputmask;
}
382
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
383

384
#else
385

386
struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
387
{
388 389 390
	if (timer)
		return timer->fclk;
	return NULL;
391
}
392
EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
393

394 395 396
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
{
	BUG();
397 398

	return 0;
399
}
400
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
401

402
#endif
403

404
int omap_dm_timer_trigger(struct omap_dm_timer *timer)
405
{
406 407 408
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
		return -EINVAL;
409 410
	}

411
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
412
	return 0;
413
}
414
EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
415

416
int omap_dm_timer_start(struct omap_dm_timer *timer)
417 418
{
	u32 l;
419

420 421 422
	if (unlikely(!timer))
		return -EINVAL;

423 424
	omap_dm_timer_enable(timer);

425 426 427 428 429
	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);
	}
430 431 432

	/* Save the context */
	timer->context.tclr = l;
433
	return 0;
434
}
435
EXPORT_SYMBOL_GPL(omap_dm_timer_start);
436

437
int omap_dm_timer_stop(struct omap_dm_timer *timer)
438
{
439
	unsigned long rate = 0;
440

441 442 443
	if (unlikely(!timer))
		return -EINVAL;

444
	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
445
		rate = clk_get_rate(timer->fclk);
446

447
	__omap_dm_timer_stop(timer, timer->posted, rate);
448

449 450 451 452 453 454 455 456
	/*
	 * 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);
457
	return 0;
458
}
459
EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
460

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

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

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

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

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

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

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

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

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

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

	clk_put(parent);
513 514

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

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

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

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

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

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

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

553 554
	omap_dm_timer_enable(timer);

555
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
556
	if (autoreload) {
557
		l |= OMAP_TIMER_CTRL_AR;
558 559
		omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
	} else {
560
		l &= ~OMAP_TIMER_CTRL_AR;
561
	}
562 563
	l |= OMAP_TIMER_CTRL_ST;

564
	__omap_dm_timer_load_start(timer, l, load, timer->posted);
565 566 567 568 569

	/* Save the context */
	timer->context.tclr = l;
	timer->context.tldr = load;
	timer->context.tcrr = load;
570
	return 0;
571
}
572
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
573

574
int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
575
			     unsigned int match)
576 577 578
{
	u32 l;

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

582
	omap_dm_timer_enable(timer);
583
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
T
Timo Teras 已提交
584
	if (enable)
585 586 587 588
		l |= OMAP_TIMER_CTRL_CE;
	else
		l &= ~OMAP_TIMER_CTRL_CE;
	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
589
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
590 591 592 593 594

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

599
int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
600
			   int toggle, int trigger)
601 602 603
{
	u32 l;

604 605 606
	if (unlikely(!timer))
		return -EINVAL;

607
	omap_dm_timer_enable(timer);
608
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
609 610 611 612 613 614 615
	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;
616
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
617 618 619 620

	/* Save the context */
	timer->context.tclr = l;
	omap_dm_timer_disable(timer);
621
	return 0;
622
}
623
EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
624

625
int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
626 627 628
{
	u32 l;

629 630 631
	if (unlikely(!timer))
		return -EINVAL;

632
	omap_dm_timer_enable(timer);
633
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
634 635 636 637 638
	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
	if (prescaler >= 0x00 && prescaler <= 0x07) {
		l |= OMAP_TIMER_CTRL_PRE;
		l |= prescaler << 2;
	}
639
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
640 641 642 643

	/* Save the context */
	timer->context.tclr = l;
	omap_dm_timer_disable(timer);
644
	return 0;
645
}
646
EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
647

648
int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
649
				  unsigned int value)
650
{
651 652 653
	if (unlikely(!timer))
		return -EINVAL;

654
	omap_dm_timer_enable(timer);
655
	__omap_dm_timer_int_enable(timer, value);
656 657 658 659 660

	/* Save the context */
	timer->context.tier = value;
	timer->context.twer = value;
	omap_dm_timer_disable(timer);
661
	return 0;
662
}
663
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
664

665 666 667 668 669 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
/**
 * 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);

696
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
697
{
698 699
	unsigned int l;

700 701
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
702 703 704
		return 0;
	}

705
	l = __raw_readl(timer->irq_stat);
706 707

	return l;
708
}
709
EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
710

711
int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
712
{
713 714 715
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
		return -EINVAL;

716
	__omap_dm_timer_write_status(timer, value);
717

718
	return 0;
719
}
720
EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
721

722
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
723
{
724 725
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not iavailable or enabled.\n", __func__);
726 727 728
		return 0;
	}

729
	return __omap_dm_timer_read_counter(timer, timer->posted);
730
}
731
EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
732

733
int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
T
Timo Teras 已提交
734
{
735 736 737
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
		return -EINVAL;
738 739
	}

740
	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
741 742 743

	/* Save the context */
	timer->context.tcrr = value;
744
	return 0;
T
Timo Teras 已提交
745
}
746
EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
T
Timo Teras 已提交
747

748
int omap_dm_timers_active(void)
749
{
750
	struct omap_dm_timer *timer;
751

752
	list_for_each_entry(timer, &omap_timer_list, node) {
753
		if (!timer->reserved)
754 755
			continue;

756
		if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
757
		    OMAP_TIMER_CTRL_ST) {
758
			return 1;
759
		}
760 761 762
	}
	return 0;
}
763
EXPORT_SYMBOL_GPL(omap_dm_timers_active);
764

765 766 767 768 769 770 771
/**
 * 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.
 */
772
static int omap_dm_timer_probe(struct platform_device *pdev)
773 774 775
{
	unsigned long flags;
	struct omap_dm_timer *timer;
776 777
	struct resource *mem, *irq;
	struct device *dev = &pdev->dev;
778 779
	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;

780
	if (!pdata && !dev->of_node) {
781
		dev_err(dev, "%s: no platform data.\n", __func__);
782 783 784 785 786
		return -ENODEV;
	}

	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (unlikely(!irq)) {
787
		dev_err(dev, "%s: no IRQ resource.\n", __func__);
788 789 790 791 792
		return -ENODEV;
	}

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

797
	timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL);
798
	if (!timer) {
799 800
		dev_err(dev, "%s: memory alloc failed!\n", __func__);
		return  -ENOMEM;
801 802
	}

803 804 805
	timer->io_base = devm_ioremap_resource(dev, mem);
	if (IS_ERR(timer->io_base))
		return PTR_ERR(timer->io_base);
806

807 808 809 810 811 812 813 814 815 816 817
	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;
818
		timer->errata = pdata->timer_errata;
819 820
		timer->capability = pdata->timer_capability;
		timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
821
		timer->get_context_loss_count = pdata->get_context_loss_count;
822 823
	}

824 825 826
	timer->irq = irq->start;
	timer->pdev = pdev;

827
	/* Skip pm_runtime_enable for OMAP1 */
828
	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
829 830
		pm_runtime_enable(dev);
		pm_runtime_irq_safe(dev);
831 832
	}

833
	if (!timer->reserved) {
834
		pm_runtime_get_sync(dev);
835
		__omap_dm_timer_init_regs(timer);
836
		pm_runtime_put(dev);
837 838
	}

839 840 841 842 843
	/* 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);

844
	dev_dbg(dev, "Device Probed.\n");
845 846 847 848 849 850 851 852 853 854 855 856

	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.
 */
857
static int omap_dm_timer_remove(struct platform_device *pdev)
858 859 860 861 862 863 864
{
	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)
865 866
		if (!strcmp(dev_name(&timer->pdev->dev),
			    dev_name(&pdev->dev))) {
867 868 869 870 871 872 873 874 875
			list_del(&timer->node);
			ret = 0;
			break;
		}
	spin_unlock_irqrestore(&dm_timer_lock, flags);

	return ret;
}

876 877 878 879 880 881
static const struct of_device_id omap_timer_match[] = {
	{ .compatible = "ti,omap2-timer", },
	{},
};
MODULE_DEVICE_TABLE(of, omap_timer_match);

882 883
static struct platform_driver omap_dm_timer_driver = {
	.probe  = omap_dm_timer_probe,
884
	.remove = omap_dm_timer_remove,
885 886
	.driver = {
		.name   = "omap_timer",
887
		.of_match_table = of_match_ptr(omap_timer_match),
888 889 890 891
	},
};

early_platform_init("earlytimer", &omap_dm_timer_driver);
892
module_platform_driver(omap_dm_timer_driver);
893 894 895 896 897

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