Skip to content

Commit

Permalink
clocksource: sh_cmt clocksource support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Magnus Damm authored and Paul Mundt committed Apr 22, 2009
1 parent 99ce567 commit 19bdc9d
Showing 1 changed file with 66 additions and 0 deletions.
66 changes: 66 additions & 0 deletions drivers/clocksource/sh_cmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct sh_cmt_priv {
unsigned long rate;
spinlock_t lock;
struct clock_event_device ced;
struct clocksource cs;
unsigned long total_cycles;
};

Expand Down Expand Up @@ -376,6 +377,68 @@ static void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag)
spin_unlock_irqrestore(&p->lock, flags);
}

static struct sh_cmt_priv *cs_to_sh_cmt(struct clocksource *cs)
{
return container_of(cs, struct sh_cmt_priv, cs);
}

static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
{
struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
unsigned long flags, raw;
unsigned long value;
int has_wrapped;

spin_lock_irqsave(&p->lock, flags);
value = p->total_cycles;
raw = sh_cmt_get_counter(p, &has_wrapped);

if (unlikely(has_wrapped))
raw = p->match_value;
spin_unlock_irqrestore(&p->lock, flags);

return value + raw;
}

static int sh_cmt_clocksource_enable(struct clocksource *cs)
{
struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
int ret;

p->total_cycles = 0;

ret = sh_cmt_start(p, FLAG_CLOCKSOURCE);
if (ret)
return ret;

/* TODO: calculate good shift from rate and counter bit width */
cs->shift = 0;
cs->mult = clocksource_hz2mult(p->rate, cs->shift);
return 0;
}

static void sh_cmt_clocksource_disable(struct clocksource *cs)
{
sh_cmt_stop(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE);
}

static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
char *name, unsigned long rating)
{
struct clocksource *cs = &p->cs;

cs->name = name;
cs->rating = rating;
cs->read = sh_cmt_clocksource_read;
cs->enable = sh_cmt_clocksource_enable;
cs->disable = sh_cmt_clocksource_disable;
cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
pr_info("sh_cmt: %s used as clock source\n", cs->name);
clocksource_register(cs);
return 0;
}

static struct sh_cmt_priv *ced_to_sh_cmt(struct clock_event_device *ced)
{
return container_of(ced, struct sh_cmt_priv, ced);
Expand Down Expand Up @@ -483,6 +546,9 @@ int sh_cmt_register(struct sh_cmt_priv *p, char *name,
if (clockevent_rating)
sh_cmt_register_clockevent(p, name, clockevent_rating);

if (clocksource_rating)
sh_cmt_register_clocksource(p, name, clocksource_rating);

return 0;
}

Expand Down

0 comments on commit 19bdc9d

Please sign in to comment.