dmtimer.c 19.4 KB
Newer Older
1 2 3 4 5 6
/*
 * linux/arch/arm/plat-omap/dmtimer.c
 *
 * OMAP Dual-Mode Timers
 *
 * Copyright (C) 2005 Nokia Corporation
7 8
 * OMAP2 support by Juha Yrjola
 * API improvements and OMAP2 clock framework support by Timo Teras
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 *
 * 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.
 */

#include <linux/init.h>
30 31 32 33 34
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/clk.h>
#include <linux/delay.h>
35
#include <asm/arch/hardware.h>
36 37 38 39
#include <asm/arch/dmtimer.h>
#include <asm/io.h>
#include <asm/arch/irqs.h>

40
/* register offsets */
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
#define _OMAP_TIMER_ID_OFFSET		0x00
#define _OMAP_TIMER_OCP_CFG_OFFSET	0x10
#define _OMAP_TIMER_SYS_STAT_OFFSET	0x14
#define _OMAP_TIMER_STAT_OFFSET		0x18
#define _OMAP_TIMER_INT_EN_OFFSET	0x1c
#define _OMAP_TIMER_WAKEUP_EN_OFFSET	0x20
#define _OMAP_TIMER_CTRL_OFFSET		0x24
#define		OMAP_TIMER_CTRL_GPOCFG		(1 << 14)
#define		OMAP_TIMER_CTRL_CAPTMODE	(1 << 13)
#define		OMAP_TIMER_CTRL_PT		(1 << 12)
#define		OMAP_TIMER_CTRL_TCM_LOWTOHIGH	(0x1 << 8)
#define		OMAP_TIMER_CTRL_TCM_HIGHTOLOW	(0x2 << 8)
#define		OMAP_TIMER_CTRL_TCM_BOTHEDGES	(0x3 << 8)
#define		OMAP_TIMER_CTRL_SCPWM		(1 << 7)
#define		OMAP_TIMER_CTRL_CE		(1 << 6) /* compare enable */
#define		OMAP_TIMER_CTRL_PRE		(1 << 5) /* prescaler enable */
#define		OMAP_TIMER_CTRL_PTV_SHIFT	2 /* prescaler value shift */
#define		OMAP_TIMER_CTRL_POSTED		(1 << 2)
#define		OMAP_TIMER_CTRL_AR		(1 << 1) /* auto-reload enable */
#define		OMAP_TIMER_CTRL_ST		(1 << 0) /* start timer */
#define _OMAP_TIMER_COUNTER_OFFSET	0x28
#define _OMAP_TIMER_LOAD_OFFSET		0x2c
#define _OMAP_TIMER_TRIGGER_OFFSET	0x30
#define _OMAP_TIMER_WRITE_PEND_OFFSET	0x34
#define		WP_NONE			0	/* no write pending bit */
#define		WP_TCLR			(1 << 0)
#define		WP_TCRR			(1 << 1)
#define		WP_TLDR			(1 << 2)
#define		WP_TTGR			(1 << 3)
#define		WP_TMAR			(1 << 4)
#define		WP_TPIR			(1 << 5)
#define		WP_TNIR			(1 << 6)
#define		WP_TCVR			(1 << 7)
#define		WP_TOCR			(1 << 8)
#define		WP_TOWR			(1 << 9)
#define _OMAP_TIMER_MATCH_OFFSET	0x38
#define _OMAP_TIMER_CAPTURE_OFFSET	0x3c
#define _OMAP_TIMER_IF_CTRL_OFFSET	0x40
#define _OMAP_TIMER_CAPTURE2_OFFSET		0x44	/* TCAR2, 34xx only */
#define _OMAP_TIMER_TICK_POS_OFFSET		0x48	/* TPIR, 34xx only */
#define _OMAP_TIMER_TICK_NEG_OFFSET		0x4c	/* TNIR, 34xx only */
#define _OMAP_TIMER_TICK_COUNT_OFFSET		0x50	/* TCVR, 34xx only */
#define _OMAP_TIMER_TICK_INT_MASK_SET_OFFSET	0x54	/* TOCR, 34xx only */
#define _OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET	0x58	/* TOWR, 34xx only */

/* register offsets with the write pending bit encoded */
#define	WPSHIFT					16

#define OMAP_TIMER_ID_REG			(_OMAP_TIMER_ID_OFFSET \
							| (WP_NONE << WPSHIFT))

#define OMAP_TIMER_OCP_CFG_REG			(_OMAP_TIMER_OCP_CFG_OFFSET \
							| (WP_NONE << WPSHIFT))

#define OMAP_TIMER_SYS_STAT_REG			(_OMAP_TIMER_SYS_STAT_OFFSET \
							| (WP_NONE << WPSHIFT))

#define OMAP_TIMER_STAT_REG			(_OMAP_TIMER_STAT_OFFSET \
							| (WP_NONE << WPSHIFT))

#define OMAP_TIMER_INT_EN_REG			(_OMAP_TIMER_INT_EN_OFFSET \
							| (WP_NONE << WPSHIFT))

#define OMAP_TIMER_WAKEUP_EN_REG		(_OMAP_TIMER_WAKEUP_EN_OFFSET \
							| (WP_NONE << WPSHIFT))

#define OMAP_TIMER_CTRL_REG			(_OMAP_TIMER_CTRL_OFFSET \
							| (WP_TCLR << WPSHIFT))

#define OMAP_TIMER_COUNTER_REG			(_OMAP_TIMER_COUNTER_OFFSET \
							| (WP_TCRR << WPSHIFT))

#define OMAP_TIMER_LOAD_REG			(_OMAP_TIMER_LOAD_OFFSET \
							| (WP_TLDR << WPSHIFT))

#define OMAP_TIMER_TRIGGER_REG			(_OMAP_TIMER_TRIGGER_OFFSET \
							| (WP_TTGR << WPSHIFT))

#define OMAP_TIMER_WRITE_PEND_REG		(_OMAP_TIMER_WRITE_PEND_OFFSET \
							| (WP_NONE << WPSHIFT))

#define OMAP_TIMER_MATCH_REG			(_OMAP_TIMER_MATCH_OFFSET \
							| (WP_TMAR << WPSHIFT))

#define OMAP_TIMER_CAPTURE_REG			(_OMAP_TIMER_CAPTURE_OFFSET \
							| (WP_NONE << WPSHIFT))

#define OMAP_TIMER_IF_CTRL_REG			(_OMAP_TIMER_IF_CTRL_OFFSET \
							| (WP_NONE << WPSHIFT))

#define OMAP_TIMER_CAPTURE2_REG			(_OMAP_TIMER_CAPTURE2_OFFSET \
							| (WP_NONE << WPSHIFT))

#define OMAP_TIMER_TICK_POS_REG			(_OMAP_TIMER_TICK_POS_OFFSET \
							| (WP_TPIR << WPSHIFT))

#define OMAP_TIMER_TICK_NEG_REG			(_OMAP_TIMER_TICK_NEG_OFFSET \
							| (WP_TNIR << WPSHIFT))

#define OMAP_TIMER_TICK_COUNT_REG		(_OMAP_TIMER_TICK_COUNT_OFFSET \
							| (WP_TCVR << WPSHIFT))

#define OMAP_TIMER_TICK_INT_MASK_SET_REG				\
		(_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT))

#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG				\
		(_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT))
148 149 150 151

struct omap_dm_timer {
	unsigned long phys_base;
	int irq;
152
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
153 154 155 156
	struct clk *iclk, *fclk;
#endif
	void __iomem *io_base;
	unsigned reserved:1;
157
	unsigned enabled:1;
158
	unsigned posted:1;
159 160 161 162
};

#ifdef CONFIG_ARCH_OMAP1

163 164
#define omap_dm_clk_enable(x)
#define omap_dm_clk_disable(x)
165 166 167
#define omap2_dm_timers			NULL
#define omap2_dm_source_names		NULL
#define omap2_dm_source_clocks		NULL
168 169 170
#define omap3_dm_timers			NULL
#define omap3_dm_source_names		NULL
#define omap3_dm_source_clocks		NULL
171

172
static struct omap_dm_timer omap1_dm_timers[] = {
173 174 175 176 177 178
	{ .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 },
	{ .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 },
	{ .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 },
	{ .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 },
	{ .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 },
	{ .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 },
179 180
	{ .phys_base = 0xfffb7400, .irq = INT_1610_GPTIMER7 },
	{ .phys_base = 0xfffbd400, .irq = INT_1610_GPTIMER8 },
181
};
182

183 184
static const int dm_timer_count = ARRAY_SIZE(omap1_dm_timers);

185
#elif defined(CONFIG_ARCH_OMAP2)
186

187 188 189
#define omap_dm_clk_enable(x)		clk_enable(x)
#define omap_dm_clk_disable(x)		clk_disable(x)
#define omap1_dm_timers			NULL
190 191 192
#define omap3_dm_timers			NULL
#define omap3_dm_source_names		NULL
#define omap3_dm_source_clocks		NULL
193

194
static struct omap_dm_timer omap2_dm_timers[] = {
195 196 197 198 199 200 201 202 203 204 205 206
	{ .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
	{ .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
	{ .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 },
	{ .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 },
	{ .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 },
	{ .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 },
	{ .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 },
	{ .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 },
	{ .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 },
	{ .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
	{ .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
	{ .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 },
207 208
};

209
static const char *omap2_dm_source_names[] __initdata = {
T
Timo Teras 已提交
210 211
	"sys_ck",
	"func_32k_ck",
212 213
	"alt_ck",
	NULL
T
Timo Teras 已提交
214 215
};

216 217
static struct clk **omap2_dm_source_clocks[3];
static const int dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
T
Timo Teras 已提交
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
#elif defined(CONFIG_ARCH_OMAP3)

#define omap_dm_clk_enable(x)		clk_enable(x)
#define omap_dm_clk_disable(x)		clk_disable(x)
#define omap1_dm_timers			NULL
#define omap2_dm_timers			NULL
#define omap2_dm_source_names		NULL
#define omap2_dm_source_clocks		NULL

static struct omap_dm_timer omap3_dm_timers[] = {
	{ .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
	{ .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 },
	{ .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 },
	{ .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 },
	{ .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 },
	{ .phys_base = 0x4903A000, .irq = INT_24XX_GPTIMER6 },
	{ .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 },
	{ .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 },
	{ .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
	{ .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
	{ .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
	{ .phys_base = 0x48304000, .irq = INT_24XX_GPTIMER12 },
};

static const char *omap3_dm_source_names[] __initdata = {
	"sys_ck",
	"omap_32k_fck",
	NULL
};

static struct clk **omap3_dm_source_clocks[2];
static const int dm_timer_count = ARRAY_SIZE(omap3_dm_timers);

252 253 254 255 256 257
#else

#error OMAP architecture not supported!

#endif

258 259 260 261
static struct omap_dm_timer *dm_timers;
static char **dm_source_names;
static struct clk **dm_source_clocks;

262 263
static spinlock_t dm_timer_lock;

264 265 266 267 268 269
/*
 * Reads timer registers in posted and non-posted mode. 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.
 */
static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
270
{
271 272 273 274 275
	if (timer->posted)
		while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
				& (reg >> WPSHIFT))
			cpu_relax();
	return readl(timer->io_base + (reg & 0xff));
276
}
277

278 279 280 281 282 283 284 285
/*
 * Writes timer registers in posted and non-posted mode. 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.
 */
static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
						u32 value)
286
{
287 288 289 290 291
	if (timer->posted)
		while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff))
				& (reg >> WPSHIFT))
			cpu_relax();
	writel(value, timer->io_base + (reg & 0xff));
292 293
}

294
static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
295
{
296 297 298 299 300 301 302 303 304 305
	int c;

	c = 0;
	while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) {
		c++;
		if (c > 100000) {
			printk(KERN_ERR "Timer failed to reset\n");
			return;
		}
	}
306 307
}

308 309 310 311
static void omap_dm_timer_reset(struct omap_dm_timer *timer)
{
	u32 l;

312
	if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
313 314 315
		omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
		omap_dm_timer_wait_for_reset(timer);
	}
316
	omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
317 318

	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG);
319 320 321 322 323 324 325 326 327
	l |= 0x02 << 3;  /* Set to smart-idle mode */
	l |= 0x2 << 8;   /* Set clock activity to perserve f-clock on idle */

	/*
	 * Enable wake-up only for GPT1 on OMAP2 CPUs.
	 * FIXME: All timers should have wake-up enabled and clear
	 * PRCM status.
	 */
	if (cpu_class_is_omap2() && (timer == &dm_timers[0]))
328
		l |= 1 << 2;
329
	omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l);
330 331 332 333 334

	/* Match hardware reset default of posted mode */
	omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
			OMAP_TIMER_CTRL_POSTED);
	timer->posted = 1;
335 336
}

T
Timo Teras 已提交
337
static void omap_dm_timer_prepare(struct omap_dm_timer *timer)
338
{
339
	omap_dm_timer_enable(timer);
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
	omap_dm_timer_reset(timer);
}

struct omap_dm_timer *omap_dm_timer_request(void)
{
	struct omap_dm_timer *timer = NULL;
	unsigned long flags;
	int i;

	spin_lock_irqsave(&dm_timer_lock, flags);
	for (i = 0; i < dm_timer_count; i++) {
		if (dm_timers[i].reserved)
			continue;

		timer = &dm_timers[i];
T
Timo Teras 已提交
355
		timer->reserved = 1;
356 357 358 359
		break;
	}
	spin_unlock_irqrestore(&dm_timer_lock, flags);

T
Timo Teras 已提交
360 361 362
	if (timer != NULL)
		omap_dm_timer_prepare(timer);

363 364 365 366
	return timer;
}

struct omap_dm_timer *omap_dm_timer_request_specific(int id)
367 368
{
	struct omap_dm_timer *timer;
369
	unsigned long flags;
370

371 372 373 374
	spin_lock_irqsave(&dm_timer_lock, flags);
	if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) {
		spin_unlock_irqrestore(&dm_timer_lock, flags);
		printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n",
375
		       __FILE__, __LINE__, __func__, id);
376 377 378
		dump_stack();
		return NULL;
	}
379

380
	timer = &dm_timers[id-1];
T
Timo Teras 已提交
381
	timer->reserved = 1;
382 383
	spin_unlock_irqrestore(&dm_timer_lock, flags);

T
Timo Teras 已提交
384 385
	omap_dm_timer_prepare(timer);

386
	return timer;
387 388
}

389 390
void omap_dm_timer_free(struct omap_dm_timer *timer)
{
391
	omap_dm_timer_enable(timer);
392
	omap_dm_timer_reset(timer);
393
	omap_dm_timer_disable(timer);
394

395 396 397 398
	WARN_ON(!timer->reserved);
	timer->reserved = 0;
}

399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
void omap_dm_timer_enable(struct omap_dm_timer *timer)
{
	if (timer->enabled)
		return;

	omap_dm_clk_enable(timer->fclk);
	omap_dm_clk_enable(timer->iclk);

	timer->enabled = 1;
}

void omap_dm_timer_disable(struct omap_dm_timer *timer)
{
	if (!timer->enabled)
		return;

	omap_dm_clk_disable(timer->iclk);
	omap_dm_clk_disable(timer->fclk);

	timer->enabled = 0;
}

421 422 423 424 425 426 427
int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
{
	return timer->irq;
}

#if defined(CONFIG_ARCH_OMAP1)

428 429 430 431 432 433
/**
 * 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)
{
434
	int i;
435 436 437 438 439 440

	/* 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 */
441 442 443
	for (i = 0; i < dm_timer_count; i++) {
		u32 l;

444
		l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG);
445 446
		if (l & OMAP_TIMER_CTRL_ST) {
			if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
447 448 449 450
				inputmask &= ~(1 << 1);
			else
				inputmask &= ~(1 << 2);
		}
451
	}
452 453 454 455

	return inputmask;
}

456
#elif defined(CONFIG_ARCH_OMAP2) || defined (CONFIG_ARCH_OMAP3)
457

458
struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
459
{
460
	return timer->fclk;
461
}
462

463 464 465
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
{
	BUG();
466 467

	return 0;
468 469
}

470
#endif
471

472
void omap_dm_timer_trigger(struct omap_dm_timer *timer)
473
{
474
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
475 476
}

477 478 479
void omap_dm_timer_start(struct omap_dm_timer *timer)
{
	u32 l;
480

481 482 483 484 485 486
	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);
	}
}
487

488
void omap_dm_timer_stop(struct omap_dm_timer *timer)
489
{
490
	u32 l;
491

492 493 494 495
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
	if (l & OMAP_TIMER_CTRL_ST) {
		l &= ~0x1;
		omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
496 497 498
	}
}

499
#ifdef CONFIG_ARCH_OMAP1
500

501
void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
502
{
503 504
	int n = (timer - dm_timers) << 1;
	u32 l;
505

506 507 508
	l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
	l |= source << n;
	omap_writel(l, MOD_CONF_CTRL_1);
509 510
}

511
#else
512

513
void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
514
{
515 516 517 518
	if (source < 0 || source >= 3)
		return;

	clk_disable(timer->fclk);
T
Timo Teras 已提交
519
	clk_set_parent(timer->fclk, dm_source_clocks[source]);
520 521 522 523
	clk_enable(timer->fclk);

	/* When the functional clock disappears, too quick writes seem to
	 * cause an abort. */
524
	__delay(150000);
525 526
}

527
#endif
528

529 530
void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
			    unsigned int load)
531 532
{
	u32 l;
533

534
	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
535 536 537 538
	if (autoreload)
		l |= OMAP_TIMER_CTRL_AR;
	else
		l &= ~OMAP_TIMER_CTRL_AR;
539
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
540
	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
541 542 543 544 545

	/* REVISIT: hw feature, ttgr overtaking tldr? */
	while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)))
		cpu_relax();

546
	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
547 548
}

549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
/* Optimized set_load which removes costly spin wait in timer_start */
void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
                            unsigned int load)
{
	u32 l;

	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
	if (autoreload)
		l |= OMAP_TIMER_CTRL_AR;
	else
		l &= ~OMAP_TIMER_CTRL_AR;
	l |= OMAP_TIMER_CTRL_ST;

	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, load);
	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}

567 568
void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
			     unsigned int match)
569 570 571 572
{
	u32 l;

	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
T
Timo Teras 已提交
573
	if (enable)
574 575 576
		l |= OMAP_TIMER_CTRL_CE;
	else
		l &= ~OMAP_TIMER_CTRL_CE;
577
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
578
	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
579 580
}

581 582
void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
			   int toggle, int trigger)
583 584 585 586
{
	u32 l;

	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
587 588 589 590 591 592 593
	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;
594 595 596
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}

597
void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
598 599 600 601
{
	u32 l;

	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
602 603 604 605 606
	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
	if (prescaler >= 0x00 && prescaler <= 0x07) {
		l |= OMAP_TIMER_CTRL_PRE;
		l |= prescaler << 2;
	}
607 608 609
	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}

610 611
void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
				  unsigned int value)
612
{
613
	omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
614
	omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, value);
615 616
}

617
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
618
{
619 620 621 622 623
	unsigned int l;

	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);

	return l;
624 625
}

626
void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
627
{
628
	omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value);
629 630
}

631
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
632
{
633 634 635 636 637
	unsigned int l;

	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);

	return l;
638 639
}

T
Timo Teras 已提交
640 641
void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
{
642
	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
T
Timo Teras 已提交
643 644
}

645
int omap_dm_timers_active(void)
646
{
647
	int i;
648

649 650
	for (i = 0; i < dm_timer_count; i++) {
		struct omap_dm_timer *timer;
651

652
		timer = &dm_timers[i];
653 654 655 656

		if (!timer->enabled)
			continue;

657
		if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
658
		    OMAP_TIMER_CTRL_ST) {
659
			return 1;
660
		}
661 662 663
	}
	return 0;
}
664

665
int __init omap_dm_timer_init(void)
666 667
{
	struct omap_dm_timer *timer;
668 669
	int i;

670
	if (!(cpu_is_omap16xx() || cpu_class_is_omap2()))
671
		return -ENODEV;
672 673

	spin_lock_init(&dm_timer_lock);
674 675 676 677 678 679 680

	if (cpu_class_is_omap1())
		dm_timers = omap1_dm_timers;
	else if (cpu_is_omap24xx()) {
		dm_timers = omap2_dm_timers;
		dm_source_names = (char **)omap2_dm_source_names;
		dm_source_clocks = (struct clk **)omap2_dm_source_clocks;
681 682 683 684
	} else if (cpu_is_omap34xx()) {
		dm_timers = omap3_dm_timers;
		dm_source_names = (char **)omap3_dm_source_names;
		dm_source_clocks = (struct clk **)omap3_dm_source_clocks;
T
Timo Teras 已提交
685
	}
686 687 688 689 690

	if (cpu_class_is_omap2())
		for (i = 0; dm_source_names[i] != NULL; i++)
			dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]);

691 692
	if (cpu_is_omap243x())
		dm_timers[0].phys_base = 0x49018000;
T
Timo Teras 已提交
693

694 695
	for (i = 0; i < dm_timer_count; i++) {
		timer = &dm_timers[i];
696
		timer->io_base = (void __iomem *)io_p2v(timer->phys_base);
697
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
698 699 700 701 702 703 704
		if (cpu_class_is_omap2()) {
			char clk_name[16];
			sprintf(clk_name, "gpt%d_ick", i + 1);
			timer->iclk = clk_get(NULL, clk_name);
			sprintf(clk_name, "gpt%d_fck", i + 1);
			timer->fclk = clk_get(NULL, clk_name);
		}
705
#endif
706 707 708 709
	}

	return 0;
}