aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/sh_cmt.c
diff options
context:
space:
mode:
authorMagnus Damm <damm@igel.co.jp>2009-04-17 01:26:31 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-04-21 20:31:04 -0400
commit19bdc9d061bcb71efd2b53083d96b59bbe1a1751 (patch)
treeebe6328a1078cd8526d9635ce54057b18984f30f /drivers/clocksource/sh_cmt.c
parent99ce567ba912109c78762246c964327f3f81f27d (diff)
clocksource: sh_cmt clocksource support
Add clocksource support to the sh_cmt driver. With this in place we can do tickless with a single CMT channel. Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/clocksource/sh_cmt.c')
-rw-r--r--drivers/clocksource/sh_cmt.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index 02bae3994abe..c24756489612 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -47,6 +47,7 @@ struct sh_cmt_priv {
47 unsigned long rate; 47 unsigned long rate;
48 spinlock_t lock; 48 spinlock_t lock;
49 struct clock_event_device ced; 49 struct clock_event_device ced;
50 struct clocksource cs;
50 unsigned long total_cycles; 51 unsigned long total_cycles;
51}; 52};
52 53
@@ -376,6 +377,68 @@ static void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag)
376 spin_unlock_irqrestore(&p->lock, flags); 377 spin_unlock_irqrestore(&p->lock, flags);
377} 378}
378 379
380static struct sh_cmt_priv *cs_to_sh_cmt(struct clocksource *cs)
381{
382 return container_of(cs, struct sh_cmt_priv, cs);
383}
384
385static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
386{
387 struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
388 unsigned long flags, raw;
389 unsigned long value;
390 int has_wrapped;
391
392 spin_lock_irqsave(&p->lock, flags);
393 value = p->total_cycles;
394 raw = sh_cmt_get_counter(p, &has_wrapped);
395
396 if (unlikely(has_wrapped))
397 raw = p->match_value;
398 spin_unlock_irqrestore(&p->lock, flags);
399
400 return value + raw;
401}
402
403static int sh_cmt_clocksource_enable(struct clocksource *cs)
404{
405 struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
406 int ret;
407
408 p->total_cycles = 0;
409
410 ret = sh_cmt_start(p, FLAG_CLOCKSOURCE);
411 if (ret)
412 return ret;
413
414 /* TODO: calculate good shift from rate and counter bit width */
415 cs->shift = 0;
416 cs->mult = clocksource_hz2mult(p->rate, cs->shift);
417 return 0;
418}
419
420static void sh_cmt_clocksource_disable(struct clocksource *cs)
421{
422 sh_cmt_stop(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE);
423}
424
425static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
426 char *name, unsigned long rating)
427{
428 struct clocksource *cs = &p->cs;
429
430 cs->name = name;
431 cs->rating = rating;
432 cs->read = sh_cmt_clocksource_read;
433 cs->enable = sh_cmt_clocksource_enable;
434 cs->disable = sh_cmt_clocksource_disable;
435 cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
436 cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
437 pr_info("sh_cmt: %s used as clock source\n", cs->name);
438 clocksource_register(cs);
439 return 0;
440}
441
379static struct sh_cmt_priv *ced_to_sh_cmt(struct clock_event_device *ced) 442static struct sh_cmt_priv *ced_to_sh_cmt(struct clock_event_device *ced)
380{ 443{
381 return container_of(ced, struct sh_cmt_priv, ced); 444 return container_of(ced, struct sh_cmt_priv, ced);
@@ -483,6 +546,9 @@ int sh_cmt_register(struct sh_cmt_priv *p, char *name,
483 if (clockevent_rating) 546 if (clockevent_rating)
484 sh_cmt_register_clockevent(p, name, clockevent_rating); 547 sh_cmt_register_clockevent(p, name, clockevent_rating);
485 548
549 if (clocksource_rating)
550 sh_cmt_register_clocksource(p, name, clocksource_rating);
551
486 return 0; 552 return 0;
487} 553}
488 554