time.c 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  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. write_seqlock(&xtime_lock);
  25. timer_tick();
  26. write_sequnlock(&xtime_lock);
  27. return IRQ_HANDLED;
  28. }
  29. static unsigned long ns9xxx_timer_gettimeoffset(void)
  30. {
  31. /* return the microseconds which have passed since the last interrupt
  32. * was _serviced_. That is, if an interrupt is pending or the counter
  33. * reloads, return one periode more. */
  34. u32 counter1 = SYS_TR(0);
  35. int pending = SYS_ISR & (1 << IRQ_TIMER0);
  36. u32 counter2 = SYS_TR(0);
  37. u32 elapsed;
  38. if (pending || counter2 > counter1)
  39. elapsed = 2 * SYS_TRC(0) - counter2;
  40. else
  41. elapsed = SYS_TRC(0) - counter1;
  42. return (elapsed * usecs_per_tick) >> 16;
  43. }
  44. static struct irqaction ns9xxx_timer_irq = {
  45. .name = "NS9xxx Timer Tick",
  46. .flags = IRQF_DISABLED | IRQF_TIMER,
  47. .handler = ns9xxx_timer_interrupt,
  48. };
  49. static void __init ns9xxx_timer_init(void)
  50. {
  51. int tc;
  52. usecs_per_tick =
  53. SH_DIV(1000000 * TIMERCLOCKSELECT, ns9xxx_cpuclock(), 16);
  54. /* disable timer */
  55. if ((tc = SYS_TC(0)) & SYS_TCx_TEN)
  56. SYS_TC(0) = tc & ~SYS_TCx_TEN;
  57. SYS_TRC(0) = SH_DIV(ns9xxx_cpuclock(), (TIMERCLOCKSELECT * HZ), 0);
  58. REGSET(tc, SYS_TCx, TEN, EN);
  59. REGSET(tc, SYS_TCx, TLCS, DIV64); /* This must match TIMERCLOCKSELECT */
  60. REGSET(tc, SYS_TCx, INTS, EN);
  61. REGSET(tc, SYS_TCx, UDS, DOWN);
  62. REGSET(tc, SYS_TCx, TDBG, STOP);
  63. REGSET(tc, SYS_TCx, TSZ, 32);
  64. REGSET(tc, SYS_TCx, REN, EN);
  65. SYS_TC(0) = tc;
  66. setup_irq(IRQ_TIMER0, &ns9xxx_timer_irq);
  67. }
  68. struct sys_timer ns9xxx_timer = {
  69. .init = ns9xxx_timer_init,
  70. .offset = ns9xxx_timer_gettimeoffset,
  71. };