timer.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * Moschip MCS814x timer routines
  3. *
  4. * Copyright (C) 2012, Florian Fainelli <florian@openwrt.org>
  5. *
  6. * Licensed under GPLv2
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/time.h>
  11. #include <linux/timex.h>
  12. #include <linux/irq.h>
  13. #include <linux/err.h>
  14. #include <linux/clk.h>
  15. #include <linux/io.h>
  16. #include <linux/of.h>
  17. #include <linux/of_address.h>
  18. #include <linux/of_irq.h>
  19. #include <asm/mach/time.h>
  20. #include <mach/mcs814x.h>
  21. /* Timer block registers */
  22. #define TIMER_VAL 0x00
  23. #define TIMER_CTL 0x04
  24. #define TIMER_CTL_EN 0x01
  25. #define TIMER_CTL_DBG 0x02
  26. static u32 last_reload;
  27. static u32 timer_correct;
  28. static u32 clock_rate;
  29. static u32 timer_reload_value;
  30. static void __iomem *mcs814x_timer_base;
  31. static inline u32 ticks2usecs(u32 x)
  32. {
  33. return x / (clock_rate / 1000000);
  34. }
  35. /*
  36. * Returns number of ms since last clock interrupt. Note that interrupts
  37. * will have been disabled by do_gettimeoffset()
  38. */
  39. static u32 mcs814x_gettimeoffset(void)
  40. {
  41. u32 ticks = readl_relaxed(mcs814x_timer_base + TIMER_VAL);
  42. if (ticks < last_reload)
  43. return ticks2usecs(ticks + (u32)(0xffffffff - last_reload));
  44. else
  45. return ticks2usecs(ticks - last_reload);
  46. }
  47. static irqreturn_t mcs814x_timer_interrupt(int irq, void *dev_id)
  48. {
  49. u32 count = readl_relaxed(mcs814x_timer_base + TIMER_VAL);
  50. /* take into account delay up to this moment */
  51. last_reload = count + timer_correct + timer_reload_value;
  52. if (last_reload < timer_reload_value) {
  53. last_reload = timer_reload_value;
  54. } else {
  55. if (timer_correct == 0)
  56. timer_correct = readl_relaxed(mcs814x_timer_base + TIMER_VAL) - count;
  57. }
  58. writel_relaxed(last_reload, mcs814x_timer_base + TIMER_VAL);
  59. timer_tick();
  60. return IRQ_HANDLED;
  61. }
  62. static struct of_device_id mcs814x_timer_ids[] = {
  63. { .compatible = "moschip,mcs814x-timer" },
  64. { /* sentinel */ },
  65. };
  66. static int __init mcs814x_of_timer_init(void)
  67. {
  68. struct device_node *np;
  69. int irq;
  70. np = of_find_matching_node(NULL, mcs814x_timer_ids);
  71. if (!np)
  72. panic("unable to find compatible timer node in dtb");
  73. mcs814x_timer_base = of_iomap(np, 0);
  74. if (!mcs814x_timer_base)
  75. panic("unable to remap timer cpu registers");
  76. irq = irq_of_parse_and_map(np, 0);
  77. if (!irq)
  78. panic("no interrupts property/mapping failed for timer");
  79. return irq;
  80. }
  81. void __init mcs814x_timer_init(void)
  82. {
  83. struct clk *clk;
  84. int irq;
  85. arch_gettimeoffset = mcs814x_gettimeoffset;
  86. clk = clk_get_sys("timer0", NULL);
  87. if (IS_ERR_OR_NULL(clk))
  88. panic("unable to get timer0 clock");
  89. clock_rate = clk_get_rate(clk);
  90. irq = mcs814x_of_timer_init();
  91. pr_info("Timer frequency: %d (kHz)\n", clock_rate / 1000);
  92. timer_reload_value = 0xffffffff - (clock_rate / HZ);
  93. /* disable timer */
  94. writel_relaxed(~TIMER_CTL_EN, mcs814x_timer_base + TIMER_CTL);
  95. writel_relaxed(timer_reload_value, mcs814x_timer_base + TIMER_VAL);
  96. last_reload = timer_reload_value;
  97. if (request_irq(irq, mcs814x_timer_interrupt,
  98. IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
  99. "mcs814x-timer", NULL))
  100. panic("unable to request timer0 irq %d", irq);
  101. /* enable timer, stop timer in debug mode */
  102. writel_relaxed(TIMER_CTL_EN | TIMER_CTL_DBG,
  103. mcs814x_timer_base + TIMER_CTL);
  104. }