timer.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * Copyright (C) 2009 Samsung Electronics
  3. * Heungjun Kim <riverful.kim@samsung.com>
  4. * Inki Dae <inki.dae@samsung.com>
  5. * Minkyu Kang <mk7.kang@samsung.com>
  6. *
  7. * See file CREDITS for list of people who contributed to this
  8. * project.
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License as
  12. * published by the Free Software Foundation; either version 2 of
  13. * the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23. * MA 02111-1307 USA
  24. */
  25. #include <common.h>
  26. #include <asm/io.h>
  27. #include <asm/arch/pwm.h>
  28. #include <asm/arch/clk.h>
  29. #define PRESCALER_1 (16 - 1) /* prescaler of timer 2, 3, 4 */
  30. #define MUX_DIV_2 1 /* 1/2 period */
  31. #define MUX_DIV_4 2 /* 1/4 period */
  32. #define MUX_DIV_8 3 /* 1/8 period */
  33. #define MUX_DIV_16 4 /* 1/16 period */
  34. #define MUX4_DIV_SHIFT 16
  35. #define TCON_TIMER4_SHIFT 20
  36. static unsigned long count_value;
  37. /* Internal tick units */
  38. static unsigned long long timestamp; /* Monotonic incrementing timer */
  39. static unsigned long lastdec; /* Last decremneter snapshot */
  40. /* macro to read the 16 bit timer */
  41. static inline struct s5p_timer *s5p_get_base_timer(void)
  42. {
  43. return (struct s5p_timer *)samsung_get_base_timer();
  44. }
  45. int timer_init(void)
  46. {
  47. struct s5p_timer *const timer = s5p_get_base_timer();
  48. u32 val;
  49. /*
  50. * @ PWM Timer 4
  51. * Timer Freq(HZ) =
  52. * PWM_CLK / { (prescaler_value + 1) * (divider_value) }
  53. */
  54. /* set prescaler : 16 */
  55. /* set divider : 2 */
  56. writel((PRESCALER_1 & 0xff) << 8, &timer->tcfg0);
  57. writel((MUX_DIV_2 & 0xf) << MUX4_DIV_SHIFT, &timer->tcfg1);
  58. /* count_value = 2085937.5(HZ) (per 1 sec)*/
  59. count_value = get_pwm_clk() / ((PRESCALER_1 + 1) *
  60. (MUX_DIV_2 + 1));
  61. /* count_value / 100 = 20859.375(HZ) (per 10 msec) */
  62. count_value = count_value / 100;
  63. /* set count value */
  64. writel(count_value, &timer->tcntb4);
  65. lastdec = count_value;
  66. val = (readl(&timer->tcon) & ~(0x07 << TCON_TIMER4_SHIFT)) |
  67. TCON4_AUTO_RELOAD;
  68. /* auto reload & manual update */
  69. writel(val | TCON4_UPDATE, &timer->tcon);
  70. /* start PWM timer 4 */
  71. writel(val | TCON4_START, &timer->tcon);
  72. timestamp = 0;
  73. return 0;
  74. }
  75. /*
  76. * timer without interrupts
  77. */
  78. void reset_timer(void)
  79. {
  80. reset_timer_masked();
  81. }
  82. unsigned long get_timer(unsigned long base)
  83. {
  84. return get_timer_masked() - base;
  85. }
  86. void set_timer(unsigned long t)
  87. {
  88. timestamp = t;
  89. }
  90. /* delay x useconds */
  91. void __udelay(unsigned long usec)
  92. {
  93. struct s5p_timer *const timer = s5p_get_base_timer();
  94. unsigned long tmo, tmp;
  95. count_value = readl(&timer->tcntb4);
  96. if (usec >= 1000) {
  97. /*
  98. * if "big" number, spread normalization
  99. * to seconds
  100. * 1. start to normalize for usec to ticks per sec
  101. * 2. find number of "ticks" to wait to achieve target
  102. * 3. finish normalize.
  103. */
  104. tmo = usec / 1000;
  105. tmo *= (CONFIG_SYS_HZ * count_value / 10);
  106. tmo /= 1000;
  107. } else {
  108. /* else small number, don't kill it prior to HZ multiply */
  109. tmo = usec * CONFIG_SYS_HZ * count_value / 10;
  110. tmo /= (1000 * 1000);
  111. }
  112. /* get current timestamp */
  113. tmp = get_timer(0);
  114. /* if setting this fordward will roll time stamp */
  115. /* reset "advancing" timestamp to 0, set lastdec value */
  116. /* else, set advancing stamp wake up time */
  117. if ((tmo + tmp + 1) < tmp)
  118. reset_timer_masked();
  119. else
  120. tmo += tmp;
  121. /* loop till event */
  122. while (get_timer_masked() < tmo)
  123. ; /* nop */
  124. }
  125. void reset_timer_masked(void)
  126. {
  127. struct s5p_timer *const timer = s5p_get_base_timer();
  128. /* reset time */
  129. lastdec = readl(&timer->tcnto4);
  130. timestamp = 0;
  131. }
  132. unsigned long get_timer_masked(void)
  133. {
  134. struct s5p_timer *const timer = s5p_get_base_timer();
  135. unsigned long now = readl(&timer->tcnto4);
  136. if (lastdec >= now)
  137. timestamp += lastdec - now;
  138. else
  139. timestamp += lastdec + count_value - now;
  140. lastdec = now;
  141. return timestamp;
  142. }
  143. /*
  144. * This function is derived from PowerPC code (read timebase as long long).
  145. * On ARM it just returns the timer value.
  146. */
  147. unsigned long long get_ticks(void)
  148. {
  149. return get_timer(0);
  150. }
  151. /*
  152. * This function is derived from PowerPC code (timebase clock frequency).
  153. * On ARM it returns the number of timer ticks per second.
  154. */
  155. unsigned long get_tbclk(void)
  156. {
  157. return CONFIG_SYS_HZ;
  158. }