PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/arch/arm/plat-mxc/irq.c

https://bitbucket.org/sola/android_board_imx53qsb_kernel
C | 297 lines | 167 code | 44 blank | 86 comment | 15 complexity | 547d19a01f358dcc030056061528baf6 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1. /*
  2. * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
  3. * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License
  7. * as published by the Free Software Foundation; either version 2
  8. * of the License, or (at your option) any later version.
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  17. * MA 02110-1301, USA.
  18. */
  19. #include <linux/module.h>
  20. #include <linux/irq.h>
  21. #include <linux/io.h>
  22. #include <linux/sysdev.h>
  23. #include <mach/common.h>
  24. #include <asm/mach/irq.h>
  25. #include <mach/hardware.h>
  26. #define AVIC_INTCNTL 0x00 /* int control reg */
  27. #define AVIC_NIMASK 0x04 /* int mask reg */
  28. #define AVIC_INTENNUM 0x08 /* int enable number reg */
  29. #define AVIC_INTDISNUM 0x0C /* int disable number reg */
  30. #define AVIC_INTENABLEH 0x10 /* int enable reg high */
  31. #define AVIC_INTENABLEL 0x14 /* int enable reg low */
  32. #define AVIC_INTTYPEH 0x18 /* int type reg high */
  33. #define AVIC_INTTYPEL 0x1C /* int type reg low */
  34. #define AVIC_NIPRIORITY(x) (0x20 + 4 * (7 - (x))) /* int priority */
  35. #define AVIC_NIVECSR 0x40 /* norm int vector/status */
  36. #define AVIC_FIVECSR 0x44 /* fast int vector/status */
  37. #define AVIC_INTSRCH 0x48 /* int source reg high */
  38. #define AVIC_INTSRCL 0x4C /* int source reg low */
  39. #define AVIC_INTFRCH 0x50 /* int force reg high */
  40. #define AVIC_INTFRCL 0x54 /* int force reg low */
  41. #define AVIC_NIPNDH 0x58 /* norm int pending high */
  42. #define AVIC_NIPNDL 0x5C /* norm int pending low */
  43. #define AVIC_FIPNDH 0x60 /* fast int pending high */
  44. #define AVIC_FIPNDL 0x64 /* fast int pending low */
  45. void __iomem *avic_base;
  46. #define IRQ_BIT(irq) (1 << (irq))
  47. static uint32_t saved_wakeup_low, saved_wakeup_high;
  48. static uint32_t suspend_wakeup_low, suspend_wakeup_high;
  49. int imx_irq_set_priority(unsigned char irq, unsigned char prio)
  50. {
  51. #ifdef CONFIG_MXC_IRQ_PRIOR
  52. unsigned int temp;
  53. unsigned int mask = 0x0F << irq % 8 * 4;
  54. if (irq >= MXC_INTERNAL_IRQS)
  55. return -EINVAL;;
  56. temp = __raw_readl(avic_base + AVIC_NIPRIORITY(irq / 8));
  57. temp &= ~mask;
  58. temp |= prio & mask;
  59. __raw_writel(temp, avic_base + AVIC_NIPRIORITY(irq / 8));
  60. return 0;
  61. #else
  62. return -ENOSYS;
  63. #endif
  64. }
  65. EXPORT_SYMBOL(imx_irq_set_priority);
  66. #ifdef CONFIG_FIQ
  67. int mxc_set_irq_fiq(unsigned int irq, unsigned int type)
  68. {
  69. unsigned int irqt;
  70. if (irq >= MXC_INTERNAL_IRQS)
  71. return -EINVAL;
  72. if (irq < MXC_INTERNAL_IRQS / 2) {
  73. irqt = __raw_readl(avic_base + AVIC_INTTYPEL) & ~(1 << irq);
  74. __raw_writel(irqt | (!!type << irq), avic_base + AVIC_INTTYPEL);
  75. } else {
  76. irq -= MXC_INTERNAL_IRQS / 2;
  77. irqt = __raw_readl(avic_base + AVIC_INTTYPEH) & ~(1 << irq);
  78. __raw_writel(irqt | (!!type << irq), avic_base + AVIC_INTTYPEH);
  79. }
  80. return 0;
  81. }
  82. EXPORT_SYMBOL(mxc_set_irq_fiq);
  83. #endif /* CONFIG_FIQ */
  84. /* Disable interrupt number "irq" in the AVIC */
  85. static void mxc_mask_irq(unsigned int irq)
  86. {
  87. __raw_writel(irq, avic_base + AVIC_INTDISNUM);
  88. }
  89. /* Enable interrupt number "irq" in the AVIC */
  90. static void mxc_unmask_irq(unsigned int irq)
  91. {
  92. __raw_writel(irq, avic_base + AVIC_INTENNUM);
  93. }
  94. /*!
  95. * Set interrupt number "irq" in the AVIC as a wake-up source.
  96. *
  97. * @param irq interrupt source number
  98. * @param enable enable as wake-up if equal to non-zero
  99. * disble as wake-up if equal to zero
  100. *
  101. * @return This function returns 0 on success.
  102. */
  103. static int mxc_set_wake_irq(unsigned int irq, unsigned int enable)
  104. {
  105. uint32_t *wakeup_intr;
  106. uint32_t irq_bit;
  107. if (irq < 32) {
  108. wakeup_intr = &suspend_wakeup_low;
  109. irq_bit = IRQ_BIT(irq);
  110. } else {
  111. wakeup_intr = &suspend_wakeup_high;
  112. irq_bit = IRQ_BIT(irq - 32);
  113. }
  114. if (enable) {
  115. *wakeup_intr |= irq_bit;
  116. } else {
  117. *wakeup_intr &= ~irq_bit;
  118. }
  119. return 0;
  120. }
  121. static struct irq_chip mxc_avic_chip = {
  122. .ack = mxc_mask_irq,
  123. .mask = mxc_mask_irq,
  124. .unmask = mxc_unmask_irq,
  125. .set_wake = mxc_set_wake_irq,
  126. };
  127. #ifdef CONFIG_PM
  128. /*!
  129. * This function puts the AVIC in low-power mode/state.
  130. * All the interrupts that are enabled are first saved.
  131. * Only those interrupts which registers as a wake source by calling
  132. * enable_irq_wake are enabled. All other interrupts are disabled.
  133. *
  134. * @param dev the system device structure used to give information
  135. * on AVIC to suspend
  136. * @param mesg the power state the device is entering
  137. *
  138. * @return The function always returns 0.
  139. */
  140. static int mxc_avic_suspend(struct sys_device *dev, pm_message_t mesg)
  141. {
  142. saved_wakeup_high = __raw_readl(avic_base + AVIC_INTENABLEH);
  143. saved_wakeup_low = __raw_readl(avic_base + AVIC_INTENABLEL);
  144. __raw_writel(suspend_wakeup_high, avic_base + AVIC_INTENABLEH);
  145. __raw_writel(suspend_wakeup_low, avic_base + AVIC_INTENABLEL);
  146. return 0;
  147. }
  148. /*!
  149. * This function brings the AVIC back from low-power state.
  150. * All the interrupts enabled before suspension are re-enabled from
  151. * the saved information.
  152. *
  153. * @param dev the system device structure used to give information
  154. * on AVIC to resume
  155. *
  156. * @return The function always returns 0.
  157. */
  158. static int mxc_avic_resume(struct sys_device *dev)
  159. {
  160. __raw_writel(saved_wakeup_high, avic_base + AVIC_INTENABLEH);
  161. __raw_writel(saved_wakeup_low, avic_base + AVIC_INTENABLEL);
  162. return 0;
  163. }
  164. #else
  165. #define mxc_avic_suspend NULL
  166. #define mxc_avic_resume NULL
  167. #endif /* CONFIG_PM */
  168. /*!
  169. * This structure contains pointers to the power management callback functions.
  170. */
  171. static struct sysdev_class mxc_avic_sysclass = {
  172. .name = "mxc_irq",
  173. .suspend = mxc_avic_suspend,
  174. .resume = mxc_avic_resume,
  175. };
  176. /*!
  177. * This structure represents AVIC as a system device.
  178. * System devices follow a slightly different driver model.
  179. * They don't need to do dynammic driver binding, can't be probed,
  180. * and don't reside on any type of peripheral bus.
  181. * So, it is represented and treated a little differently.
  182. */
  183. static struct sys_device mxc_avic_device = {
  184. .id = 0,
  185. .cls = &mxc_avic_sysclass,
  186. };
  187. /*
  188. * This function is used to get the AVIC Lo and Hi interrupts
  189. * that are enabled as wake up sources to wake up the core from suspend
  190. */
  191. void mxc_get_wake_irq(u32 *wake_src[])
  192. {
  193. *wake_src[0] = __raw_readl(avic_base + AVIC_INTENABLEL);
  194. *wake_src[1] = __raw_readl(avic_base + AVIC_INTENABLEH);
  195. }
  196. /*
  197. * This function initializes the AVIC hardware and disables all the
  198. * interrupts. It registers the interrupt enable and disable functions
  199. * to the kernel for each interrupt source.
  200. */
  201. void __init mxc_init_irq(void __iomem *irqbase)
  202. {
  203. int i;
  204. avic_base = irqbase;
  205. /* put the AVIC into the reset value with
  206. * all interrupts disabled
  207. */
  208. __raw_writel(0, avic_base + AVIC_INTCNTL);
  209. __raw_writel(0x1f, avic_base + AVIC_NIMASK);
  210. /* disable all interrupts */
  211. __raw_writel(0, avic_base + AVIC_INTENABLEH);
  212. __raw_writel(0, avic_base + AVIC_INTENABLEL);
  213. /* all IRQ no FIQ */
  214. __raw_writel(0, avic_base + AVIC_INTTYPEH);
  215. __raw_writel(0, avic_base + AVIC_INTTYPEL);
  216. for (i = 0; i < MXC_INTERNAL_IRQS; i++) {
  217. set_irq_chip(i, &mxc_avic_chip);
  218. set_irq_handler(i, handle_level_irq);
  219. set_irq_flags(i, IRQF_VALID);
  220. }
  221. /* Set default priority value (0) for all IRQ's */
  222. for (i = 0; i < 8; i++)
  223. __raw_writel(0, avic_base + AVIC_NIPRIORITY(i));
  224. /* init architectures chained interrupt handler */
  225. mxc_register_gpios();
  226. #ifdef CONFIG_FIQ
  227. /* Initialize FIQ */
  228. init_FIQ();
  229. #endif
  230. if (MXC_INT_FORCE >= 32)
  231. __raw_writel(1 << (MXC_INT_FORCE & 31), avic_base + AVIC_INTFRCH);
  232. else if (MXC_INT_FORCE >= 0)
  233. __raw_writel(1 << MXC_INT_FORCE, avic_base + AVIC_INTFRCL);
  234. printk(KERN_INFO "MXC IRQ initialized\n");
  235. }
  236. /*!
  237. * This function registers AVIC hardware as a system device.
  238. * System devices will only be suspended with interrupts disabled, and
  239. * after all other devices have been suspended. On resume, they will be
  240. * resumed before any other devices, and also with interrupts disabled.
  241. *
  242. * @return This function returns 0 on success.
  243. */
  244. static int __init mxc_avic_sysinit(void)
  245. {
  246. int ret = 0;
  247. ret = sysdev_class_register(&mxc_avic_sysclass);
  248. if (ret == 0) {
  249. ret = sysdev_register(&mxc_avic_device);
  250. }
  251. return ret;
  252. }
  253. arch_initcall(mxc_avic_sysinit);