forked from mirrors/linux
		
	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;
 | 
			
		||||
	spinlock_t lock;
 | 
			
		||||
	struct clock_event_device ced;
 | 
			
		||||
	struct clocksource cs;
 | 
			
		||||
	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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue