time.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * linux/arch/arm/plat-mxc/time.c
  3. *
  4. * Copyright (C) 2000-2001 Deep Blue Solutions
  5. * Copyright (C) 2002 Shane Nay (shane@minirl.com)
  6. * Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com)
  7. * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  21. * MA 02110-1301, USA.
  22. */
  23. #include <linux/interrupt.h>
  24. #include <linux/irq.h>
  25. #include <linux/clockchips.h>
  26. #include <linux/clk.h>
  27. #include <mach/hardware.h>
  28. #include <asm/mach/time.h>
  29. #include <mach/common.h>
  30. #include <mach/mxc_timer.h>
  31. static struct clock_event_device clockevent_mxc;
  32. static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
  33. /* clock source for the timer */
  34. static struct clk *timer_clk;
  35. /* clock source */
  36. static cycle_t mxc_get_cycles(void)
  37. {
  38. return __raw_readl(TIMER_BASE + MXC_TCN);
  39. }
  40. static struct clocksource clocksource_mxc = {
  41. .name = "mxc_timer1",
  42. .rating = 200,
  43. .read = mxc_get_cycles,
  44. .mask = CLOCKSOURCE_MASK(32),
  45. .shift = 20,
  46. .flags = CLOCK_SOURCE_IS_CONTINUOUS,
  47. };
  48. static int __init mxc_clocksource_init(void)
  49. {
  50. unsigned int clock;
  51. clock = clk_get_rate(timer_clk);
  52. clocksource_mxc.mult = clocksource_hz2mult(clock,
  53. clocksource_mxc.shift);
  54. clocksource_register(&clocksource_mxc);
  55. return 0;
  56. }
  57. /* clock event */
  58. static int mxc_set_next_event(unsigned long evt,
  59. struct clock_event_device *unused)
  60. {
  61. unsigned long tcmp;
  62. tcmp = __raw_readl(TIMER_BASE + MXC_TCN) + evt;
  63. __raw_writel(tcmp, TIMER_BASE + MXC_TCMP);
  64. return (int)(tcmp - __raw_readl(TIMER_BASE + MXC_TCN)) < 0 ?
  65. -ETIME : 0;
  66. }
  67. #ifdef DEBUG
  68. static const char *clock_event_mode_label[] = {
  69. [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
  70. [CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT",
  71. [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
  72. [CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED"
  73. };
  74. #endif /* DEBUG */
  75. static void mxc_set_mode(enum clock_event_mode mode,
  76. struct clock_event_device *evt)
  77. {
  78. unsigned long flags;
  79. /*
  80. * The timer interrupt generation is disabled at least
  81. * for enough time to call mxc_set_next_event()
  82. */
  83. local_irq_save(flags);
  84. /* Disable interrupt in GPT module */
  85. gpt_irq_disable();
  86. if (mode != clockevent_mode) {
  87. /* Set event time into far-far future */
  88. __raw_writel(__raw_readl(TIMER_BASE + MXC_TCN) - 3,
  89. TIMER_BASE + MXC_TCMP);
  90. /* Clear pending interrupt */
  91. gpt_irq_acknowledge();
  92. }
  93. #ifdef DEBUG
  94. printk(KERN_INFO "mxc_set_mode: changing mode from %s to %s\n",
  95. clock_event_mode_label[clockevent_mode],
  96. clock_event_mode_label[mode]);
  97. #endif /* DEBUG */
  98. /* Remember timer mode */
  99. clockevent_mode = mode;
  100. local_irq_restore(flags);
  101. switch (mode) {
  102. case CLOCK_EVT_MODE_PERIODIC:
  103. printk(KERN_ERR"mxc_set_mode: Periodic mode is not "
  104. "supported for i.MX\n");
  105. break;
  106. case CLOCK_EVT_MODE_ONESHOT:
  107. /*
  108. * Do not put overhead of interrupt enable/disable into
  109. * mxc_set_next_event(), the core has about 4 minutes
  110. * to call mxc_set_next_event() or shutdown clock after
  111. * mode switching
  112. */
  113. local_irq_save(flags);
  114. gpt_irq_enable();
  115. local_irq_restore(flags);
  116. break;
  117. case CLOCK_EVT_MODE_SHUTDOWN:
  118. case CLOCK_EVT_MODE_UNUSED:
  119. case CLOCK_EVT_MODE_RESUME:
  120. /* Left event sources disabled, no more interrupts appear */
  121. break;
  122. }
  123. }
  124. /*
  125. * IRQ handler for the timer
  126. */
  127. static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
  128. {
  129. struct clock_event_device *evt = &clockevent_mxc;
  130. uint32_t tstat;
  131. tstat = __raw_readl(TIMER_BASE + MXC_TSTAT);
  132. gpt_irq_acknowledge();
  133. evt->event_handler(evt);
  134. return IRQ_HANDLED;
  135. }
  136. static struct irqaction mxc_timer_irq = {
  137. .name = "i.MX Timer Tick",
  138. .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
  139. .handler = mxc_timer_interrupt,
  140. };
  141. static struct clock_event_device clockevent_mxc = {
  142. .name = "mxc_timer1",
  143. .features = CLOCK_EVT_FEAT_ONESHOT,
  144. .shift = 32,
  145. .set_mode = mxc_set_mode,
  146. .set_next_event = mxc_set_next_event,
  147. .rating = 200,
  148. };
  149. static int __init mxc_clockevent_init(void)
  150. {
  151. unsigned int clock;
  152. clock = clk_get_rate(timer_clk);
  153. clockevent_mxc.mult = div_sc(clock, NSEC_PER_SEC,
  154. clockevent_mxc.shift);
  155. clockevent_mxc.max_delta_ns =
  156. clockevent_delta2ns(0xfffffffe, &clockevent_mxc);
  157. clockevent_mxc.min_delta_ns =
  158. clockevent_delta2ns(0xff, &clockevent_mxc);
  159. clockevent_mxc.cpumask = cpumask_of_cpu(0);
  160. clockevents_register_device(&clockevent_mxc);
  161. return 0;
  162. }
  163. void __init mxc_timer_init(const char *clk_timer)
  164. {
  165. timer_clk = clk_get(NULL, clk_timer);
  166. if (!timer_clk) {
  167. printk(KERN_ERR"Cannot determine timer clock. Giving up.\n");
  168. return;
  169. }
  170. clk_enable(timer_clk);
  171. /*
  172. * Initialise to a known state (all timers off, and timing reset)
  173. */
  174. __raw_writel(0, TIMER_BASE + MXC_TCTL);
  175. __raw_writel(0, TIMER_BASE + MXC_TPRER); /* see datasheet note */
  176. __raw_writel(TCTL_FRR | /* free running */
  177. TCTL_VAL | /* set clocksource and arch specific bits */
  178. TCTL_TEN, /* start the timer */
  179. TIMER_BASE + MXC_TCTL);
  180. /* init and register the timer to the framework */
  181. mxc_clocksource_init();
  182. mxc_clockevent_init();
  183. /* Make irqs happen */
  184. setup_irq(TIMER_INTERRUPT, &mxc_timer_irq);
  185. }