diff options
Diffstat (limited to 'drivers/clocksource/sh_cmt.c')
-rw-r--r-- | drivers/clocksource/sh_cmt.c | 56 |
1 files changed, 26 insertions, 30 deletions
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 717305d30444..dc7c033ef587 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c | |||
@@ -283,16 +283,21 @@ static void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p, | |||
283 | } while (delay); | 283 | } while (delay); |
284 | } | 284 | } |
285 | 285 | ||
286 | static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta) | 286 | static void __sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta) |
287 | { | 287 | { |
288 | unsigned long flags; | ||
289 | |||
290 | if (delta > p->max_match_value) | 288 | if (delta > p->max_match_value) |
291 | dev_warn(&p->pdev->dev, "delta out of range\n"); | 289 | dev_warn(&p->pdev->dev, "delta out of range\n"); |
292 | 290 | ||
293 | spin_lock_irqsave(&p->lock, flags); | ||
294 | p->next_match_value = delta; | 291 | p->next_match_value = delta; |
295 | sh_cmt_clock_event_program_verify(p, 0); | 292 | sh_cmt_clock_event_program_verify(p, 0); |
293 | } | ||
294 | |||
295 | static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta) | ||
296 | { | ||
297 | unsigned long flags; | ||
298 | |||
299 | spin_lock_irqsave(&p->lock, flags); | ||
300 | __sh_cmt_set_next(p, delta); | ||
296 | spin_unlock_irqrestore(&p->lock, flags); | 301 | spin_unlock_irqrestore(&p->lock, flags); |
297 | } | 302 | } |
298 | 303 | ||
@@ -308,7 +313,7 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id) | |||
308 | * isr before we end up here. | 313 | * isr before we end up here. |
309 | */ | 314 | */ |
310 | if (p->flags & FLAG_CLOCKSOURCE) | 315 | if (p->flags & FLAG_CLOCKSOURCE) |
311 | p->total_cycles += p->match_value; | 316 | p->total_cycles += p->match_value + 1; |
312 | 317 | ||
313 | if (!(p->flags & FLAG_REPROGRAM)) | 318 | if (!(p->flags & FLAG_REPROGRAM)) |
314 | p->next_match_value = p->max_match_value; | 319 | p->next_match_value = p->max_match_value; |
@@ -359,7 +364,7 @@ static int sh_cmt_start(struct sh_cmt_priv *p, unsigned long flag) | |||
359 | 364 | ||
360 | /* setup timeout if no clockevent */ | 365 | /* setup timeout if no clockevent */ |
361 | if ((flag == FLAG_CLOCKSOURCE) && (!(p->flags & FLAG_CLOCKEVENT))) | 366 | if ((flag == FLAG_CLOCKSOURCE) && (!(p->flags & FLAG_CLOCKEVENT))) |
362 | sh_cmt_set_next(p, p->max_match_value); | 367 | __sh_cmt_set_next(p, p->max_match_value); |
363 | out: | 368 | out: |
364 | spin_unlock_irqrestore(&p->lock, flags); | 369 | spin_unlock_irqrestore(&p->lock, flags); |
365 | 370 | ||
@@ -381,7 +386,7 @@ static void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag) | |||
381 | 386 | ||
382 | /* adjust the timeout to maximum if only clocksource left */ | 387 | /* adjust the timeout to maximum if only clocksource left */ |
383 | if ((flag == FLAG_CLOCKEVENT) && (p->flags & FLAG_CLOCKSOURCE)) | 388 | if ((flag == FLAG_CLOCKEVENT) && (p->flags & FLAG_CLOCKSOURCE)) |
384 | sh_cmt_set_next(p, p->max_match_value); | 389 | __sh_cmt_set_next(p, p->max_match_value); |
385 | 390 | ||
386 | spin_unlock_irqrestore(&p->lock, flags); | 391 | spin_unlock_irqrestore(&p->lock, flags); |
387 | } | 392 | } |
@@ -403,7 +408,7 @@ static cycle_t sh_cmt_clocksource_read(struct clocksource *cs) | |||
403 | raw = sh_cmt_get_counter(p, &has_wrapped); | 408 | raw = sh_cmt_get_counter(p, &has_wrapped); |
404 | 409 | ||
405 | if (unlikely(has_wrapped)) | 410 | if (unlikely(has_wrapped)) |
406 | raw += p->match_value; | 411 | raw += p->match_value + 1; |
407 | spin_unlock_irqrestore(&p->lock, flags); | 412 | spin_unlock_irqrestore(&p->lock, flags); |
408 | 413 | ||
409 | return value + raw; | 414 | return value + raw; |
@@ -411,11 +416,15 @@ static cycle_t sh_cmt_clocksource_read(struct clocksource *cs) | |||
411 | 416 | ||
412 | static int sh_cmt_clocksource_enable(struct clocksource *cs) | 417 | static int sh_cmt_clocksource_enable(struct clocksource *cs) |
413 | { | 418 | { |
419 | int ret; | ||
414 | struct sh_cmt_priv *p = cs_to_sh_cmt(cs); | 420 | struct sh_cmt_priv *p = cs_to_sh_cmt(cs); |
415 | 421 | ||
416 | p->total_cycles = 0; | 422 | p->total_cycles = 0; |
417 | 423 | ||
418 | return sh_cmt_start(p, FLAG_CLOCKSOURCE); | 424 | ret = sh_cmt_start(p, FLAG_CLOCKSOURCE); |
425 | if (!ret) | ||
426 | __clocksource_updatefreq_hz(cs, p->rate); | ||
427 | return ret; | ||
419 | } | 428 | } |
420 | 429 | ||
421 | static void sh_cmt_clocksource_disable(struct clocksource *cs) | 430 | static void sh_cmt_clocksource_disable(struct clocksource *cs) |
@@ -443,19 +452,10 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p, | |||
443 | cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8); | 452 | cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8); |
444 | cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; | 453 | cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; |
445 | 454 | ||
446 | /* clk_get_rate() needs an enabled clock */ | ||
447 | clk_enable(p->clk); | ||
448 | p->rate = clk_get_rate(p->clk) / (p->width == 16) ? 512 : 8; | ||
449 | clk_disable(p->clk); | ||
450 | |||
451 | /* TODO: calculate good shift from rate and counter bit width */ | ||
452 | cs->shift = 0; | ||
453 | cs->mult = clocksource_hz2mult(p->rate, cs->shift); | ||
454 | |||
455 | dev_info(&p->pdev->dev, "used as clock source\n"); | 455 | dev_info(&p->pdev->dev, "used as clock source\n"); |
456 | 456 | ||
457 | clocksource_register(cs); | 457 | /* Register with dummy 1 Hz value, gets updated in ->enable() */ |
458 | 458 | clocksource_register_hz(cs, 1); | |
459 | return 0; | 459 | return 0; |
460 | } | 460 | } |
461 | 461 | ||
@@ -478,7 +478,7 @@ static void sh_cmt_clock_event_start(struct sh_cmt_priv *p, int periodic) | |||
478 | ced->min_delta_ns = clockevent_delta2ns(0x1f, ced); | 478 | ced->min_delta_ns = clockevent_delta2ns(0x1f, ced); |
479 | 479 | ||
480 | if (periodic) | 480 | if (periodic) |
481 | sh_cmt_set_next(p, (p->rate + HZ/2) / HZ); | 481 | sh_cmt_set_next(p, ((p->rate + HZ/2) / HZ) - 1); |
482 | else | 482 | else |
483 | sh_cmt_set_next(p, p->max_match_value); | 483 | sh_cmt_set_next(p, p->max_match_value); |
484 | } | 484 | } |
@@ -523,9 +523,9 @@ static int sh_cmt_clock_event_next(unsigned long delta, | |||
523 | 523 | ||
524 | BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); | 524 | BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); |
525 | if (likely(p->flags & FLAG_IRQCONTEXT)) | 525 | if (likely(p->flags & FLAG_IRQCONTEXT)) |
526 | p->next_match_value = delta; | 526 | p->next_match_value = delta - 1; |
527 | else | 527 | else |
528 | sh_cmt_set_next(p, delta); | 528 | sh_cmt_set_next(p, delta - 1); |
529 | 529 | ||
530 | return 0; | 530 | return 0; |
531 | } | 531 | } |
@@ -616,13 +616,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
616 | /* get hold of clock */ | 616 | /* get hold of clock */ |
617 | p->clk = clk_get(&p->pdev->dev, "cmt_fck"); | 617 | p->clk = clk_get(&p->pdev->dev, "cmt_fck"); |
618 | if (IS_ERR(p->clk)) { | 618 | if (IS_ERR(p->clk)) { |
619 | dev_warn(&p->pdev->dev, "using deprecated clock lookup\n"); | 619 | dev_err(&p->pdev->dev, "cannot get clock\n"); |
620 | p->clk = clk_get(&p->pdev->dev, cfg->clk); | 620 | ret = PTR_ERR(p->clk); |
621 | if (IS_ERR(p->clk)) { | 621 | goto err1; |
622 | dev_err(&p->pdev->dev, "cannot get clock\n"); | ||
623 | ret = PTR_ERR(p->clk); | ||
624 | goto err1; | ||
625 | } | ||
626 | } | 622 | } |
627 | 623 | ||
628 | if (resource_size(res) == 6) { | 624 | if (resource_size(res) == 6) { |