@@ -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+
379442static 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