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/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
static void omap_timer_restore_context(struct omap_dm_timer *timer)
{
86
	if (timer->revision == 1)
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
		__raw_writel(timer->context.tistat, timer->sys_stat);

	__raw_writel(timer->context.tisr, timer->irq_stat);
	omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
				timer->context.twer);
	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
				timer->context.tcrr);
	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
				timer->context.tldr);
	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
				timer->context.tmar);
	omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
				timer->context.tsicr);
	__raw_writel(timer->context.tier, timer->irq_ena);
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
				timer->context.tclr);
}

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

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

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

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

130
	__omap_dm_timer_reset(timer, 0, 0);
131
	__omap_dm_timer_enable_posted(timer);
132
	omap_dm_timer_disable(timer);
133 134
}

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

J
Jon Hunter 已提交
139 140 141 142 143 144 145 146 147 148 149
	/*
	 * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
	 * do not call clk_get() for these devices.
	 */
	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
		timer->fclk = clk_get(&timer->pdev->dev, "fck");
		if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
			timer->fclk = NULL;
			dev_err(&timer->pdev->dev, ": No fclk handle.\n");
			return -EINVAL;
		}
150 151
	}

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

	ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);

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

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

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

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

	return 0;
}

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

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

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

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

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

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

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

214 215 216 217 218 219 220
	/* 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;
	}

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

231 232 233 234 235 236 237
	if (timer) {
		ret = omap_dm_timer_prepare(timer);
		if (ret) {
			timer->reserved = 0;
			timer = NULL;
		}
	}
238

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

242
	return timer;
243
}
244
EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
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 288 289 290 291 292 293 294 295 296 297
/**
 * 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);

298
int omap_dm_timer_free(struct omap_dm_timer *timer)
299
{
300 301 302
	if (unlikely(!timer))
		return -EINVAL;

303
	clk_put(timer->fclk);
304

305 306
	WARN_ON(!timer->reserved);
	timer->reserved = 0;
307
	return 0;
308
}
309
EXPORT_SYMBOL_GPL(omap_dm_timer_free);
310

311 312
void omap_dm_timer_enable(struct omap_dm_timer *timer)
{
313
	pm_runtime_get_sync(&timer->pdev->dev);
314
}
315
EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
316 317 318

void omap_dm_timer_disable(struct omap_dm_timer *timer)
{
319
	pm_runtime_put_sync(&timer->pdev->dev);
320
}
321
EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
322

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

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

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

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

	return inputmask;
}
365
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
366

367
#else
368

369
struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
370
{
371 372 373
	if (timer)
		return timer->fclk;
	return NULL;
374
}
375
EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
376

377 378 379
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
{
	BUG();
380 381

	return 0;
382
}
383
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
384

385
#endif
386

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

394
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
395
	return 0;
396
}
397
EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
398

399
int omap_dm_timer_start(struct omap_dm_timer *timer)
400 401
{
	u32 l;
402

403 404 405
	if (unlikely(!timer))
		return -EINVAL;

406 407
	omap_dm_timer_enable(timer);

408
	if (!(timer->capability & OMAP_TIMER_ALWON)) {
409 410
		if (timer->get_context_loss_count &&
			timer->get_context_loss_count(&timer->pdev->dev) !=
411
				timer->ctx_loss_count)
412 413 414
			omap_timer_restore_context(timer);
	}

415 416 417 418 419
	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);
	}
420 421 422

	/* Save the context */
	timer->context.tclr = l;
423
	return 0;
424
}
425
EXPORT_SYMBOL_GPL(omap_dm_timer_start);
426

427
int omap_dm_timer_stop(struct omap_dm_timer *timer)
428
{
429
	unsigned long rate = 0;
430

431 432 433
	if (unlikely(!timer))
		return -EINVAL;

434
	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
435
		rate = clk_get_rate(timer->fclk);
436

437
	__omap_dm_timer_stop(timer, timer->posted, rate);
438

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

	/*
	 * Since the register values are computed and written within
	 * __omap_dm_timer_stop, we need to use read to retrieve the
	 * context.
	 */
	timer->context.tclr =
			omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
	timer->context.tisr = __raw_readl(timer->irq_stat);
	omap_dm_timer_disable(timer);
454
	return 0;
455
}
456
EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
457

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

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

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

470
	if (source < 0 || source >= 3)
471
		return -EINVAL;
472

473 474 475 476 477
	/*
	 * 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
	 */
478
	if (pdata && pdata->set_timer_src)
479 480 481 482 483 484 485 486 487 488
		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:
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 504 505 506 507 508 509 510 511 512 513 514 515
		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);
516 517

	return ret;
518
}
519
EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
520

521
int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
522
			    unsigned int load)
523 524
{
	u32 l;
525

526 527 528
	if (unlikely(!timer))
		return -EINVAL;

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

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

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

553 554 555
	if (unlikely(!timer))
		return -EINVAL;

556 557
	omap_dm_timer_enable(timer);

558
	if (!(timer->capability & OMAP_TIMER_ALWON)) {
559 560
		if (timer->get_context_loss_count &&
			timer->get_context_loss_count(&timer->pdev->dev) !=
561
				timer->ctx_loss_count)
562 563 564
			omap_timer_restore_context(timer);
	}

565
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
566
	if (autoreload) {
567
		l |= OMAP_TIMER_CTRL_AR;
568 569
		omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
	} else {
570
		l &= ~OMAP_TIMER_CTRL_AR;
571
	}
572 573
	l |= OMAP_TIMER_CTRL_ST;

574
	__omap_dm_timer_load_start(timer, l, load, timer->posted);
575 576 577 578 579

	/* Save the context */
	timer->context.tclr = l;
	timer->context.tldr = load;
	timer->context.tcrr = load;
580
	return 0;
581
}
582
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
583

584
int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
585
			     unsigned int match)
586 587 588
{
	u32 l;

589 590 591
	if (unlikely(!timer))
		return -EINVAL;

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

	/* Save the context */
	timer->context.tclr = l;
	timer->context.tmar = match;
	omap_dm_timer_disable(timer);
605
	return 0;
606
}
607
EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
608

609
int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
610
			   int toggle, int trigger)
611 612 613
{
	u32 l;

614 615 616
	if (unlikely(!timer))
		return -EINVAL;

617
	omap_dm_timer_enable(timer);
618
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
619 620 621 622 623 624 625
	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;
626
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
627 628 629 630

	/* Save the context */
	timer->context.tclr = l;
	omap_dm_timer_disable(timer);
631
	return 0;
632
}
633
EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
634

635
int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
636 637 638
{
	u32 l;

639 640 641
	if (unlikely(!timer))
		return -EINVAL;

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

	/* Save the context */
	timer->context.tclr = l;
	omap_dm_timer_disable(timer);
654
	return 0;
655
}
656
EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
657

658
int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
659
				  unsigned int value)
660
{
661 662 663
	if (unlikely(!timer))
		return -EINVAL;

664
	omap_dm_timer_enable(timer);
665
	__omap_dm_timer_int_enable(timer, value);
666 667 668 669 670

	/* Save the context */
	timer->context.tier = value;
	timer->context.twer = value;
	omap_dm_timer_disable(timer);
671
	return 0;
672
}
673
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
674

675
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
676
{
677 678
	unsigned int l;

679 680
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
681 682 683
		return 0;
	}

684
	l = __raw_readl(timer->irq_stat);
685 686

	return l;
687
}
688
EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
689

690
int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
691
{
692 693 694
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
		return -EINVAL;

695
	__omap_dm_timer_write_status(timer, value);
696 697
	/* Save the context */
	timer->context.tisr = value;
698
	return 0;
699
}
700
EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
701

702
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
703
{
704 705
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not iavailable or enabled.\n", __func__);
706 707 708
		return 0;
	}

709
	return __omap_dm_timer_read_counter(timer, timer->posted);
710
}
711
EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
712

713
int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
T
Timo Teras 已提交
714
{
715 716 717
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
		return -EINVAL;
718 719
	}

720
	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
721 722 723

	/* Save the context */
	timer->context.tcrr = value;
724
	return 0;
T
Timo Teras 已提交
725
}
726
EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
T
Timo Teras 已提交
727

728
int omap_dm_timers_active(void)
729
{
730
	struct omap_dm_timer *timer;
731

732
	list_for_each_entry(timer, &omap_timer_list, node) {
733
		if (!timer->reserved)
734 735
			continue;

736
		if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
737
		    OMAP_TIMER_CTRL_ST) {
738
			return 1;
739
		}
740 741 742
	}
	return 0;
}
743
EXPORT_SYMBOL_GPL(omap_dm_timers_active);
744

745 746 747 748 749 750 751 752 753 754 755
/**
 * 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;
756 757
	struct resource *mem, *irq;
	struct device *dev = &pdev->dev;
758 759
	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;

760
	if (!pdata && !dev->of_node) {
761
		dev_err(dev, "%s: no platform data.\n", __func__);
762 763 764 765 766
		return -ENODEV;
	}

	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (unlikely(!irq)) {
767
		dev_err(dev, "%s: no IRQ resource.\n", __func__);
768 769 770 771 772
		return -ENODEV;
	}

	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (unlikely(!mem)) {
773
		dev_err(dev, "%s: no memory resource.\n", __func__);
774 775 776
		return -ENODEV;
	}

777
	timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL);
778
	if (!timer) {
779 780
		dev_err(dev, "%s: memory alloc failed!\n", __func__);
		return  -ENOMEM;
781 782
	}

783
	timer->io_base = devm_request_and_ioremap(dev, mem);
784
	if (!timer->io_base) {
785 786
		dev_err(dev, "%s: region already claimed.\n", __func__);
		return -ENOMEM;
787 788
	}

789 790 791 792 793 794 795 796 797 798 799
	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;
800
		timer->errata = pdata->timer_errata;
801 802
		timer->capability = pdata->timer_capability;
		timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
803
		timer->get_context_loss_count = pdata->get_context_loss_count;
804 805
	}

806 807 808
	timer->irq = irq->start;
	timer->pdev = pdev;

809
	/* Skip pm_runtime_enable for OMAP1 */
810
	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
811 812
		pm_runtime_enable(dev);
		pm_runtime_irq_safe(dev);
813 814
	}

815
	if (!timer->reserved) {
816
		pm_runtime_get_sync(dev);
817
		__omap_dm_timer_init_regs(timer);
818
		pm_runtime_put(dev);
819 820
	}

821 822 823 824 825
	/* 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);

826
	dev_dbg(dev, "Device Probed.\n");
827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846

	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)
847 848
		if (!strcmp(dev_name(&timer->pdev->dev),
			    dev_name(&pdev->dev))) {
849 850 851 852 853 854 855 856 857
			list_del(&timer->node);
			ret = 0;
			break;
		}
	spin_unlock_irqrestore(&dm_timer_lock, flags);

	return ret;
}

858 859 860 861 862 863
static const struct of_device_id omap_timer_match[] = {
	{ .compatible = "ti,omap2-timer", },
	{},
};
MODULE_DEVICE_TABLE(of, omap_timer_match);

864 865
static struct platform_driver omap_dm_timer_driver = {
	.probe  = omap_dm_timer_probe,
866
	.remove = __devexit_p(omap_dm_timer_remove),
867 868
	.driver = {
		.name   = "omap_timer",
869
		.of_match_table = of_match_ptr(omap_timer_match),
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890
	},
};

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