aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/sh_cmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource/sh_cmt.c')
-rw-r--r--drivers/clocksource/sh_cmt.c116
1 files changed, 97 insertions, 19 deletions
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index 1c92c39a53aa..cf56a2af5fe1 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -18,7 +18,6 @@
18 */ 18 */
19 19
20#include <linux/init.h> 20#include <linux/init.h>
21#include <linux/bootmem.h>
22#include <linux/platform_device.h> 21#include <linux/platform_device.h>
23#include <linux/spinlock.h> 22#include <linux/spinlock.h>
24#include <linux/interrupt.h> 23#include <linux/interrupt.h>
@@ -29,7 +28,7 @@
29#include <linux/err.h> 28#include <linux/err.h>
30#include <linux/clocksource.h> 29#include <linux/clocksource.h>
31#include <linux/clockchips.h> 30#include <linux/clockchips.h>
32#include <linux/sh_cmt.h> 31#include <linux/sh_timer.h>
33 32
34struct sh_cmt_priv { 33struct sh_cmt_priv {
35 void __iomem *mapbase; 34 void __iomem *mapbase;
@@ -47,6 +46,7 @@ struct sh_cmt_priv {
47 unsigned long rate; 46 unsigned long rate;
48 spinlock_t lock; 47 spinlock_t lock;
49 struct clock_event_device ced; 48 struct clock_event_device ced;
49 struct clocksource cs;
50 unsigned long total_cycles; 50 unsigned long total_cycles;
51}; 51};
52 52
@@ -59,7 +59,7 @@ static DEFINE_SPINLOCK(sh_cmt_lock);
59 59
60static inline unsigned long sh_cmt_read(struct sh_cmt_priv *p, int reg_nr) 60static inline unsigned long sh_cmt_read(struct sh_cmt_priv *p, int reg_nr)
61{ 61{
62 struct sh_cmt_config *cfg = p->pdev->dev.platform_data; 62 struct sh_timer_config *cfg = p->pdev->dev.platform_data;
63 void __iomem *base = p->mapbase; 63 void __iomem *base = p->mapbase;
64 unsigned long offs; 64 unsigned long offs;
65 65
@@ -83,7 +83,7 @@ static inline unsigned long sh_cmt_read(struct sh_cmt_priv *p, int reg_nr)
83static inline void sh_cmt_write(struct sh_cmt_priv *p, int reg_nr, 83static inline void sh_cmt_write(struct sh_cmt_priv *p, int reg_nr,
84 unsigned long value) 84 unsigned long value)
85{ 85{
86 struct sh_cmt_config *cfg = p->pdev->dev.platform_data; 86 struct sh_timer_config *cfg = p->pdev->dev.platform_data;
87 void __iomem *base = p->mapbase; 87 void __iomem *base = p->mapbase;
88 unsigned long offs; 88 unsigned long offs;
89 89
@@ -110,23 +110,28 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p,
110 int *has_wrapped) 110 int *has_wrapped)
111{ 111{
112 unsigned long v1, v2, v3; 112 unsigned long v1, v2, v3;
113 int o1, o2;
114
115 o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit;
113 116
114 /* Make sure the timer value is stable. Stolen from acpi_pm.c */ 117 /* Make sure the timer value is stable. Stolen from acpi_pm.c */
115 do { 118 do {
119 o2 = o1;
116 v1 = sh_cmt_read(p, CMCNT); 120 v1 = sh_cmt_read(p, CMCNT);
117 v2 = sh_cmt_read(p, CMCNT); 121 v2 = sh_cmt_read(p, CMCNT);
118 v3 = sh_cmt_read(p, CMCNT); 122 v3 = sh_cmt_read(p, CMCNT);
119 } while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) 123 o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit;
120 || (v3 > v1 && v3 < v2))); 124 } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
125 || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
121 126
122 *has_wrapped = sh_cmt_read(p, CMCSR) & p->overflow_bit; 127 *has_wrapped = o1;
123 return v2; 128 return v2;
124} 129}
125 130
126 131
127static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start) 132static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start)
128{ 133{
129 struct sh_cmt_config *cfg = p->pdev->dev.platform_data; 134 struct sh_timer_config *cfg = p->pdev->dev.platform_data;
130 unsigned long flags, value; 135 unsigned long flags, value;
131 136
132 /* start stop register shared by multiple timer channels */ 137 /* start stop register shared by multiple timer channels */
@@ -144,7 +149,7 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start)
144 149
145static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate) 150static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
146{ 151{
147 struct sh_cmt_config *cfg = p->pdev->dev.platform_data; 152 struct sh_timer_config *cfg = p->pdev->dev.platform_data;
148 int ret; 153 int ret;
149 154
150 /* enable clock */ 155 /* enable clock */
@@ -153,16 +158,18 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
153 pr_err("sh_cmt: cannot enable clock \"%s\"\n", cfg->clk); 158 pr_err("sh_cmt: cannot enable clock \"%s\"\n", cfg->clk);
154 return ret; 159 return ret;
155 } 160 }
156 *rate = clk_get_rate(p->clk) / 8;
157 161
158 /* make sure channel is disabled */ 162 /* make sure channel is disabled */
159 sh_cmt_start_stop_ch(p, 0); 163 sh_cmt_start_stop_ch(p, 0);
160 164
161 /* configure channel, periodic mode and maximum timeout */ 165 /* configure channel, periodic mode and maximum timeout */
162 if (p->width == 16) 166 if (p->width == 16) {
163 sh_cmt_write(p, CMCSR, 0); 167 *rate = clk_get_rate(p->clk) / 512;
164 else 168 sh_cmt_write(p, CMCSR, 0x43);
169 } else {
170 *rate = clk_get_rate(p->clk) / 8;
165 sh_cmt_write(p, CMCSR, 0x01a4); 171 sh_cmt_write(p, CMCSR, 0x01a4);
172 }
166 173
167 sh_cmt_write(p, CMCOR, 0xffffffff); 174 sh_cmt_write(p, CMCOR, 0xffffffff);
168 sh_cmt_write(p, CMCNT, 0); 175 sh_cmt_write(p, CMCNT, 0);
@@ -376,6 +383,68 @@ static void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag)
376 spin_unlock_irqrestore(&p->lock, flags); 383 spin_unlock_irqrestore(&p->lock, flags);
377} 384}
378 385
386static struct sh_cmt_priv *cs_to_sh_cmt(struct clocksource *cs)
387{
388 return container_of(cs, struct sh_cmt_priv, cs);
389}
390
391static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
392{
393 struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
394 unsigned long flags, raw;
395 unsigned long value;
396 int has_wrapped;
397
398 spin_lock_irqsave(&p->lock, flags);
399 value = p->total_cycles;
400 raw = sh_cmt_get_counter(p, &has_wrapped);
401
402 if (unlikely(has_wrapped))
403 raw += p->match_value;
404 spin_unlock_irqrestore(&p->lock, flags);
405
406 return value + raw;
407}
408
409static int sh_cmt_clocksource_enable(struct clocksource *cs)
410{
411 struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
412 int ret;
413
414 p->total_cycles = 0;
415
416 ret = sh_cmt_start(p, FLAG_CLOCKSOURCE);
417 if (ret)
418 return ret;
419
420 /* TODO: calculate good shift from rate and counter bit width */
421 cs->shift = 0;
422 cs->mult = clocksource_hz2mult(p->rate, cs->shift);
423 return 0;
424}
425
426static void sh_cmt_clocksource_disable(struct clocksource *cs)
427{
428 sh_cmt_stop(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE);
429}
430
431static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
432 char *name, unsigned long rating)
433{
434 struct clocksource *cs = &p->cs;
435
436 cs->name = name;
437 cs->rating = rating;
438 cs->read = sh_cmt_clocksource_read;
439 cs->enable = sh_cmt_clocksource_enable;
440 cs->disable = sh_cmt_clocksource_disable;
441 cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
442 cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
443 pr_info("sh_cmt: %s used as clock source\n", cs->name);
444 clocksource_register(cs);
445 return 0;
446}
447
379static struct sh_cmt_priv *ced_to_sh_cmt(struct clock_event_device *ced) 448static struct sh_cmt_priv *ced_to_sh_cmt(struct clock_event_device *ced)
380{ 449{
381 return container_of(ced, struct sh_cmt_priv, ced); 450 return container_of(ced, struct sh_cmt_priv, ced);
@@ -468,9 +537,9 @@ static void sh_cmt_register_clockevent(struct sh_cmt_priv *p,
468 clockevents_register_device(ced); 537 clockevents_register_device(ced);
469} 538}
470 539
471int sh_cmt_register(struct sh_cmt_priv *p, char *name, 540static int sh_cmt_register(struct sh_cmt_priv *p, char *name,
472 unsigned long clockevent_rating, 541 unsigned long clockevent_rating,
473 unsigned long clocksource_rating) 542 unsigned long clocksource_rating)
474{ 543{
475 if (p->width == (sizeof(p->max_match_value) * 8)) 544 if (p->width == (sizeof(p->max_match_value) * 8))
476 p->max_match_value = ~0; 545 p->max_match_value = ~0;
@@ -483,12 +552,15 @@ int sh_cmt_register(struct sh_cmt_priv *p, char *name,
483 if (clockevent_rating) 552 if (clockevent_rating)
484 sh_cmt_register_clockevent(p, name, clockevent_rating); 553 sh_cmt_register_clockevent(p, name, clockevent_rating);
485 554
555 if (clocksource_rating)
556 sh_cmt_register_clocksource(p, name, clocksource_rating);
557
486 return 0; 558 return 0;
487} 559}
488 560
489static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) 561static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
490{ 562{
491 struct sh_cmt_config *cfg = pdev->dev.platform_data; 563 struct sh_timer_config *cfg = pdev->dev.platform_data;
492 struct resource *res; 564 struct resource *res;
493 int irq, ret; 565 int irq, ret;
494 ret = -ENXIO; 566 ret = -ENXIO;
@@ -545,7 +617,7 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
545 if (resource_size(res) == 6) { 617 if (resource_size(res) == 6) {
546 p->width = 16; 618 p->width = 16;
547 p->overflow_bit = 0x80; 619 p->overflow_bit = 0x80;
548 p->clear_bits = ~0xc0; 620 p->clear_bits = ~0x80;
549 } else { 621 } else {
550 p->width = 32; 622 p->width = 32;
551 p->overflow_bit = 0x8000; 623 p->overflow_bit = 0x8000;
@@ -566,8 +638,14 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
566static int __devinit sh_cmt_probe(struct platform_device *pdev) 638static int __devinit sh_cmt_probe(struct platform_device *pdev)
567{ 639{
568 struct sh_cmt_priv *p = platform_get_drvdata(pdev); 640 struct sh_cmt_priv *p = platform_get_drvdata(pdev);
641 struct sh_timer_config *cfg = pdev->dev.platform_data;
569 int ret; 642 int ret;
570 643
644 if (p) {
645 pr_info("sh_cmt: %s kept as earlytimer\n", cfg->name);
646 return 0;
647 }
648
571 p = kmalloc(sizeof(*p), GFP_KERNEL); 649 p = kmalloc(sizeof(*p), GFP_KERNEL);
572 if (p == NULL) { 650 if (p == NULL) {
573 dev_err(&pdev->dev, "failed to allocate driver data\n"); 651 dev_err(&pdev->dev, "failed to allocate driver data\n");
@@ -577,7 +655,6 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
577 ret = sh_cmt_setup(p, pdev); 655 ret = sh_cmt_setup(p, pdev);
578 if (ret) { 656 if (ret) {
579 kfree(p); 657 kfree(p);
580
581 platform_set_drvdata(pdev, NULL); 658 platform_set_drvdata(pdev, NULL);
582 } 659 }
583 return ret; 660 return ret;
@@ -606,6 +683,7 @@ static void __exit sh_cmt_exit(void)
606 platform_driver_unregister(&sh_cmt_device_driver); 683 platform_driver_unregister(&sh_cmt_device_driver);
607} 684}
608 685
686early_platform_init("earlytimer", &sh_cmt_device_driver);
609module_init(sh_cmt_init); 687module_init(sh_cmt_init);
610module_exit(sh_cmt_exit); 688module_exit(sh_cmt_exit);
611 689