dmtimer.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. * linux/arch/arm/plat-omap/dmtimer.c
  3. *
  4. * OMAP Dual-Mode Timers
  5. *
  6. * Copyright (C) 2005 Nokia Corporation
  7. * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
  8. *
  9. * This program is free software; you can redistribute it and/or modify it
  10. * under the terms of the GNU General Public License as published by the
  11. * Free Software Foundation; either version 2 of the License, or (at your
  12. * option) any later version.
  13. *
  14. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  15. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  16. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
  17. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  18. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  21. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. *
  23. * You should have received a copy of the GNU General Public License along
  24. * with this program; if not, write to the Free Software Foundation, Inc.,
  25. * 675 Mass Ave, Cambridge, MA 02139, USA.
  26. */
  27. #include <linux/init.h>
  28. #include <asm/arch/hardware.h>
  29. #include <asm/arch/dmtimer.h>
  30. #include <asm/io.h>
  31. #include <asm/arch/irqs.h>
  32. #include <linux/spinlock.h>
  33. #include <linux/list.h>
  34. #define OMAP_TIMER_COUNT 8
  35. #define OMAP_TIMER_ID_REG 0x00
  36. #define OMAP_TIMER_OCP_CFG_REG 0x10
  37. #define OMAP_TIMER_SYS_STAT_REG 0x14
  38. #define OMAP_TIMER_STAT_REG 0x18
  39. #define OMAP_TIMER_INT_EN_REG 0x1c
  40. #define OMAP_TIMER_WAKEUP_EN_REG 0x20
  41. #define OMAP_TIMER_CTRL_REG 0x24
  42. #define OMAP_TIMER_COUNTER_REG 0x28
  43. #define OMAP_TIMER_LOAD_REG 0x2c
  44. #define OMAP_TIMER_TRIGGER_REG 0x30
  45. #define OMAP_TIMER_WRITE_PEND_REG 0x34
  46. #define OMAP_TIMER_MATCH_REG 0x38
  47. #define OMAP_TIMER_CAPTURE_REG 0x3c
  48. #define OMAP_TIMER_IF_CTRL_REG 0x40
  49. static struct dmtimer_info_struct {
  50. struct list_head unused_timers;
  51. struct list_head reserved_timers;
  52. } dm_timer_info;
  53. static struct omap_dm_timer dm_timers[] = {
  54. { .base=0xfffb1400, .irq=INT_1610_GPTIMER1 },
  55. { .base=0xfffb1c00, .irq=INT_1610_GPTIMER2 },
  56. { .base=0xfffb2400, .irq=INT_1610_GPTIMER3 },
  57. { .base=0xfffb2c00, .irq=INT_1610_GPTIMER4 },
  58. { .base=0xfffb3400, .irq=INT_1610_GPTIMER5 },
  59. { .base=0xfffb3c00, .irq=INT_1610_GPTIMER6 },
  60. { .base=0xfffb4400, .irq=INT_1610_GPTIMER7 },
  61. { .base=0xfffb4c00, .irq=INT_1610_GPTIMER8 },
  62. { .base=0x0 },
  63. };
  64. static spinlock_t dm_timer_lock;
  65. inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value)
  66. {
  67. omap_writel(value, timer->base + reg);
  68. while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG))
  69. ;
  70. }
  71. u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg)
  72. {
  73. return omap_readl(timer->base + reg);
  74. }
  75. int omap_dm_timers_active(void)
  76. {
  77. struct omap_dm_timer *timer;
  78. for (timer = &dm_timers[0]; timer->base; ++timer)
  79. if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
  80. OMAP_TIMER_CTRL_ST)
  81. return 1;
  82. return 0;
  83. }
  84. void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
  85. {
  86. int n = (timer - dm_timers) << 1;
  87. u32 l;
  88. l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
  89. l |= source << n;
  90. omap_writel(l, MOD_CONF_CTRL_1);
  91. }
  92. static void omap_dm_timer_reset(struct omap_dm_timer *timer)
  93. {
  94. /* Reset and set posted mode */
  95. omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
  96. omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, 0x02);
  97. omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR);
  98. }
  99. struct omap_dm_timer * omap_dm_timer_request(void)
  100. {
  101. struct omap_dm_timer *timer = NULL;
  102. unsigned long flags;
  103. spin_lock_irqsave(&dm_timer_lock, flags);
  104. if (!list_empty(&dm_timer_info.unused_timers)) {
  105. timer = (struct omap_dm_timer *)
  106. dm_timer_info.unused_timers.next;
  107. list_move_tail((struct list_head *)timer,
  108. &dm_timer_info.reserved_timers);
  109. }
  110. spin_unlock_irqrestore(&dm_timer_lock, flags);
  111. return timer;
  112. }
  113. void omap_dm_timer_free(struct omap_dm_timer *timer)
  114. {
  115. unsigned long flags;
  116. omap_dm_timer_reset(timer);
  117. spin_lock_irqsave(&dm_timer_lock, flags);
  118. list_move_tail((struct list_head *)timer, &dm_timer_info.unused_timers);
  119. spin_unlock_irqrestore(&dm_timer_lock, flags);
  120. }
  121. void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
  122. unsigned int value)
  123. {
  124. omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
  125. }
  126. unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
  127. {
  128. return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
  129. }
  130. void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
  131. {
  132. omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value);
  133. }
  134. void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer)
  135. {
  136. u32 l;
  137. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  138. l |= OMAP_TIMER_CTRL_AR;
  139. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  140. }
  141. void omap_dm_timer_trigger(struct omap_dm_timer *timer)
  142. {
  143. omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1);
  144. }
  145. void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value)
  146. {
  147. u32 l;
  148. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  149. l |= value & 0x3;
  150. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  151. }
  152. void omap_dm_timer_start(struct omap_dm_timer *timer)
  153. {
  154. u32 l;
  155. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  156. l |= OMAP_TIMER_CTRL_ST;
  157. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  158. }
  159. void omap_dm_timer_stop(struct omap_dm_timer *timer)
  160. {
  161. u32 l;
  162. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  163. l &= ~0x1;
  164. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  165. }
  166. unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
  167. {
  168. return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
  169. }
  170. void omap_dm_timer_reset_counter(struct omap_dm_timer *timer)
  171. {
  172. omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0);
  173. }
  174. void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load)
  175. {
  176. omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
  177. }
  178. void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match)
  179. {
  180. omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
  181. }
  182. void omap_dm_timer_enable_compare(struct omap_dm_timer *timer)
  183. {
  184. u32 l;
  185. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  186. l |= OMAP_TIMER_CTRL_CE;
  187. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  188. }
  189. static inline void __dm_timer_init(void)
  190. {
  191. struct omap_dm_timer *timer;
  192. spin_lock_init(&dm_timer_lock);
  193. INIT_LIST_HEAD(&dm_timer_info.unused_timers);
  194. INIT_LIST_HEAD(&dm_timer_info.reserved_timers);
  195. timer = &dm_timers[0];
  196. while (timer->base) {
  197. list_add_tail((struct list_head *)timer, &dm_timer_info.unused_timers);
  198. omap_dm_timer_reset(timer);
  199. timer++;
  200. }
  201. }
  202. static int __init omap_dm_timer_init(void)
  203. {
  204. if (cpu_is_omap16xx())
  205. __dm_timer_init();
  206. return 0;
  207. }
  208. arch_initcall(omap_dm_timer_init);