timer.c 19.1 KB
Newer Older
1
/*
2
 * linux/arch/arm/mach-omap2/timer.c
3
4
5
 *
 * OMAP2 GP timer support.
 *
6
7
 * Copyright (C) 2009 Nokia Corporation
 *
8
9
10
11
12
 * Update to use new clocksource/clockevent layers
 * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
 * Copyright (C) 2007 MontaVista Software, Inc.
 *
 * Original driver:
13
14
 * Copyright (C) 2005 Nokia Corporation
 * Author: Paul Mundt <paul.mundt@nokia.com>
15
 *         Juha Yrjölä <juha.yrjola@nokia.com>
16
 * OMAP Dual-mode timer framework support by Timo Teras
17
18
19
 *
 * Some parts based off of TI's 24xx code:
 *
20
 * Copyright (C) 2004-2009 Texas Instruments, Inc.
21
22
 *
 * Roughly modelled after the OMAP1 MPU timer code.
23
 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
24
25
26
27
28
29
30
31
32
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License. See the file "COPYING" in the main directory of this archive
 * for more details.
 */
#include <linux/init.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/err.h>
33
#include <linux/clk.h>
34
#include <linux/delay.h>
35
#include <linux/irq.h>
36
37
#include <linux/clocksource.h>
#include <linux/clockchips.h>
38
#include <linux/slab.h>
39
#include <linux/of.h>
40
41
#include <linux/of_address.h>
#include <linux/of_irq.h>
42
43
#include <linux/platform_device.h>
#include <linux/platform_data/dmtimer-omap.h>
44

45
#include <asm/mach/time.h>
46
#include <asm/smp_twd.h>
47
#include <asm/sched_clock.h>
48

49
#include "omap_hwmod.h"
50
#include "omap_device.h"
51
#include <plat/counter-32k.h>
52
#include <plat/dmtimer.h>
53
#include "omap-pm.h"
54

55
#include "soc.h"
56
#include "common.h"
57
#include "powerdomain.h"
58

59
60
61
62
63
#define REALTIME_COUNTER_BASE				0x48243200
#define INCREMENTER_NUMERATOR_OFFSET			0x10
#define INCREMENTER_DENUMERATOR_RELOAD_OFFSET		0x14
#define NUMERATOR_DENUMERATOR_MASK			0xfffff000

64
65
66
/* Clockevent code */

static struct omap_dm_timer clkev;
67
static struct clock_event_device clockevent_gpt;
68

69
static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
70
{
71
72
	struct clock_event_device *evt = &clockevent_gpt;

73
	__omap_dm_timer_write_status(&clkev, OMAP_TIMER_INT_OVERFLOW);
74

75
	evt->event_handler(evt);
76
77
78
79
	return IRQ_HANDLED;
}

static struct irqaction omap2_gp_timer_irq = {
80
	.name		= "gp_timer",
Bernhard Walle's avatar
Bernhard Walle committed
81
	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
82
83
84
	.handler	= omap2_gp_timer_interrupt,
};

85
86
static int omap2_gp_timer_set_next_event(unsigned long cycles,
					 struct clock_event_device *evt)
87
{
88
	__omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST,
89
				   0xffffffff - cycles, OMAP_TIMER_POSTED);
90
91
92
93
94
95
96
97
98

	return 0;
}

static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
				    struct clock_event_device *evt)
{
	u32 period;

99
	__omap_dm_timer_stop(&clkev, OMAP_TIMER_POSTED, clkev.rate);
100
101
102

	switch (mode) {
	case CLOCK_EVT_MODE_PERIODIC:
103
		period = clkev.rate / HZ;
104
		period -= 1;
105
		/* Looks like we need to first set the load value separately */
106
		__omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG,
107
				      0xffffffff - period, OMAP_TIMER_POSTED);
108
		__omap_dm_timer_load_start(&clkev,
109
					OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
110
					0xffffffff - period, OMAP_TIMER_POSTED);
111
112
113
114
115
116
117
118
119
120
121
122
		break;
	case CLOCK_EVT_MODE_ONESHOT:
		break;
	case CLOCK_EVT_MODE_UNUSED:
	case CLOCK_EVT_MODE_SHUTDOWN:
	case CLOCK_EVT_MODE_RESUME:
		break;
	}
}

static struct clock_event_device clockevent_gpt = {
	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
123
	.rating		= 300,
124
125
126
127
	.set_next_event	= omap2_gp_timer_set_next_event,
	.set_mode	= omap2_gp_timer_set_mode,
};

128
129
130
131
132
133
134
135
136
137
138
static struct property device_disabled = {
	.name = "status",
	.length = sizeof("disabled"),
	.value = "disabled",
};

static struct of_device_id omap_timer_match[] __initdata = {
	{ .compatible = "ti,omap2-timer", },
	{ }
};

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/**
 * omap_get_timer_dt - get a timer using device-tree
 * @match	- device-tree match structure for matching a device type
 * @property	- optional timer property to match
 *
 * Helper function to get a timer during early boot using device-tree for use
 * as kernel system timer. Optionally, the property argument can be used to
 * select a timer with a specific property. Once a timer is found then mark
 * the timer node in device-tree as disabled, to prevent the kernel from
 * registering this timer as a platform device and so no one else can use it.
 */
static struct device_node * __init omap_get_timer_dt(struct of_device_id *match,
						     const char *property)
{
	struct device_node *np;

	for_each_matching_node(np, match) {
156
		if (!of_device_is_available(np))
157
158
			continue;

159
		if (property && !of_get_property(np, property, NULL))
160
161
			continue;

162
163
164
165
166
167
		if (!property && (of_get_property(np, "ti,timer-alwon", NULL) ||
				  of_get_property(np, "ti,timer-dsp", NULL) ||
				  of_get_property(np, "ti,timer-pwm", NULL) ||
				  of_get_property(np, "ti,timer-secure", NULL)))
			continue;

168
		of_add_property(np, &device_disabled);
169
170
171
172
173
174
		return np;
	}

	return NULL;
}

175
176
177
178
179
180
181
182
/**
 * omap_dmtimer_init - initialisation function when device tree is used
 *
 * For secure OMAP3 devices, timers with device type "timer-secure" cannot
 * be used by the kernel as they are reserved. Therefore, to prevent the
 * kernel registering these devices remove them dynamically from the device
 * tree on boot.
 */
183
static void __init omap_dmtimer_init(void)
184
185
186
187
188
189
190
191
{
	struct device_node *np;

	if (!cpu_is_omap34xx())
		return;

	/* If we are a secure device, remove any secure timer nodes */
	if ((omap_type() != OMAP2_DEVICE_TYPE_GP)) {
192
193
194
		np = omap_get_timer_dt(omap_timer_match, "ti,timer-secure");
		if (np)
			of_node_put(np);
195
196
197
	}
}

198
199
200
201
202
/**
 * omap_dm_timer_get_errata - get errata flags for a timer
 *
 * Get the timer errata flags that are specific to the OMAP device being used.
 */
203
static u32 __init omap_dm_timer_get_errata(void)
204
205
206
207
208
209
210
{
	if (cpu_is_omap24xx())
		return 0;

	return OMAP_TIMER_ERRATA_I103_I767;
}

211
static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
212
213
214
215
					 const char *fck_source,
					 const char *property,
					 const char **timer_name,
					 int posted)
216
{
217
	char name[10]; /* 10 = sizeof("gptXX_Xck0") */
218
219
	const char *oh_name;
	struct device_node *np;
220
	struct omap_hwmod *oh;
221
	struct resource irq, mem;
222
	struct clk *src;
223
	int r = 0;
224

225
	if (of_have_populated_dt()) {
226
		np = omap_get_timer_dt(omap_timer_match, property);
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
		if (!np)
			return -ENODEV;

		of_property_read_string_index(np, "ti,hwmods", 0, &oh_name);
		if (!oh_name)
			return -ENODEV;

		timer->irq = irq_of_parse_and_map(np, 0);
		if (!timer->irq)
			return -ENXIO;

		timer->io_base = of_iomap(np, 0);

		of_node_put(np);
	} else {
242
		if (omap_dm_timer_reserve_systimer(timer->id))
243
244
			return -ENODEV;

245
		sprintf(name, "timer%d", timer->id);
246
247
248
249
		oh_name = name;
	}

	oh = omap_hwmod_lookup(oh_name);
250
251
252
	if (!oh)
		return -ENODEV;

253
254
	*timer_name = oh->name;

255
256
	if (!of_have_populated_dt()) {
		r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL,
257
						   &irq);
258
259
		if (r)
			return -ENXIO;
260
		timer->irq = irq.start;
261
262

		r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL,
263
						   &mem);
264
265
266
267
		if (r)
			return -ENXIO;

		/* Static mapping, never released */
268
		timer->io_base = ioremap(mem.start, mem.end - mem.start);
269
	}
270
271
272
273
274

	if (!timer->io_base)
		return -ENXIO;

	/* After the dmtimer is using hwmod these clocks won't be needed */
275
	timer->fclk = clk_get(NULL, omap_hwmod_get_main_clk(oh));
276
	if (IS_ERR(timer->fclk))
277
		return PTR_ERR(timer->fclk);
278

279
280
281
	src = clk_get(NULL, fck_source);
	if (IS_ERR(src))
		return PTR_ERR(src);
282

283
284
285
286
287
	if (clk_get_parent(timer->fclk) != src) {
		r = clk_set_parent(timer->fclk, src);
		if (r < 0) {
			pr_warn("%s: %s cannot set source\n", __func__,
				oh->name);
288
			clk_put(src);
289
			return r;
290
291
		}
	}
292

293
294
	clk_put(src);

295
296
	omap_hwmod_setup_one(oh_name);
	omap_hwmod_enable(oh);
297
	__omap_dm_timer_init_regs(timer);
298

299
300
301
302
303
304
	if (posted)
		__omap_dm_timer_enable_posted(timer);

	/* Check that the intended posted configuration matches the actual */
	if (posted != timer->posted)
		return -EINVAL;
305

306
	timer->rate = clk_get_rate(timer->fclk);
307
	timer->reserved = 1;
308

309
	return r;
310
}
311

312
static void __init omap2_gp_clockevent_init(int gptimer_id,
313
314
						const char *fck_source,
						const char *property)
315
316
{
	int res;
317

318
	clkev.id = gptimer_id;
319
320
321
322
323
324
325
326
327
	clkev.errata = omap_dm_timer_get_errata();

	/*
	 * For clock-event timers we never read the timer counter and
	 * so we are not impacted by errata i103 and i767. Therefore,
	 * we can safely ignore this errata for clock-event timers.
	 */
	__omap_dm_timer_override_errata(&clkev, OMAP_TIMER_ERRATA_I103_I767);

328
	res = omap_dm_timer_init_one(&clkev, fck_source, property,
329
				     &clockevent_gpt.name, OMAP_TIMER_POSTED);
330
	BUG_ON(res);
331

332
	omap2_gp_timer_irq.dev_id = &clkev;
333
	setup_irq(clkev.irq, &omap2_gp_timer_irq);
334

335
	__omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
336

337
338
	clockevent_gpt.cpumask = cpu_possible_mask;
	clockevent_gpt.irq = omap_dm_timer_get_irq(&clkev);
339
340
341
	clockevents_config_and_register(&clockevent_gpt, clkev.rate,
					3, /* Timer internal resynch latency */
					0xffffffff);
342

343
344
	pr_info("OMAP clockevent source: %s at %lu Hz\n", clockevent_gpt.name,
		clkev.rate);
345
346
}

347
/* Clocksource code */
348
static struct omap_dm_timer clksrc;
349
static bool use_gptimer_clksrc;
350

351
352
353
/*
 * clocksource
 */
354
static cycle_t clocksource_read_cycles(struct clocksource *cs)
355
{
356
	return (cycle_t)__omap_dm_timer_read_counter(&clksrc,
357
						     OMAP_TIMER_NONPOSTED);
358
359
360
361
362
363
364
365
366
}

static struct clocksource clocksource_gpt = {
	.rating		= 300,
	.read		= clocksource_read_cycles,
	.mask		= CLOCKSOURCE_MASK(32),
	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
};

367
static u32 notrace dmtimer_read_sched_clock(void)
368
{
369
	if (clksrc.reserved)
370
		return __omap_dm_timer_read_counter(&clksrc,
371
						    OMAP_TIMER_NONPOSTED);
372

373
	return 0;
374
375
}

376
377
378
379
380
static struct of_device_id omap_counter_match[] __initdata = {
	{ .compatible = "ti,omap-counter32k", },
	{ }
};

381
/* Setup free-running counter for clocksource */
382
static int __init __maybe_unused omap2_sync32k_clocksource_init(void)
383
384
{
	int ret;
385
	struct device_node *np = NULL;
386
387
388
389
	struct omap_hwmod *oh;
	void __iomem *vbase;
	const char *oh_name = "counter_32k";

390
391
392
393
394
395
396
397
398
399
400
401
402
403
	/*
	 * If device-tree is present, then search the DT blob
	 * to see if the 32kHz counter is supported.
	 */
	if (of_have_populated_dt()) {
		np = omap_get_timer_dt(omap_counter_match, NULL);
		if (!np)
			return -ENODEV;

		of_property_read_string_index(np, "ti,hwmods", 0, &oh_name);
		if (!oh_name)
			return -ENODEV;
	}

404
405
406
407
408
409
410
411
412
	/*
	 * First check hwmod data is available for sync32k counter
	 */
	oh = omap_hwmod_lookup(oh_name);
	if (!oh || oh->slaves_cnt == 0)
		return -ENODEV;

	omap_hwmod_setup_one(oh_name);

413
414
415
416
417
418
419
	if (np) {
		vbase = of_iomap(np, 0);
		of_node_put(np);
	} else {
		vbase = omap_hwmod_get_mpu_rt_va(oh);
	}

420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
	if (!vbase) {
		pr_warn("%s: failed to get counter_32k resource\n", __func__);
		return -ENXIO;
	}

	ret = omap_hwmod_enable(oh);
	if (ret) {
		pr_warn("%s: failed to enable counter_32k module (%d)\n",
							__func__, ret);
		return ret;
	}

	ret = omap_init_clocksource_32k(vbase);
	if (ret) {
		pr_warn("%s: failed to initialize counter_32k as a clocksource (%d)\n",
							__func__, ret);
		omap_hwmod_idle(oh);
	}

	return ret;
}

static void __init omap2_gptimer_clocksource_init(int gptimer_id,
443
444
						  const char *fck_source,
						  const char *property)
445
446
447
{
	int res;

448
	clksrc.id = gptimer_id;
449
450
	clksrc.errata = omap_dm_timer_get_errata();

451
	res = omap_dm_timer_init_one(&clksrc, fck_source, property,
452
				     &clocksource_gpt.name,
453
				     OMAP_TIMER_NONPOSTED);
454
	BUG_ON(res);
455

456
	__omap_dm_timer_load_start(&clksrc,
457
				   OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0,
458
				   OMAP_TIMER_NONPOSTED);
459
	setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate);
460

461
462
463
	if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
		pr_err("Could not register clocksource %s\n",
			clocksource_gpt.name);
464
	else
465
466
		pr_info("OMAP clocksource: %s at %lu Hz\n",
			clocksource_gpt.name, clksrc.rate);
467
468
}

469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
#ifdef CONFIG_SOC_HAS_REALTIME_COUNTER
/*
 * The realtime counter also called master counter, is a free-running
 * counter, which is related to real time. It produces the count used
 * by the CPU local timer peripherals in the MPU cluster. The timer counts
 * at a rate of 6.144 MHz. Because the device operates on different clocks
 * in different power modes, the master counter shifts operation between
 * clocks, adjusting the increment per clock in hardware accordingly to
 * maintain a constant count rate.
 */
static void __init realtime_counter_init(void)
{
	void __iomem *base;
	static struct clk *sys_clk;
	unsigned long rate;
	unsigned int reg, num, den;

	base = ioremap(REALTIME_COUNTER_BASE, SZ_32);
	if (!base) {
		pr_err("%s: ioremap failed\n", __func__);
		return;
	}
491
	sys_clk = clk_get(NULL, "sys_clkin");
492
	if (IS_ERR(sys_clk)) {
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
		pr_err("%s: failed to get system clock handle\n", __func__);
		iounmap(base);
		return;
	}

	rate = clk_get_rate(sys_clk);
	/* Numerator/denumerator values refer TRM Realtime Counter section */
	switch (rate) {
	case 1200000:
		num = 64;
		den = 125;
		break;
	case 1300000:
		num = 768;
		den = 1625;
		break;
	case 19200000:
		num = 8;
		den = 25;
		break;
	case 2600000:
		num = 384;
		den = 1625;
		break;
	case 2700000:
		num = 256;
		den = 1125;
		break;
	case 38400000:
	default:
		/* Program it for 38.4 MHz */
		num = 4;
		den = 25;
		break;
	}

	/* Program numerator and denumerator registers */
	reg = __raw_readl(base + INCREMENTER_NUMERATOR_OFFSET) &
			NUMERATOR_DENUMERATOR_MASK;
	reg |= num;
	__raw_writel(reg, base + INCREMENTER_NUMERATOR_OFFSET);

	reg = __raw_readl(base + INCREMENTER_NUMERATOR_OFFSET) &
			NUMERATOR_DENUMERATOR_MASK;
	reg |= den;
	__raw_writel(reg, base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET);

	iounmap(base);
}
#else
static inline void __init realtime_counter_init(void)
{}
#endif

547
#define OMAP_SYS_GP_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop,	\
548
			       clksrc_nr, clksrc_src, clksrc_prop)	\
Stephen Warren's avatar
Stephen Warren committed
549
void __init omap##name##_gptimer_timer_init(void)			\
550
551
552
{									\
	omap_dmtimer_init();						\
	omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop);	\
553
554
	omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src,		\
					clksrc_prop);			\
555
556
557
}

#define OMAP_SYS_32K_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop,	\
558
				clksrc_nr, clksrc_src, clksrc_prop)	\
Stephen Warren's avatar
Stephen Warren committed
559
void __init omap##name##_sync32k_timer_init(void)		\
560
{									\
561
	omap_dmtimer_init();						\
562
	omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop);	\
563
564
	/* Enable the use of clocksource="gp_timer" kernel parameter */	\
	if (use_gptimer_clksrc)						\
565
566
		omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src,	\
						clksrc_prop);		\
567
568
	else								\
		omap2_sync32k_clocksource_init();			\
569
570
571
}

#ifdef CONFIG_ARCH_OMAP2
572
OMAP_SYS_32K_TIMER_INIT(2, 1, "timer_32k_ck", "ti,timer-alwon",
573
			2, "timer_sys_ck", NULL);
574
#endif /* CONFIG_ARCH_OMAP2 */
575
576

#ifdef CONFIG_ARCH_OMAP3
577
OMAP_SYS_32K_TIMER_INIT(3, 1, "timer_32k_ck", "ti,timer-alwon",
578
			2, "timer_sys_ck", NULL);
579
OMAP_SYS_32K_TIMER_INIT(3_secure, 12, "secure_32k_fck", "ti,timer-secure",
580
			2, "timer_sys_ck", NULL);
581
#endif /* CONFIG_ARCH_OMAP3 */
582

583
#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM33XX)
584
585
OMAP_SYS_GP_TIMER_INIT(3, 2, "timer_sys_ck", NULL,
		       1, "timer_sys_ck", "ti,timer-alwon");
586
#endif
587

588
#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5)
589
590
static OMAP_SYS_32K_TIMER_INIT(4, 1, "timer_32k_ck", "ti,timer-alwon",
			       2, "sys_clkin_ck", NULL);
591
#endif
592

593
#ifdef CONFIG_ARCH_OMAP4
594
#ifdef CONFIG_LOCAL_TIMERS
595
static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29);
Stephen Warren's avatar
Stephen Warren committed
596
void __init omap4_local_timer_init(void)
597
{
598
	omap4_sync32k_timer_init();
599
600
601
602
	/* Local timers are not supprted on OMAP4430 ES1.0 */
	if (omap_rev() != OMAP4430_REV_ES1_0) {
		int err;

603
		if (of_have_populated_dt()) {
604
			clocksource_of_init();
605
606
607
			return;
		}

608
609
610
611
		err = twd_local_timer_register(&twd_local_timer);
		if (err)
			pr_err("twd_local_timer_register failed %d\n", err);
	}
612
}
613
#else /* CONFIG_LOCAL_TIMERS */
Stephen Warren's avatar
Stephen Warren committed
614
void __init omap4_local_timer_init(void)
615
{
616
	omap4_sync32k_timer_init();
617
618
619
}
#endif /* CONFIG_LOCAL_TIMERS */
#endif /* CONFIG_ARCH_OMAP4 */
620

621
#ifdef CONFIG_SOC_OMAP5
Stephen Warren's avatar
Stephen Warren committed
622
void __init omap5_realtime_timer_init(void)
623
{
624
	omap4_sync32k_timer_init();
625
	realtime_counter_init();
626

627
	clocksource_of_init();
628
}
629
#endif /* CONFIG_SOC_OMAP5 */
630

631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
/**
 * omap_timer_init - build and register timer device with an
 * associated timer hwmod
 * @oh:	timer hwmod pointer to be used to build timer device
 * @user:	parameter that can be passed from calling hwmod API
 *
 * Called by omap_hwmod_for_each_by_class to register each of the timer
 * devices present in the system. The number of timer devices is known
 * by parsing through the hwmod database for a given class name. At the
 * end of function call memory is allocated for timer device and it is
 * registered to the framework ready to be proved by the driver.
 */
static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
{
	int id;
	int ret = 0;
	char *name = "omap_timer";
	struct dmtimer_platform_data *pdata;
649
	struct platform_device *pdev;
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
	struct omap_timer_capability_dev_attr *timer_dev_attr;

	pr_debug("%s: %s\n", __func__, oh->name);

	/* on secure device, do not register secure timer */
	timer_dev_attr = oh->dev_attr;
	if (omap_type() != OMAP2_DEVICE_TYPE_GP && timer_dev_attr)
		if (timer_dev_attr->timer_capability == OMAP_TIMER_SECURE)
			return ret;

	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
	if (!pdata) {
		pr_err("%s: No memory for [%s]\n", __func__, oh->name);
		return -ENOMEM;
	}

	/*
	 * Extract the IDs from name field in hwmod database
	 * and use the same for constructing ids' for the
	 * timer devices. In a way, we are avoiding usage of
	 * static variable witin the function to do the same.
	 * CAUTION: We have to be careful and make sure the
	 * name in hwmod database does not change in which case
	 * we might either make corresponding change here or
	 * switch back static variable mechanism.
	 */
	sscanf(oh->name, "timer%2d", &id);

678
679
	if (timer_dev_attr)
		pdata->timer_capability = timer_dev_attr->timer_capability;
680

681
	pdata->timer_errata = omap_dm_timer_get_errata();
682
683
	pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;

684
	pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata));
685

686
	if (IS_ERR(pdev)) {
687
688
689
690
691
692
693
694
695
		pr_err("%s: Can't build omap_device for %s: %s.\n",
			__func__, name, oh->name);
		ret = -EINVAL;
	}

	kfree(pdata);

	return ret;
}
696
697
698
699
700
701
702
703
704
705
706

/**
 * omap2_dm_timer_init - top level regular device initialization
 *
 * Uses dedicated hwmod api to parse through hwmod database for
 * given class name and then build and register the timer device.
 */
static int __init omap2_dm_timer_init(void)
{
	int ret;

707
708
709
710
	/* If dtb is there, the devices will be created dynamically */
	if (of_have_populated_dt())
		return -ENODEV;

711
712
713
714
715
716
717
718
	ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL);
	if (unlikely(ret)) {
		pr_err("%s: device registration failed.\n", __func__);
		return -EINVAL;
	}

	return 0;
}
719
omap_arch_initcall(omap2_dm_timer_init);
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744

/**
 * omap2_override_clocksource - clocksource override with user configuration
 *
 * Allows user to override default clocksource, using kernel parameter
 *   clocksource="gp_timer"	(For all OMAP2PLUS architectures)
 *
 * Note that, here we are using same standard kernel parameter "clocksource=",
 * and not introducing any OMAP specific interface.
 */
static int __init omap2_override_clocksource(char *str)
{
	if (!str)
		return 0;
	/*
	 * For OMAP architecture, we only have two options
	 *    - sync_32k (default)
	 *    - gp_timer (sys_clk based)
	 */
	if (!strcmp(str, "gp_timer"))
		use_gptimer_clksrc = true;

	return 0;
}
early_param("clocksource", omap2_override_clocksource);