Blame view

arch/arm/mach-omap2/timer.c 12.6 KB
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
1
  /*
0f622e8ca   Tony Lindgren   omap2+: Rename ti...
2
   * linux/arch/arm/mach-omap2/timer.c
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
3
4
5
   *
   * OMAP2 GP timer support.
   *
f248076c0   Paul Walmsley   OMAP2/3 GPTIMER: ...
6
7
   * Copyright (C) 2009 Nokia Corporation
   *
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
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:
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
13
14
   * Copyright (C) 2005 Nokia Corporation
   * Author: Paul Mundt <paul.mundt@nokia.com>
96de0e252   Jan Engelhardt   Convert files to ...
15
   *         Juha Yrjölä <juha.yrjola@nokia.com>
77900a2fc   Timo Teras   ARM: OMAP: Port d...
16
   * OMAP Dual-mode timer framework support by Timo Teras
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
17
18
19
   *
   * Some parts based off of TI's 24xx code:
   *
44169075e   Santosh Shilimkar   ARM: OMAP4: Add m...
20
   * Copyright (C) 2004-2009 Texas Instruments, Inc.
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
21
22
   *
   * Roughly modelled after the OMAP1 MPU timer code.
44169075e   Santosh Shilimkar   ARM: OMAP4: Add m...
23
   * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
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>
f8ce25476   Russell King   [ARM] Move asm/ha...
33
  #include <linux/clk.h>
77900a2fc   Timo Teras   ARM: OMAP: Port d...
34
  #include <linux/delay.h>
e6687290a   Dirk Behme   ARM: OMAP: Fix wa...
35
  #include <linux/irq.h>
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
36
37
  #include <linux/clocksource.h>
  #include <linux/clockchips.h>
c345c8b09   Tarun Kanti DebBarma   ARM: OMAP2+: dmti...
38
  #include <linux/slab.h>
f8ce25476   Russell King   [ARM] Move asm/ha...
39

1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
40
  #include <asm/mach/time.h>
ce491cf85   Tony Lindgren   omap: headers: Mo...
41
  #include <plat/dmtimer.h>
39e1d4c18   Santosh Shilimkar   ARM: OMAP4: SMP: ...
42
  #include <asm/localtimer.h>
cbc943807   Paul Walmsley   OMAP2+: clocksour...
43
  #include <asm/sched_clock.h>
4e65331c6   Tony Lindgren   ARM: 7159/1: OMAP...
44
  #include "common.h"
38698bef5   Paul Walmsley   OMAP2+: clockeven...
45
  #include <plat/omap_hwmod.h>
c345c8b09   Tarun Kanti DebBarma   ARM: OMAP2+: dmti...
46
  #include <plat/omap_device.h>
b481113a8   Tarun Kanti DebBarma   ARM: OMAP: dmtime...
47
48
49
  #include <plat/omap-pm.h>
  
  #include "powerdomain.h"
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
50

aa5618899   Tony Lindgren   omap2+: Use dmtim...
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  /* Parent clocks, eventually these will come from the clock framework */
  
  #define OMAP2_MPU_SOURCE	"sys_ck"
  #define OMAP3_MPU_SOURCE	OMAP2_MPU_SOURCE
  #define OMAP4_MPU_SOURCE	"sys_clkin_ck"
  #define OMAP2_32K_SOURCE	"func_32k_ck"
  #define OMAP3_32K_SOURCE	"omap_32k_fck"
  #define OMAP4_32K_SOURCE	"sys_32k_ck"
  
  #ifdef CONFIG_OMAP_32K_TIMER
  #define OMAP2_CLKEV_SOURCE	OMAP2_32K_SOURCE
  #define OMAP3_CLKEV_SOURCE	OMAP3_32K_SOURCE
  #define OMAP4_CLKEV_SOURCE	OMAP4_32K_SOURCE
  #define OMAP3_SECURE_TIMER	12
  #else
  #define OMAP2_CLKEV_SOURCE	OMAP2_MPU_SOURCE
  #define OMAP3_CLKEV_SOURCE	OMAP3_MPU_SOURCE
  #define OMAP4_CLKEV_SOURCE	OMAP4_MPU_SOURCE
  #define OMAP3_SECURE_TIMER	1
  #endif
d8328f3b8   Paul Walmsley   OMAP: counter_32k...
71

f248076c0   Paul Walmsley   OMAP2/3 GPTIMER: ...
72
73
  /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
  #define MAX_GPTIMER_ID		12
0dad9faea   Tony Lindgren   ARM: OMAP: dmtime...
74
  static u32 sys_timer_reserved;
11a0186f3   Tony Lindgren   omap2+: Reserve c...
75

aa5618899   Tony Lindgren   omap2+: Use dmtim...
76
77
78
  /* Clockevent code */
  
  static struct omap_dm_timer clkev;
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
79
  static struct clock_event_device clockevent_gpt;
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
80

0cd61b68c   Linus Torvalds   Initial blind fix...
81
  static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
82
  {
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
83
  	struct clock_event_device *evt = &clockevent_gpt;
ee17f1147   Tony Lindgren   ARM: OMAP: Add su...
84
  	__omap_dm_timer_write_status(&clkev, OMAP_TIMER_INT_OVERFLOW);
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
85

5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
86
  	evt->event_handler(evt);
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
87
88
89
90
91
  	return IRQ_HANDLED;
  }
  
  static struct irqaction omap2_gp_timer_irq = {
  	.name		= "gp timer",
b30fabada   Bernhard Walle   Add IRQF_IRQPOLL ...
92
  	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
93
94
  	.handler	= omap2_gp_timer_interrupt,
  };
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
95
96
  static int omap2_gp_timer_set_next_event(unsigned long cycles,
  					 struct clock_event_device *evt)
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
97
  {
ee17f1147   Tony Lindgren   ARM: OMAP: Add su...
98
  	__omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST,
aa5618899   Tony Lindgren   omap2+: Use dmtim...
99
  						0xffffffff - cycles, 1);
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
100
101
102
103
104
105
106
107
  
  	return 0;
  }
  
  static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
  				    struct clock_event_device *evt)
  {
  	u32 period;
ee17f1147   Tony Lindgren   ARM: OMAP: Add su...
108
  	__omap_dm_timer_stop(&clkev, 1, clkev.rate);
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
109
110
111
  
  	switch (mode) {
  	case CLOCK_EVT_MODE_PERIODIC:
aa5618899   Tony Lindgren   omap2+: Use dmtim...
112
  		period = clkev.rate / HZ;
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
113
  		period -= 1;
aa5618899   Tony Lindgren   omap2+: Use dmtim...
114
  		/* Looks like we need to first set the load value separately */
ee17f1147   Tony Lindgren   ARM: OMAP: Add su...
115
  		__omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG,
aa5618899   Tony Lindgren   omap2+: Use dmtim...
116
  					0xffffffff - period, 1);
ee17f1147   Tony Lindgren   ARM: OMAP: Add su...
117
  		__omap_dm_timer_load_start(&clkev,
aa5618899   Tony Lindgren   omap2+: Use dmtim...
118
119
  					OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
  						0xffffffff - period, 1);
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  		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 = {
  	.name		= "gp timer",
  	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
  	.shift		= 32,
  	.set_next_event	= omap2_gp_timer_set_next_event,
  	.set_mode	= omap2_gp_timer_set_mode,
  };
aa5618899   Tony Lindgren   omap2+: Use dmtim...
137
138
139
  static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
  						int gptimer_id,
  						const char *fck_source)
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
140
  {
aa5618899   Tony Lindgren   omap2+: Use dmtim...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  	char name[10]; /* 10 = sizeof("gptXX_Xck0") */
  	struct omap_hwmod *oh;
  	size_t size;
  	int res = 0;
  
  	sprintf(name, "timer%d", gptimer_id);
  	omap_hwmod_setup_one(name);
  	oh = omap_hwmod_lookup(name);
  	if (!oh)
  		return -ENODEV;
  
  	timer->irq = oh->mpu_irqs[0].irq;
  	timer->phys_base = oh->slaves[0]->addr->pa_start;
  	size = oh->slaves[0]->addr->pa_end - timer->phys_base;
  
  	/* Static mapping, never released */
  	timer->io_base = ioremap(timer->phys_base, size);
  	if (!timer->io_base)
  		return -ENXIO;
  
  	/* After the dmtimer is using hwmod these clocks won't be needed */
  	sprintf(name, "gpt%d_fck", gptimer_id);
  	timer->fclk = clk_get(NULL, name);
  	if (IS_ERR(timer->fclk))
  		return -ENODEV;
  
  	sprintf(name, "gpt%d_ick", gptimer_id);
  	timer->iclk = clk_get(NULL, name);
  	if (IS_ERR(timer->iclk)) {
  		clk_put(timer->fclk);
  		return -ENODEV;
  	}
f248076c0   Paul Walmsley   OMAP2/3 GPTIMER: ...
173

aa5618899   Tony Lindgren   omap2+: Use dmtim...
174
  	omap_hwmod_enable(oh);
11a0186f3   Tony Lindgren   omap2+: Reserve c...
175
  	sys_timer_reserved |= (1 << (gptimer_id - 1));
aa5618899   Tony Lindgren   omap2+: Use dmtim...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  	if (gptimer_id != 12) {
  		struct clk *src;
  
  		src = clk_get(NULL, fck_source);
  		if (IS_ERR(src)) {
  			res = -EINVAL;
  		} else {
  			res = __omap_dm_timer_set_source(timer->fclk, src);
  			if (IS_ERR_VALUE(res))
  				pr_warning("%s: timer%i cannot set source
  ",
  						__func__, gptimer_id);
  			clk_put(src);
  		}
  	}
ee17f1147   Tony Lindgren   ARM: OMAP: Add su...
191
192
  	__omap_dm_timer_init_regs(timer);
  	__omap_dm_timer_reset(timer, 1, 1);
aa5618899   Tony Lindgren   omap2+: Use dmtim...
193
194
195
  	timer->posted = 1;
  
  	timer->rate = clk_get_rate(timer->fclk);
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
196

aa5618899   Tony Lindgren   omap2+: Use dmtim...
197
  	timer->reserved = 1;
38698bef5   Paul Walmsley   OMAP2+: clockeven...
198

aa5618899   Tony Lindgren   omap2+: Use dmtim...
199
200
  	return res;
  }
f248076c0   Paul Walmsley   OMAP2/3 GPTIMER: ...
201

aa5618899   Tony Lindgren   omap2+: Use dmtim...
202
203
204
205
  static void __init omap2_gp_clockevent_init(int gptimer_id,
  						const char *fck_source)
  {
  	int res;
f248076c0   Paul Walmsley   OMAP2/3 GPTIMER: ...
206

aa5618899   Tony Lindgren   omap2+: Use dmtim...
207
208
  	res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source);
  	BUG_ON(res);
f248076c0   Paul Walmsley   OMAP2/3 GPTIMER: ...
209

98e182a26   Tony Lindgren   omap2+: Remove gp...
210
  	omap2_gp_timer_irq.dev_id = (void *)&clkev;
aa5618899   Tony Lindgren   omap2+: Use dmtim...
211
  	setup_irq(clkev.irq, &omap2_gp_timer_irq);
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
212

ee17f1147   Tony Lindgren   ARM: OMAP: Add su...
213
  	__omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
aa5618899   Tony Lindgren   omap2+: Use dmtim...
214
215
  
  	clockevent_gpt.mult = div_sc(clkev.rate, NSEC_PER_SEC,
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
216
217
218
219
  				     clockevent_gpt.shift);
  	clockevent_gpt.max_delta_ns =
  		clockevent_delta2ns(0xffffffff, &clockevent_gpt);
  	clockevent_gpt.min_delta_ns =
df88acbbd   Aaro Koskinen   ARM: OMAP: gptime...
220
221
  		clockevent_delta2ns(3, &clockevent_gpt);
  		/* Timer internal resynch latency. */
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
222

320ab2b0b   Rusty Russell   cpumask: convert ...
223
  	clockevent_gpt.cpumask = cpumask_of(0);
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
224
  	clockevents_register_device(&clockevent_gpt);
aa5618899   Tony Lindgren   omap2+: Use dmtim...
225
226
227
228
  
  	pr_info("OMAP clockevent source: GPTIMER%d at %lu Hz
  ",
  		gptimer_id, clkev.rate);
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
229
  }
f248076c0   Paul Walmsley   OMAP2/3 GPTIMER: ...
230
  /* Clocksource code */
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
231
  #ifdef CONFIG_OMAP_32K_TIMER
0f622e8ca   Tony Lindgren   omap2+: Rename ti...
232
  /*
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
233
234
   * When 32k-timer is enabled, don't use GPTimer for clocksource
   * instead, just leave default clocksource which uses the 32k
d8328f3b8   Paul Walmsley   OMAP: counter_32k...
235
   * sync counter.  See clocksource setup in plat-omap/counter_32k.c
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
236
   */
3d05a3e80   Tony Lindgren   omap2+: Use dmtim...
237
  static void __init omap2_gp_clocksource_init(int unused, const char *dummy)
d8328f3b8   Paul Walmsley   OMAP: counter_32k...
238
239
240
  {
  	omap_init_clocksource_32k();
  }
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
241
  #else
3d05a3e80   Tony Lindgren   omap2+: Use dmtim...
242
243
  
  static struct omap_dm_timer clksrc;
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
244
245
246
  /*
   * clocksource
   */
8e19608e8   Magnus Damm   clocksource: pass...
247
  static cycle_t clocksource_read_cycles(struct clocksource *cs)
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
248
  {
ee17f1147   Tony Lindgren   ARM: OMAP: Add su...
249
  	return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 1);
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
250
251
252
253
254
255
256
  }
  
  static struct clocksource clocksource_gpt = {
  	.name		= "gp timer",
  	.rating		= 300,
  	.read		= clocksource_read_cycles,
  	.mask		= CLOCKSOURCE_MASK(32),
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
257
258
  	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
  };
2f0778afa   Marc Zyngier   ARM: 7205/2: sche...
259
  static u32 notrace dmtimer_read_sched_clock(void)
cbc943807   Paul Walmsley   OMAP2+: clocksour...
260
  {
3d05a3e80   Tony Lindgren   omap2+: Use dmtim...
261
  	if (clksrc.reserved)
2f0778afa   Marc Zyngier   ARM: 7205/2: sche...
262
  		return __omap_dm_timer_read_counter(clksrc.io_base, 1);
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
263

2f0778afa   Marc Zyngier   ARM: 7205/2: sche...
264
  	return 0;
3d05a3e80   Tony Lindgren   omap2+: Use dmtim...
265
266
267
268
269
270
271
272
273
274
  }
  
  /* Setup free-running counter for clocksource */
  static void __init omap2_gp_clocksource_init(int gptimer_id,
  						const char *fck_source)
  {
  	int res;
  
  	res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source);
  	BUG_ON(res);
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
275

3d05a3e80   Tony Lindgren   omap2+: Use dmtim...
276
277
278
  	pr_info("OMAP clocksource: GPTIMER%d at %lu Hz
  ",
  		gptimer_id, clksrc.rate);
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
279

ee17f1147   Tony Lindgren   ARM: OMAP: Add su...
280
  	__omap_dm_timer_load_start(&clksrc,
e9d0b97ee   Hemant Pedanekar   omap: timer: Set ...
281
  			OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
2f0778afa   Marc Zyngier   ARM: 7205/2: sche...
282
  	setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate);
cbc943807   Paul Walmsley   OMAP2+: clocksour...
283

3d05a3e80   Tony Lindgren   omap2+: Use dmtim...
284
285
286
287
  	if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
  		pr_err("Could not register clocksource %s
  ",
  			clocksource_gpt.name);
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
288
289
  }
  #endif
3d05a3e80   Tony Lindgren   omap2+: Use dmtim...
290
291
  #define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src,			\
  				clksrc_nr, clksrc_src)			\
e74984e46   Tony Lindgren   omap: Set separat...
292
293
  static void __init omap##name##_timer_init(void)			\
  {									\
aa5618899   Tony Lindgren   omap2+: Use dmtim...
294
  	omap2_gp_clockevent_init((clkev_nr), clkev_src);		\
3d05a3e80   Tony Lindgren   omap2+: Use dmtim...
295
  	omap2_gp_clocksource_init((clksrc_nr), clksrc_src);		\
e74984e46   Tony Lindgren   omap: Set separat...
296
297
298
299
300
301
302
303
  }
  
  #define OMAP_SYS_TIMER(name)						\
  struct sys_timer omap##name##_timer = {					\
  	.init	= omap##name##_timer_init,				\
  };
  
  #ifdef CONFIG_ARCH_OMAP2
3d05a3e80   Tony Lindgren   omap2+: Use dmtim...
304
  OMAP_SYS_TIMER_INIT(2, 1, OMAP2_CLKEV_SOURCE, 2, OMAP2_MPU_SOURCE)
e74984e46   Tony Lindgren   omap: Set separat...
305
306
307
308
  OMAP_SYS_TIMER(2)
  #endif
  
  #ifdef CONFIG_ARCH_OMAP3
3d05a3e80   Tony Lindgren   omap2+: Use dmtim...
309
  OMAP_SYS_TIMER_INIT(3, 1, OMAP3_CLKEV_SOURCE, 2, OMAP3_MPU_SOURCE)
e74984e46   Tony Lindgren   omap: Set separat...
310
  OMAP_SYS_TIMER(3)
3d05a3e80   Tony Lindgren   omap2+: Use dmtim...
311
312
  OMAP_SYS_TIMER_INIT(3_secure, OMAP3_SECURE_TIMER, OMAP3_CLKEV_SOURCE,
  			2, OMAP3_MPU_SOURCE)
e74984e46   Tony Lindgren   omap: Set separat...
313
314
315
316
317
  OMAP_SYS_TIMER(3_secure)
  #endif
  
  #ifdef CONFIG_ARCH_OMAP4
  static void __init omap4_timer_init(void)
5a3a388fb   Kevin Hilman   ARM: OMAP: Timer3...
318
  {
39e1d4c18   Santosh Shilimkar   ARM: OMAP4: SMP: ...
319
  #ifdef CONFIG_LOCAL_TIMERS
e74984e46   Tony Lindgren   omap: Set separat...
320
321
  	twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256);
  	BUG_ON(!twd_base);
39e1d4c18   Santosh Shilimkar   ARM: OMAP4: SMP: ...
322
  #endif
aa5618899   Tony Lindgren   omap2+: Use dmtim...
323
  	omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE);
3d05a3e80   Tony Lindgren   omap2+: Use dmtim...
324
  	omap2_gp_clocksource_init(2, OMAP4_MPU_SOURCE);
1dbae815a   Tony Lindgren   [ARM] 3145/1: OMA...
325
  }
e74984e46   Tony Lindgren   omap: Set separat...
326
327
  OMAP_SYS_TIMER(4)
  #endif
c345c8b09   Tarun Kanti DebBarma   ARM: OMAP2+: dmti...
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  
  /**
   * omap2_dm_timer_set_src - change the timer input clock source
   * @pdev:	timer platform device pointer
   * @source:	array index of parent clock source
   */
  static int omap2_dm_timer_set_src(struct platform_device *pdev, int source)
  {
  	int ret;
  	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
  	struct clk *fclk, *parent;
  	char *parent_name = NULL;
  
  	fclk = clk_get(&pdev->dev, "fck");
  	if (IS_ERR_OR_NULL(fclk)) {
  		dev_err(&pdev->dev, "%s: %d: clk_get() FAILED
  ",
  				__func__, __LINE__);
  		return -EINVAL;
  	}
  
  	switch (source) {
  	case OMAP_TIMER_SRC_SYS_CLK:
  		parent_name = "sys_ck";
  		break;
  
  	case OMAP_TIMER_SRC_32_KHZ:
  		parent_name = "32k_ck";
  		break;
  
  	case OMAP_TIMER_SRC_EXT_CLK:
  		if (pdata->timer_ip_version == OMAP_TIMER_IP_VERSION_1) {
  			parent_name = "alt_ck";
  			break;
  		}
  		dev_err(&pdev->dev, "%s: %d: invalid clk src.
  ",
  			__func__, __LINE__);
  		clk_put(fclk);
  		return -EINVAL;
  	}
  
  	parent = clk_get(&pdev->dev, parent_name);
  	if (IS_ERR_OR_NULL(parent)) {
  		dev_err(&pdev->dev, "%s: %d: clk_get() %s FAILED
  ",
  			__func__, __LINE__, parent_name);
  		clk_put(fclk);
  		return -EINVAL;
  	}
  
  	ret = clk_set_parent(fclk, parent);
  	if (IS_ERR_VALUE(ret)) {
  		dev_err(&pdev->dev, "%s: clk_set_parent() to %s FAILED
  ",
  			__func__, parent_name);
  		ret = -EINVAL;
  	}
  
  	clk_put(parent);
  	clk_put(fclk);
  
  	return ret;
  }
c345c8b09   Tarun Kanti DebBarma   ARM: OMAP2+: dmti...
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
  /**
   * 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;
c541c15fb   Tony Lindgren   Merge branches 'c...
410
  	struct platform_device *pdev;
c345c8b09   Tarun Kanti DebBarma   ARM: OMAP2+: dmti...
411
  	struct omap_timer_capability_dev_attr *timer_dev_attr;
b481113a8   Tarun Kanti DebBarma   ARM: OMAP: dmtime...
412
  	struct powerdomain *pwrdm;
c345c8b09   Tarun Kanti DebBarma   ARM: OMAP2+: dmti...
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
  
  	pr_debug("%s: %s
  ", __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]
  ", __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);
  
  	pdata->set_timer_src = omap2_dm_timer_set_src;
  	pdata->timer_ip_version = oh->class->rev;
0dad9faea   Tony Lindgren   ARM: OMAP: dmtime...
444
445
446
  	/* Mark clocksource and clockevent timers as reserved */
  	if ((sys_timer_reserved >> (id - 1)) & 0x1)
  		pdata->reserved = 1;
b481113a8   Tarun Kanti DebBarma   ARM: OMAP: dmtime...
447
448
449
450
451
  	pwrdm = omap_hwmod_get_pwrdm(oh);
  	pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
  #ifdef CONFIG_PM
  	pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
  #endif
c541c15fb   Tony Lindgren   Merge branches 'c...
452
  	pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
c16ae1e64   Benoit Cousson   ARM: OMAP2+: time...
453
  				 NULL, 0, 0);
c345c8b09   Tarun Kanti DebBarma   ARM: OMAP2+: dmti...
454

c541c15fb   Tony Lindgren   Merge branches 'c...
455
  	if (IS_ERR(pdev)) {
c345c8b09   Tarun Kanti DebBarma   ARM: OMAP2+: dmti...
456
457
458
459
460
461
462
463
464
465
  		pr_err("%s: Can't build omap_device for %s: %s.
  ",
  			__func__, name, oh->name);
  		ret = -EINVAL;
  	}
  
  	kfree(pdata);
  
  	return ret;
  }
3392cdd33   Tarun Kanti DebBarma   ARM: OMAP: dmtime...
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
  
  /**
   * 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;
  
  	ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL);
  	if (unlikely(ret)) {
  		pr_err("%s: device registration failed.
  ", __func__);
  		return -EINVAL;
  	}
  
  	return 0;
  }
  arch_initcall(omap2_dm_timer_init);