dmtimer.c 23.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/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
enum {
	REQUEST_ANY = 0,
	REQUEST_BY_ID,
	REQUEST_BY_CAP,
	REQUEST_BY_NODE,
};

62 63 64 65 66 67 68 69
/**
 * 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.
70 71
 */
static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
72
{
73 74
	WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
	return __omap_dm_timer_read(timer, reg, timer->posted);
75
}
76

77 78 79 80 81 82 83 84 85
/**
 * 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.
86 87 88
 */
static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
						u32 value)
89
{
90 91
	WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
	__omap_dm_timer_write(timer, reg, value, timer->posted);
92 93
}

94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
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);
}

111
static int omap_dm_timer_reset(struct omap_dm_timer *timer)
112
{
113
	u32 l, timeout = 100000;
114

115 116
	if (timer->revision != 1)
		return -EINVAL;
117

118 119 120 121 122 123 124 125 126 127
	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;
128
	}
129

130 131 132 133 134 135 136 137
	/* 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;
138 139
}

140
static int omap_dm_timer_prepare(struct omap_dm_timer *timer)
141
{
142 143
	int rc;

J
Jon Hunter 已提交
144 145 146 147 148 149 150 151 152 153 154
	/*
	 * 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;
		}
155 156
	}

157 158
	omap_dm_timer_enable(timer);

159 160 161 162 163 164 165
	if (timer->capability & OMAP_TIMER_NEEDS_RESET) {
		rc = omap_dm_timer_reset(timer);
		if (rc) {
			omap_dm_timer_disable(timer);
			return rc;
		}
	}
166

167 168
	__omap_dm_timer_enable_posted(timer);
	omap_dm_timer_disable(timer);
169

170
	return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
171 172
}

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
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;
}

188
static struct omap_dm_timer *_omap_dm_timer_request(int req_type, void *data)
189
{
190
	struct omap_dm_timer *timer = NULL, *t;
191
	struct device_node *np = NULL;
192
	unsigned long flags;
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
	u32 cap = 0;
	int id = 0;

	switch (req_type) {
	case REQUEST_BY_ID:
		id = *(int *)data;
		break;
	case REQUEST_BY_CAP:
		cap = *(u32 *)data;
		break;
	case REQUEST_BY_NODE:
		np = (struct device_node *)data;
		break;
	default:
		/* REQUEST_ANY */
		break;
	}
210 211

	spin_lock_irqsave(&dm_timer_lock, flags);
212 213
	list_for_each_entry(t, &omap_timer_list, node) {
		if (t->reserved)
214 215
			continue;

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
		switch (req_type) {
		case REQUEST_BY_ID:
			if (id == t->pdev->id) {
				timer = t;
				timer->reserved = 1;
				goto found;
			}
			break;
		case REQUEST_BY_CAP:
			if (cap == (t->capability & 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)
					goto found;
			}
			break;
		case REQUEST_BY_NODE:
			if (np == t->pdev->dev.of_node) {
				timer = t;
				timer->reserved = 1;
				goto found;
			}
			break;
		default:
			/* REQUEST_ANY */
			timer = t;
			timer->reserved = 1;
			goto found;
		}
257
	}
258
found:
259
	spin_unlock_irqrestore(&dm_timer_lock, flags);
260

261 262 263
	if (timer && omap_dm_timer_prepare(timer)) {
		timer->reserved = 0;
		timer = NULL;
264
	}
265

266 267
	if (!timer)
		pr_debug("%s: timer request failed!\n", __func__);
T
Timo Teras 已提交
268

269 270
	return timer;
}
271 272 273 274 275

struct omap_dm_timer *omap_dm_timer_request(void)
{
	return _omap_dm_timer_request(REQUEST_ANY, NULL);
}
276
EXPORT_SYMBOL_GPL(omap_dm_timer_request);
277 278

struct omap_dm_timer *omap_dm_timer_request_specific(int id)
279
{
280 281
	/* Requesting timer by ID is not supported when device tree is used */
	if (of_have_populated_dt()) {
282
		pr_warn("%s: Please use omap_dm_timer_request_by_cap/node()\n",
283 284 285 286
			__func__);
		return NULL;
	}

287
	return _omap_dm_timer_request(REQUEST_BY_ID, &id);
288
}
289
EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
290

291 292 293 294 295 296 297 298 299 300 301
/**
 * 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)
{
302 303 304
	return _omap_dm_timer_request(REQUEST_BY_CAP, &cap);
}
EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap);
305

306 307 308 309 310 311 312 313 314 315
/**
 * omap_dm_timer_request_by_node - Request a timer by device-tree node
 * @np:		Pointer to device-tree timer node
 *
 * Request a timer based upon a device node pointer. Returns pointer to
 * timer handle on success and a NULL pointer on failure.
 */
struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np)
{
	if (!np)
316 317
		return NULL;

318
	return _omap_dm_timer_request(REQUEST_BY_NODE, np);
319
}
320
EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_node);
321

322
int omap_dm_timer_free(struct omap_dm_timer *timer)
323
{
324 325 326
	if (unlikely(!timer))
		return -EINVAL;

327
	clk_put(timer->fclk);
328

329 330
	WARN_ON(!timer->reserved);
	timer->reserved = 0;
331
	return 0;
332
}
333
EXPORT_SYMBOL_GPL(omap_dm_timer_free);
334

335 336
void omap_dm_timer_enable(struct omap_dm_timer *timer)
{
337 338
	int c;

339
	pm_runtime_get_sync(&timer->pdev->dev);
340 341 342 343 344 345 346 347

	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;
			}
348 349
		} else {
			omap_timer_restore_context(timer);
350 351
		}
	}
352
}
353
EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
354 355 356

void omap_dm_timer_disable(struct omap_dm_timer *timer)
{
357
	pm_runtime_put_sync(&timer->pdev->dev);
358
}
359
EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
360

361 362
int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
{
363 364 365
	if (timer)
		return timer->irq;
	return -EINVAL;
366
}
367
EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
368 369

#if defined(CONFIG_ARCH_OMAP1)
370
#include <mach/hardware.h>
371 372 373 374 375 376
/**
 * 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)
{
377 378 379
	int i = 0;
	struct omap_dm_timer *timer = NULL;
	unsigned long flags;
380 381 382 383 384 385

	/* 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 */
386 387
	spin_lock_irqsave(&dm_timer_lock, flags);
	list_for_each_entry(timer, &omap_timer_list, node) {
388 389
		u32 l;

390
		l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
391 392
		if (l & OMAP_TIMER_CTRL_ST) {
			if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
393 394 395 396
				inputmask &= ~(1 << 1);
			else
				inputmask &= ~(1 << 2);
		}
397
		i++;
398
	}
399
	spin_unlock_irqrestore(&dm_timer_lock, flags);
400 401 402

	return inputmask;
}
403
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
404

405
#else
406

407
struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
408
{
409 410 411
	if (timer)
		return timer->fclk;
	return NULL;
412
}
413
EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
414

415 416 417
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
{
	BUG();
418 419

	return 0;
420
}
421
EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
422

423
#endif
424

425
int omap_dm_timer_trigger(struct omap_dm_timer *timer)
426
{
427 428 429
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
		return -EINVAL;
430 431
	}

432
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
433
	return 0;
434
}
435
EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
436

437
int omap_dm_timer_start(struct omap_dm_timer *timer)
438 439
{
	u32 l;
440

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

444 445
	omap_dm_timer_enable(timer);

446 447 448 449 450
	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);
	}
451 452 453

	/* Save the context */
	timer->context.tclr = l;
454
	return 0;
455
}
456
EXPORT_SYMBOL_GPL(omap_dm_timer_start);
457

458
int omap_dm_timer_stop(struct omap_dm_timer *timer)
459
{
460
	unsigned long rate = 0;
461

462 463 464
	if (unlikely(!timer))
		return -EINVAL;

465
	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
466
		rate = clk_get_rate(timer->fclk);
467

468
	__omap_dm_timer_stop(timer, timer->posted, rate);
469

470 471 472 473 474 475 476 477
	/*
	 * 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);
478
	return 0;
479
}
480
EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
481

482
int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
483
{
484
	int ret;
485
	char *parent_name = NULL;
486
	struct clk *parent;
487 488 489 490 491 492
	struct dmtimer_platform_data *pdata;

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

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

494
	if (source < 0 || source >= 3)
495
		return -EINVAL;
496

497 498 499 500 501
	/*
	 * 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
	 */
502
	if (pdata && pdata->set_timer_src)
503 504
		return pdata->set_timer_src(timer->pdev, source);

505
	if (!timer->fclk)
506 507 508 509
		return -EINVAL;

	switch (source) {
	case OMAP_TIMER_SRC_SYS_CLK:
510
		parent_name = "timer_sys_ck";
511 512 513
		break;

	case OMAP_TIMER_SRC_32_KHZ:
514
		parent_name = "timer_32k_ck";
515 516 517
		break;

	case OMAP_TIMER_SRC_EXT_CLK:
518
		parent_name = "timer_ext_ck";
519 520 521 522 523 524
		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);
525
		return -EINVAL;
526 527
	}

528
	ret = clk_set_parent(timer->fclk, parent);
529 530 531 532 533
	if (IS_ERR_VALUE(ret))
		pr_err("%s: failed to set %s as parent\n", __func__,
			parent_name);

	clk_put(parent);
534 535

	return ret;
536
}
537
EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
538

539
int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
540
			    unsigned int load)
541 542
{
	u32 l;
543

544 545 546
	if (unlikely(!timer))
		return -EINVAL;

547
	omap_dm_timer_enable(timer);
548
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
549 550 551 552
	if (autoreload)
		l |= OMAP_TIMER_CTRL_AR;
	else
		l &= ~OMAP_TIMER_CTRL_AR;
553
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
554
	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
555

556
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
557 558 559 560
	/* Save the context */
	timer->context.tclr = l;
	timer->context.tldr = load;
	omap_dm_timer_disable(timer);
561
	return 0;
562
}
563
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
564

565
/* Optimized set_load which removes costly spin wait in timer_start */
566
int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
567 568 569 570
                            unsigned int load)
{
	u32 l;

571 572 573
	if (unlikely(!timer))
		return -EINVAL;

574 575
	omap_dm_timer_enable(timer);

576
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
577
	if (autoreload) {
578
		l |= OMAP_TIMER_CTRL_AR;
579 580
		omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
	} else {
581
		l &= ~OMAP_TIMER_CTRL_AR;
582
	}
583 584
	l |= OMAP_TIMER_CTRL_ST;

585
	__omap_dm_timer_load_start(timer, l, load, timer->posted);
586 587 588 589 590

	/* Save the context */
	timer->context.tclr = l;
	timer->context.tldr = load;
	timer->context.tcrr = load;
591
	return 0;
592
}
593
EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
594

595
int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
596
			     unsigned int match)
597 598 599
{
	u32 l;

600 601 602
	if (unlikely(!timer))
		return -EINVAL;

603
	omap_dm_timer_enable(timer);
604
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
T
Timo Teras 已提交
605
	if (enable)
606 607 608 609
		l |= OMAP_TIMER_CTRL_CE;
	else
		l &= ~OMAP_TIMER_CTRL_CE;
	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
610
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
611 612 613 614 615

	/* Save the context */
	timer->context.tclr = l;
	timer->context.tmar = match;
	omap_dm_timer_disable(timer);
616
	return 0;
617
}
618
EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
619

620
int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
621
			   int toggle, int trigger)
622 623 624
{
	u32 l;

625 626 627
	if (unlikely(!timer))
		return -EINVAL;

628
	omap_dm_timer_enable(timer);
629
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
630 631 632 633 634 635 636
	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;
637
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
638 639 640 641

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

646
int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
647 648 649
{
	u32 l;

650 651 652
	if (unlikely(!timer))
		return -EINVAL;

653
	omap_dm_timer_enable(timer);
654
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
655 656 657 658 659
	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
	if (prescaler >= 0x00 && prescaler <= 0x07) {
		l |= OMAP_TIMER_CTRL_PRE;
		l |= prescaler << 2;
	}
660
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
661 662 663 664

	/* Save the context */
	timer->context.tclr = l;
	omap_dm_timer_disable(timer);
665
	return 0;
666
}
667
EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
668

669
int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
670
				  unsigned int value)
671
{
672 673 674
	if (unlikely(!timer))
		return -EINVAL;

675
	omap_dm_timer_enable(timer);
676
	__omap_dm_timer_int_enable(timer, value);
677 678 679 680 681

	/* Save the context */
	timer->context.tier = value;
	timer->context.twer = value;
	omap_dm_timer_disable(timer);
682
	return 0;
683
}
684
EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
685

686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
/**
 * 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);

717
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
718
{
719 720
	unsigned int l;

721 722
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
723 724 725
		return 0;
	}

726
	l = __raw_readl(timer->irq_stat);
727 728

	return l;
729
}
730
EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
731

732
int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
733
{
734 735 736
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
		return -EINVAL;

737
	__omap_dm_timer_write_status(timer, value);
738

739
	return 0;
740
}
741
EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
742

743
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
744
{
745 746
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not iavailable or enabled.\n", __func__);
747 748 749
		return 0;
	}

750
	return __omap_dm_timer_read_counter(timer, timer->posted);
751
}
752
EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
753

754
int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
T
Timo Teras 已提交
755
{
756 757 758
	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
		pr_err("%s: timer not available or enabled.\n", __func__);
		return -EINVAL;
759 760
	}

761
	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
762 763 764

	/* Save the context */
	timer->context.tcrr = value;
765
	return 0;
T
Timo Teras 已提交
766
}
767
EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
T
Timo Teras 已提交
768

769
int omap_dm_timers_active(void)
770
{
771
	struct omap_dm_timer *timer;
772

773
	list_for_each_entry(timer, &omap_timer_list, node) {
774
		if (!timer->reserved)
775 776
			continue;

777
		if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
778
		    OMAP_TIMER_CTRL_ST) {
779
			return 1;
780
		}
781 782 783
	}
	return 0;
}
784
EXPORT_SYMBOL_GPL(omap_dm_timers_active);
785

786 787 788 789 790 791 792
/**
 * 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.
 */
793
static int omap_dm_timer_probe(struct platform_device *pdev)
794 795 796
{
	unsigned long flags;
	struct omap_dm_timer *timer;
797 798
	struct resource *mem, *irq;
	struct device *dev = &pdev->dev;
799 800
	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;

801
	if (!pdata && !dev->of_node) {
802
		dev_err(dev, "%s: no platform data.\n", __func__);
803 804 805 806 807
		return -ENODEV;
	}

	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (unlikely(!irq)) {
808
		dev_err(dev, "%s: no IRQ resource.\n", __func__);
809 810 811 812 813
		return -ENODEV;
	}

	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (unlikely(!mem)) {
814
		dev_err(dev, "%s: no memory resource.\n", __func__);
815 816 817
		return -ENODEV;
	}

818
	timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL);
819
	if (!timer) {
820 821
		dev_err(dev, "%s: memory alloc failed!\n", __func__);
		return  -ENOMEM;
822 823
	}

824 825 826
	timer->io_base = devm_ioremap_resource(dev, mem);
	if (IS_ERR(timer->io_base))
		return PTR_ERR(timer->io_base);
827

828 829 830 831 832 833 834 835 836 837 838
	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;
839
		timer->errata = pdata->timer_errata;
840 841
		timer->capability = pdata->timer_capability;
		timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
842
		timer->get_context_loss_count = pdata->get_context_loss_count;
843 844
	}

845 846 847
	timer->irq = irq->start;
	timer->pdev = pdev;

848
	/* Skip pm_runtime_enable for OMAP1 */
849
	if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
850 851
		pm_runtime_enable(dev);
		pm_runtime_irq_safe(dev);
852 853
	}

854
	if (!timer->reserved) {
855
		pm_runtime_get_sync(dev);
856
		__omap_dm_timer_init_regs(timer);
857
		pm_runtime_put(dev);
858 859
	}

860 861 862 863 864
	/* 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);

865
	dev_dbg(dev, "Device Probed.\n");
866 867 868 869 870 871 872 873 874 875 876 877

	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.
 */
878
static int omap_dm_timer_remove(struct platform_device *pdev)
879 880 881 882 883 884 885
{
	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)
886 887
		if (!strcmp(dev_name(&timer->pdev->dev),
			    dev_name(&pdev->dev))) {
888 889 890 891 892 893 894 895 896
			list_del(&timer->node);
			ret = 0;
			break;
		}
	spin_unlock_irqrestore(&dm_timer_lock, flags);

	return ret;
}

897
static const struct of_device_id omap_timer_match[] = {
898 899 900 901 902 903
	{ .compatible = "ti,omap2420-timer", },
	{ .compatible = "ti,omap3430-timer", },
	{ .compatible = "ti,omap4430-timer", },
	{ .compatible = "ti,omap5430-timer", },
	{ .compatible = "ti,am335x-timer", },
	{ .compatible = "ti,am335x-timer-1ms", },
904 905 906 907
	{},
};
MODULE_DEVICE_TABLE(of, omap_timer_match);

908 909
static struct platform_driver omap_dm_timer_driver = {
	.probe  = omap_dm_timer_probe,
910
	.remove = omap_dm_timer_remove,
911 912
	.driver = {
		.name   = "omap_timer",
913
		.of_match_table = of_match_ptr(omap_timer_match),
914 915 916 917
	},
};

early_platform_init("earlytimer", &omap_dm_timer_driver);
918
module_platform_driver(omap_dm_timer_driver);
919 920 921 922 923

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