Skip to content

Commit 19bdc9d

Browse files
Magnus Dammpmundt
authored andcommitted
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 <[email protected]> Signed-off-by: Paul Mundt <[email protected]>
1 parent 99ce567 commit 19bdc9d

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

drivers/clocksource/sh_cmt.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct sh_cmt_priv {
4747
unsigned long rate;
4848
spinlock_t lock;
4949
struct clock_event_device ced;
50+
struct clocksource cs;
5051
unsigned long total_cycles;
5152
};
5253

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

380+
static struct sh_cmt_priv *cs_to_sh_cmt(struct clocksource *cs)
381+
{
382+
return container_of(cs, struct sh_cmt_priv, cs);
383+
}
384+
385+
static 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+
403+
static 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+
420+
static void sh_cmt_clocksource_disable(struct clocksource *cs)
421+
{
422+
sh_cmt_stop(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE);
423+
}
424+
425+
static 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+
379442
static struct sh_cmt_priv *ced_to_sh_cmt(struct clock_event_device *ced)
380443
{
381444
return container_of(ced, struct sh_cmt_priv, ced);
@@ -483,6 +546,9 @@ int sh_cmt_register(struct sh_cmt_priv *p, char *name,
483546
if (clockevent_rating)
484547
sh_cmt_register_clockevent(p, name, clockevent_rating);
485548

549+
if (clocksource_rating)
550+
sh_cmt_register_clocksource(p, name, clocksource_rating);
551+
486552
return 0;
487553
}
488554

0 commit comments

Comments
 (0)