dmtimer.c 22.8 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 <linux/of.h>
#include <linux/of_device.h>
45

46
#include <plat/dmtimer.h>
47

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

101
static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
102
{
103 104
	int c;

105 106 107
	if (!timer->sys_stat)
		return;

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

118 119
static void omap_dm_timer_reset(struct omap_dm_timer *timer)
{
120 121
	omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
	omap_dm_timer_wait_for_reset(timer);
122
	__omap_dm_timer_reset(timer, 0, 0);
123 124
}

125
int omap_dm_timer_prepare(struct omap_dm_timer *timer)
126
{
J
Jon Hunter 已提交
127 128 129 130 131 132 133 134 135 136 137
	/*
	 * 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;
		}
138 139
	}

140 141
	omap_dm_timer_enable(timer);

142
	if (timer->capability & OMAP_TIMER_NEEDS_RESET)
143 144
		omap_dm_timer_reset(timer);

145 146
	__omap_dm_timer_enable_posted(timer);
	omap_dm_timer_disable(timer);
147

148
	return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
149 150
}

151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
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;
}

166 167
struct omap_dm_timer *omap_dm_timer_request(void)
{
168
	struct omap_dm_timer *timer = NULL, *t;
169
	unsigned long flags;
170
	int ret = 0;
171 172

	spin_lock_irqsave(&dm_timer_lock, flags);
173 174
	list_for_each_entry(t, &omap_timer_list, node) {
		if (t->reserved)
175 176
			continue;

177
		timer = t;
T
Timo Teras 已提交
178
		timer->reserved = 1;
179 180
		break;
	}
181
	spin_unlock_irqrestore(&dm_timer_lock, flags);
182 183 184 185 186 187 188 189

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

191 192
	if (!timer)
		pr_debug("%s: timer request failed!\n", __func__);
T
Timo Teras 已提交
193

194 195
	return timer;
}
196
EXPORT_SYMBOL_GPL(omap_dm_timer_request);
197 198

struct omap_dm_timer *omap_dm_timer_request_specific(int id)
199
{
200
	struct omap_dm_timer *timer = NULL, *t;
201
	unsigned long flags;
202
	int ret = 0;
203

204 205 206 207 208 209 210
	/* 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;
	}

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

221 222 223 224 225 226 227
	if (timer) {
		ret = omap_dm_timer_prepare(timer);
		if (ret) {
			timer->reserved = 0;
			timer = NULL;
		}
	}
228

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

232
	return timer;
233
}
234
EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
235

236 237 238 239 240 241 242 243 244 245 246 247 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
/**
 * 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);

288
int omap_dm_timer_free(struct omap_dm_timer *timer)
289
{
290 291 292
	if (unlikely(!timer))
		return -EINVAL;

293
	clk_put(timer->fclk);
294

295 296
	WARN_ON(!timer->reserved);
	timer->reserved = 0;
297
	return 0;
298
}
299
EXPORT_SYMBOL_GPL(omap_dm_timer_free);
300

301 302
void omap_dm_timer_enable(struct omap_dm_timer *timer)
{
303
	pm_runtime_get_sync(&timer->pdev->dev);
304
}
305
EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
306 307 308

void omap_dm_timer_disable(struct omap_dm_timer *timer)
{
309
	pm_runtime_put_sync(&timer->pdev->dev);
310
}
311
EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
312

313 314
int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
{
315 316 317
	if (timer)
		return timer->irq;
	return -EINVAL;
318
}
319
EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
320 321

#if defined(CONFIG_ARCH_OMAP1)
322
#include <mach/hardware.h>
323 324 325 326 327 328
/**
 * 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)
{
329 330 331
	int i = 0;
	struct omap_dm_timer *timer = NULL;
	unsigned long flags;
332 333 334 335 336 337

	/* 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 */
338 339
	spin_lock_irqsave(&dm_timer_lock, flags);
	list_for_each_entry(timer, &omap_timer_list, node) {
340 341
		u32 l;

342
		l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
343 344
		if (l & OMAP_TIMER_CTRL_ST) {
			if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
345 346 347 348
				inputmask &= ~(1 << 1);
			else
				inputmask &= ~(1 << 2);
		}
349
		i++;
350
	}
351
	spin_unlock_irqrestore(&dm_timer_lock, flags);
352 353 354

	return inputmask;
}
355
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
356

357
#else
358

359
struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
360
{
361 362 363
	if (timer)
		return timer->fclk;
	return NULL;
364
}
365
EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
366

367 368 369
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
{
	BUG();
370 371

	return 0;
372
}
373
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
374

375
#endif
376

377
int omap_dm_timer_trigger(struct omap_dm_timer *timer)
378
{
379 380 381
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
		return -EINVAL;
382 383
	}

384
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
385
	return 0;
386
}
387
EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
388

389
int omap_dm_timer_start(struct omap_dm_timer *timer)
390 391
{
	u32 l;
392

393 394 395
	if (unlikely(!timer))
		return -EINVAL;

396 397
	omap_dm_timer_enable(timer);

398
	if (!(timer->capability & OMAP_TIMER_ALWON)) {
399 400
		if (timer->get_context_loss_count &&
			timer->get_context_loss_count(&timer->pdev->dev) !=
401
				timer->ctx_loss_count)
402 403 404
			omap_timer_restore_context(timer);
	}

405 406 407 408 409
	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);
	}
410 411 412

	/* Save the context */
	timer->context.tclr = l;
413
	return 0;
414
}
415
EXPORT_SYMBOL_GPL(omap_dm_timer_start);
416

417
int omap_dm_timer_stop(struct omap_dm_timer *timer)
418
{
419
	unsigned long rate = 0;
420

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

424
	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
425
		rate = clk_get_rate(timer->fclk);
426

427
	__omap_dm_timer_stop(timer, timer->posted, rate);
428

429 430 431 432 433
	if (!(timer->capability & OMAP_TIMER_ALWON)) {
		if (timer->get_context_loss_count)
			timer->ctx_loss_count =
				timer->get_context_loss_count(&timer->pdev->dev);
	}
434 435 436 437 438 439 440 441 442

	/*
	 * 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);
443
	return 0;
444
}
445
EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
446

447
int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
448
{
449
	int ret;
450 451
	char *parent_name = NULL;
	struct clk *fclk, *parent;
452 453 454 455 456 457
	struct dmtimer_platform_data *pdata;

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

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

459
	if (source < 0 || source >= 3)
460
		return -EINVAL;
461

462 463 464 465 466
	/*
	 * 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
	 */
467
	if (pdata && pdata->set_timer_src)
468 469 470 471 472 473 474 475 476 477
		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:
478
		parent_name = "timer_sys_ck";
479 480 481
		break;

	case OMAP_TIMER_SRC_32_KHZ:
482
		parent_name = "timer_32k_ck";
483 484 485
		break;

	case OMAP_TIMER_SRC_EXT_CLK:
486
		parent_name = "timer_ext_ck";
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
		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);
505 506

	return ret;
507
}
508
EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
509

510
int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
511
			    unsigned int load)
512 513
{
	u32 l;
514

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
	if (autoreload)
		l |= OMAP_TIMER_CTRL_AR;
	else
		l &= ~OMAP_TIMER_CTRL_AR;
524
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
525
	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
526

527
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
528 529 530 531
	/* Save the context */
	timer->context.tclr = l;
	timer->context.tldr = load;
	omap_dm_timer_disable(timer);
532
	return 0;
533
}
534
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
535

536
/* Optimized set_load which removes costly spin wait in timer_start */
537
int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
538 539 540 541
                            unsigned int load)
{
	u32 l;

542 543 544
	if (unlikely(!timer))
		return -EINVAL;

545 546
	omap_dm_timer_enable(timer);

547
	if (!(timer->capability & OMAP_TIMER_ALWON)) {
548 549
		if (timer->get_context_loss_count &&
			timer->get_context_loss_count(&timer->pdev->dev) !=
550
				timer->ctx_loss_count)
551 552 553
			omap_timer_restore_context(timer);
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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
/**
 * 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);

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

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

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

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

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

715
	__omap_dm_timer_write_status(timer, value);
716

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

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

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

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

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

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

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

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

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

764 765 766 767 768 769 770 771 772 773 774
/**
 * 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;
775 776
	struct resource *mem, *irq;
	struct device *dev = &pdev->dev;
777 778
	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;

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

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

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

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

802
	timer->io_base = devm_request_and_ioremap(dev, mem);
803
	if (!timer->io_base) {
804 805
		dev_err(dev, "%s: region already claimed.\n", __func__);
		return -ENOMEM;
806 807
	}

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

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

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

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

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

845
	dev_dbg(dev, "Device Probed.\n");
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865

	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)
866 867
		if (!strcmp(dev_name(&timer->pdev->dev),
			    dev_name(&pdev->dev))) {
868 869 870 871 872 873 874 875 876
			list_del(&timer->node);
			ret = 0;
			break;
		}
	spin_unlock_irqrestore(&dm_timer_lock, flags);

	return ret;
}

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

883 884
static struct platform_driver omap_dm_timer_driver = {
	.probe  = omap_dm_timer_probe,
885
	.remove = __devexit_p(omap_dm_timer_remove),
886 887
	.driver = {
		.name   = "omap_timer",
888
		.of_match_table = of_match_ptr(omap_timer_match),
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
	},
};

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