time.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /*
  2. * arch/arm/mach-ns9xxx/time.c
  3. *
  4. * Copyright (C) 2006 by Digi International Inc.
  5. * All rights reserved.
  6. *
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License version 2 as published by
  9. * the Free Software Foundation.
  10. */
  11. #include <linux/jiffies.h>
  12. #include <linux/interrupt.h>
  13. #include <linux/irq.h>
  14. #include <asm/arch-ns9xxx/regs-sys.h>
  15. #include <asm/arch-ns9xxx/clock.h>
  16. #include <asm/arch-ns9xxx/irqs.h>
  17. #include <asm/arch/system.h>
  18. #include "generic.h"
  19. #define TIMERCLOCKSELECT 64
  20. static u32 usecs_per_tick;
  21. static irqreturn_t
  22. ns9xxx_timer_interrupt(int irq, void *dev_id)
  23. {
  24. int timerno = irq - IRQ_TIMER0;
  25. u32 tc;
  26. write_seqlock(&xtime_lock);
  27. timer_tick();
  28. write_sequnlock(&xtime_lock);
  29. /* clear irq */
  30. tc = SYS_TC(timerno);
  31. if (REGGET(tc, SYS_TCx, REN) == SYS_TCx_REN_DIS) {
  32. REGSET(tc, SYS_TCx, TEN, DIS);
  33. SYS_TC(timerno) = tc;
  34. }
  35. REGSET(tc, SYS_TCx, INTC, SET);
  36. SYS_TC(timerno) = tc;
  37. REGSET(tc, SYS_TCx, INTC, UNSET);
  38. SYS_TC(timerno) = tc;
  39. return IRQ_HANDLED;
  40. }
  41. static unsigned long ns9xxx_timer_gettimeoffset(void)
  42. {
  43. /* return the microseconds which have passed since the last interrupt
  44. * was _serviced_. That is, if an interrupt is pending or the counter
  45. * reloads, return one period more. */
  46. u32 counter1 = SYS_TR(0);
  47. int pending = SYS_ISR & (1 << IRQ_TIMER0);
  48. u32 counter2 = SYS_TR(0);
  49. u32 elapsed;
  50. if (pending || counter2 > counter1)
  51. elapsed = 2 * SYS_TRC(0) - counter2;
  52. else
  53. elapsed = SYS_TRC(0) - counter1;
  54. return (elapsed * usecs_per_tick) >> 16;
  55. }
  56. static struct irqaction ns9xxx_timer_irq = {
  57. .name = "NS9xxx Timer Tick",
  58. .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
  59. .handler = ns9xxx_timer_interrupt,
  60. };
  61. static void __init ns9xxx_timer_init(void)
  62. {
  63. int tc;
  64. usecs_per_tick =
  65. SH_DIV(1000000 * TIMERCLOCKSELECT, ns9xxx_cpuclock(), 16);
  66. /* disable timer */
  67. if ((tc = SYS_TC(0)) & SYS_TCx_TEN)
  68. SYS_TC(0) = tc & ~SYS_TCx_TEN;
  69. SYS_TRC(0) = SH_DIV(ns9xxx_cpuclock(), (TIMERCLOCKSELECT * HZ), 0);
  70. REGSET(tc, SYS_TCx, TEN, EN);
  71. REGSET(tc, SYS_TCx, TLCS, DIV64); /* This must match TIMERCLOCKSELECT */
  72. REGSET(tc, SYS_TCx, INTS, EN);
  73. REGSET(tc, SYS_TCx, UDS, DOWN);
  74. REGSET(tc, SYS_TCx, TDBG, STOP);
  75. REGSET(tc, SYS_TCx, TSZ, 32);
  76. REGSET(tc, SYS_TCx, REN, EN);
  77. SYS_TC(0) = tc;
  78. setup_irq(IRQ_TIMER0, &ns9xxx_timer_irq);
  79. }
  80. struct sys_timer ns9xxx_timer = {
  81. .init = ns9xxx_timer_init,
  82. .offset = ns9xxx_timer_gettimeoffset,
  83. };