mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
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>
This commit is contained in:
parent
99ce567ba9
commit
19bdc9d061
1 changed files with 66 additions and 0 deletions
|
@ -47,6 +47,7 @@ struct sh_cmt_priv {
|
||||||
unsigned long rate;
|
unsigned long rate;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct clock_event_device ced;
|
struct clock_event_device ced;
|
||||||
|
struct clocksource cs;
|
||||||
unsigned long total_cycles;
|
unsigned long total_cycles;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -376,6 +377,68 @@ static void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag)
|
||||||
spin_unlock_irqrestore(&p->lock, flags);
|
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)
|
static struct sh_cmt_priv *ced_to_sh_cmt(struct clock_event_device *ced)
|
||||||
{
|
{
|
||||||
return container_of(ced, struct sh_cmt_priv, ced);
|
return container_of(ced, struct sh_cmt_priv, ced);
|
||||||
|
@ -483,6 +546,9 @@ int sh_cmt_register(struct sh_cmt_priv *p, char *name,
|
||||||
if (clockevent_rating)
|
if (clockevent_rating)
|
||||||
sh_cmt_register_clockevent(p, name, clockevent_rating);
|
sh_cmt_register_clockevent(p, name, clockevent_rating);
|
||||||
|
|
||||||
|
if (clocksource_rating)
|
||||||
|
sh_cmt_register_clocksource(p, name, clocksource_rating);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue