dmtimer.c 22.1 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
		l |= OMAP_TIMER_CTRL_CE;
	else
		l &= ~OMAP_TIMER_CTRL_CE;
587
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
588
	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
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
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
665
{
666 667
	unsigned int l;

668 669
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
670 671 672
		return 0;
	}

673
	l = __raw_readl(timer->irq_stat);
674 675

	return l;
676
}
677
EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
678

679
int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
680
{
681 682 683
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
		return -EINVAL;

684
	__omap_dm_timer_write_status(timer, value);
685

686
	return 0;
687
}
688
EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
689

690
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
691
{
692 693
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not iavailable or enabled.\n", __func__);
694 695 696
		return 0;
	}

697
	return __omap_dm_timer_read_counter(timer, timer->posted);
698
}
699
EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
700

701
int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
T
Timo Teras 已提交
702
{
703 704 705
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
		return -EINVAL;
706 707
	}

708
	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
709 710 711

	/* Save the context */
	timer->context.tcrr = value;
712
	return 0;
T
Timo Teras 已提交
713
}
714
EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
T
Timo Teras 已提交
715

716
int omap_dm_timers_active(void)
717
{
718
	struct omap_dm_timer *timer;
719

720
	list_for_each_entry(timer, &omap_timer_list, node) {
721
		if (!timer->reserved)
722 723
			continue;

724
		if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
725
		    OMAP_TIMER_CTRL_ST) {
726
			return 1;
727
		}
728 729 730
	}
	return 0;
}
731
EXPORT_SYMBOL_GPL(omap_dm_timers_active);
732

733 734 735 736 737 738 739 740 741 742 743
/**
 * 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;
744 745
	struct resource *mem, *irq;
	struct device *dev = &pdev->dev;
746 747
	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;

748
	if (!pdata && !dev->of_node) {
749
		dev_err(dev, "%s: no platform data.\n", __func__);
750 751 752 753 754
		return -ENODEV;
	}

	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (unlikely(!irq)) {
755
		dev_err(dev, "%s: no IRQ resource.\n", __func__);
756 757 758 759 760
		return -ENODEV;
	}

	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (unlikely(!mem)) {
761
		dev_err(dev, "%s: no memory resource.\n", __func__);
762 763 764
		return -ENODEV;
	}

765
	timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL);
766
	if (!timer) {
767 768
		dev_err(dev, "%s: memory alloc failed!\n", __func__);
		return  -ENOMEM;
769 770
	}

771
	timer->io_base = devm_request_and_ioremap(dev, mem);
772
	if (!timer->io_base) {
773 774
		dev_err(dev, "%s: region already claimed.\n", __func__);
		return -ENOMEM;
775 776
	}

777 778 779 780 781 782 783 784 785 786 787
	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;
788
		timer->errata = pdata->timer_errata;
789 790
		timer->capability = pdata->timer_capability;
		timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
791
		timer->get_context_loss_count = pdata->get_context_loss_count;
792 793
	}

794 795 796
	timer->irq = irq->start;
	timer->pdev = pdev;

797
	/* Skip pm_runtime_enable for OMAP1 */
798
	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
799 800
		pm_runtime_enable(dev);
		pm_runtime_irq_safe(dev);
801 802
	}

803
	if (!timer->reserved) {
804
		pm_runtime_get_sync(dev);
805
		__omap_dm_timer_init_regs(timer);
806
		pm_runtime_put(dev);
807 808
	}

809 810 811 812 813
	/* 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);

814
	dev_dbg(dev, "Device Probed.\n");
815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834

	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)
835 836
		if (!strcmp(dev_name(&timer->pdev->dev),
			    dev_name(&pdev->dev))) {
837 838 839 840 841 842 843 844 845
			list_del(&timer->node);
			ret = 0;
			break;
		}
	spin_unlock_irqrestore(&dm_timer_lock, flags);

	return ret;
}

846 847 848 849 850 851
static const struct of_device_id omap_timer_match[] = {
	{ .compatible = "ti,omap2-timer", },
	{},
};
MODULE_DEVICE_TABLE(of, omap_timer_match);

852 853
static struct platform_driver omap_dm_timer_driver = {
	.probe  = omap_dm_timer_probe,
854
	.remove = __devexit_p(omap_dm_timer_remove),
855 856
	.driver = {
		.name   = "omap_timer",
857
		.of_match_table = of_match_ptr(omap_timer_match),
858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878
	},
};

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