irq-eint.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /*
  2. * linux/arch/arm/plat-s5pc1xx/irq-eint.c
  3. *
  4. * Copyright 2009 Samsung Electronics Co.
  5. * Byungho Min <bhmin@samsung.com>
  6. * Kyungin Park <kyungmin.park@samsung.com>
  7. *
  8. * Based on plat-s3c64xx/irq-eint.c
  9. *
  10. * S5PC1XX - Interrupt handling for IRQ_EINT(x)
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License version 2 as
  14. * published by the Free Software Foundation.
  15. */
  16. #include <linux/kernel.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/irq.h>
  19. #include <linux/io.h>
  20. #include <linux/sysdev.h>
  21. #include <linux/pm.h>
  22. #include <linux/gpio.h>
  23. #include <asm/hardware/vic.h>
  24. #include <mach/map.h>
  25. #include <plat/gpio-cfg.h>
  26. #include <plat/gpio-ext.h>
  27. #include <plat/pm.h>
  28. #include <plat/regs-gpio.h>
  29. #include <plat/regs-irqtype.h>
  30. /*
  31. * bank is a group of external interrupt
  32. * bank0 means EINT0 ... EINT7
  33. * bank1 means EINT8 ... EINT15
  34. * bank2 means EINT16 ... EINT23
  35. * bank3 means EINT24 ... EINT31
  36. */
  37. static inline int s3c_get_eint(unsigned int irq)
  38. {
  39. int real;
  40. if (irq < IRQ_EINT16_31)
  41. real = (irq - IRQ_EINT0);
  42. else
  43. real = (irq - S3C_IRQ_EINT_BASE) + IRQ_EINT16_31 - IRQ_EINT0;
  44. return real;
  45. }
  46. static inline int s3c_get_bank(unsigned int irq)
  47. {
  48. return s3c_get_eint(irq) >> 3;
  49. }
  50. static inline int s3c_eint_to_bit(unsigned int irq)
  51. {
  52. int real, bit;
  53. real = s3c_get_eint(irq);
  54. bit = 1 << (real & (8 - 1));
  55. return bit;
  56. }
  57. static inline void s3c_irq_eint_mask(unsigned int irq)
  58. {
  59. u32 mask;
  60. u32 bank = s3c_get_bank(irq);
  61. mask = __raw_readl(S5PC1XX_WKUP_INT_MASK(bank));
  62. mask |= s3c_eint_to_bit(irq);
  63. __raw_writel(mask, S5PC1XX_WKUP_INT_MASK(bank));
  64. }
  65. static void s3c_irq_eint_unmask(unsigned int irq)
  66. {
  67. u32 mask;
  68. u32 bank = s3c_get_bank(irq);
  69. mask = __raw_readl(S5PC1XX_WKUP_INT_MASK(bank));
  70. mask &= ~(s3c_eint_to_bit(irq));
  71. __raw_writel(mask, S5PC1XX_WKUP_INT_MASK(bank));
  72. }
  73. static inline void s3c_irq_eint_ack(unsigned int irq)
  74. {
  75. u32 bank = s3c_get_bank(irq);
  76. __raw_writel(s3c_eint_to_bit(irq), S5PC1XX_WKUP_INT_PEND(bank));
  77. }
  78. static void s3c_irq_eint_maskack(unsigned int irq)
  79. {
  80. /* compiler should in-line these */
  81. s3c_irq_eint_mask(irq);
  82. s3c_irq_eint_ack(irq);
  83. }
  84. static int s3c_irq_eint_set_type(unsigned int irq, unsigned int type)
  85. {
  86. u32 bank = s3c_get_bank(irq);
  87. int real = s3c_get_eint(irq);
  88. int gpio, shift, sfn;
  89. u32 ctrl, con = 0;
  90. switch (type) {
  91. case IRQ_TYPE_NONE:
  92. printk(KERN_WARNING "No edge setting!\n");
  93. break;
  94. case IRQ_TYPE_EDGE_RISING:
  95. con = S5PC1XX_WKUP_INT_RISEEDGE;
  96. break;
  97. case IRQ_TYPE_EDGE_FALLING:
  98. con = S5PC1XX_WKUP_INT_FALLEDGE;
  99. break;
  100. case IRQ_TYPE_EDGE_BOTH:
  101. con = S5PC1XX_WKUP_INT_BOTHEDGE;
  102. break;
  103. case IRQ_TYPE_LEVEL_LOW:
  104. con = S5PC1XX_WKUP_INT_LOWLEV;
  105. break;
  106. case IRQ_TYPE_LEVEL_HIGH:
  107. con = S5PC1XX_WKUP_INT_HILEV;
  108. break;
  109. default:
  110. printk(KERN_ERR "No such irq type %d", type);
  111. return -EINVAL;
  112. }
  113. gpio = real & (8 - 1);
  114. shift = gpio << 2;
  115. ctrl = __raw_readl(S5PC1XX_WKUP_INT_CON(bank));
  116. ctrl &= ~(0x7 << shift);
  117. ctrl |= con << shift;
  118. __raw_writel(ctrl, S5PC1XX_WKUP_INT_CON(bank));
  119. switch (real) {
  120. case 0 ... 7:
  121. gpio = S5PC100_GPH0(gpio);
  122. break;
  123. case 8 ... 15:
  124. gpio = S5PC100_GPH1(gpio);
  125. break;
  126. case 16 ... 23:
  127. gpio = S5PC100_GPH2(gpio);
  128. break;
  129. case 24 ... 31:
  130. gpio = S5PC100_GPH3(gpio);
  131. break;
  132. default:
  133. return -EINVAL;
  134. }
  135. sfn = S3C_GPIO_SFN(0x2);
  136. s3c_gpio_cfgpin(gpio, sfn);
  137. return 0;
  138. }
  139. static struct irq_chip s3c_irq_eint = {
  140. .name = "EINT",
  141. .mask = s3c_irq_eint_mask,
  142. .unmask = s3c_irq_eint_unmask,
  143. .mask_ack = s3c_irq_eint_maskack,
  144. .ack = s3c_irq_eint_ack,
  145. .set_type = s3c_irq_eint_set_type,
  146. .set_wake = s3c_irqext_wake,
  147. };
  148. /* s3c_irq_demux_eint
  149. *
  150. * This function demuxes the IRQ from external interrupts,
  151. * from IRQ_EINT(16) to IRQ_EINT(31). It is designed to be inlined into
  152. * the specific handlers s3c_irq_demux_eintX_Y.
  153. */
  154. static inline void s3c_irq_demux_eint(unsigned int start, unsigned int end)
  155. {
  156. u32 status = __raw_readl(S5PC1XX_WKUP_INT_PEND((start >> 3)));
  157. u32 mask = __raw_readl(S5PC1XX_WKUP_INT_MASK((start >> 3)));
  158. unsigned int irq;
  159. status &= ~mask;
  160. status &= (1 << (end - start + 1)) - 1;
  161. for (irq = IRQ_EINT(start); irq <= IRQ_EINT(end); irq++) {
  162. if (status & 1)
  163. generic_handle_irq(irq);
  164. status >>= 1;
  165. }
  166. }
  167. static void s3c_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
  168. {
  169. s3c_irq_demux_eint(16, 23);
  170. s3c_irq_demux_eint(24, 31);
  171. }
  172. /*
  173. * Handle EINT0 ... EINT15 at VIC directly
  174. */
  175. static void s3c_irq_vic_eint_mask(unsigned int irq)
  176. {
  177. void __iomem *base = get_irq_chip_data(irq);
  178. unsigned int real;
  179. s3c_irq_eint_mask(irq);
  180. real = s3c_get_eint(irq);
  181. writel(1 << real, base + VIC_INT_ENABLE_CLEAR);
  182. }
  183. static void s3c_irq_vic_eint_unmask(unsigned int irq)
  184. {
  185. void __iomem *base = get_irq_chip_data(irq);
  186. unsigned int real;
  187. s3c_irq_eint_unmask(irq);
  188. real = s3c_get_eint(irq);
  189. writel(1 << real, base + VIC_INT_ENABLE);
  190. }
  191. static inline void s3c_irq_vic_eint_ack(unsigned int irq)
  192. {
  193. u32 bit;
  194. u32 bank = s3c_get_bank(irq);
  195. bit = s3c_eint_to_bit(irq);
  196. __raw_writel(bit, S5PC1XX_WKUP_INT_PEND(bank));
  197. }
  198. static void s3c_irq_vic_eint_maskack(unsigned int irq)
  199. {
  200. /* compiler should in-line these */
  201. s3c_irq_vic_eint_mask(irq);
  202. s3c_irq_vic_eint_ack(irq);
  203. }
  204. static struct irq_chip s3c_irq_vic_eint = {
  205. .name = "EINT",
  206. .mask = s3c_irq_vic_eint_mask,
  207. .unmask = s3c_irq_vic_eint_unmask,
  208. .mask_ack = s3c_irq_vic_eint_maskack,
  209. .ack = s3c_irq_vic_eint_ack,
  210. .set_type = s3c_irq_eint_set_type,
  211. .set_wake = s3c_irqext_wake,
  212. };
  213. static int __init s5pc1xx_init_irq_eint(void)
  214. {
  215. int irq;
  216. for (irq = IRQ_EINT0; irq <= IRQ_EINT15; irq++) {
  217. set_irq_chip(irq, &s3c_irq_vic_eint);
  218. set_irq_handler(irq, handle_level_irq);
  219. set_irq_flags(irq, IRQF_VALID);
  220. }
  221. for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) {
  222. set_irq_chip(irq, &s3c_irq_eint);
  223. set_irq_handler(irq, handle_level_irq);
  224. set_irq_flags(irq, IRQF_VALID);
  225. }
  226. set_irq_chained_handler(IRQ_EINT16_31, s3c_irq_demux_eint16_31);
  227. return 0;
  228. }
  229. arch_initcall(s5pc1xx_init_irq_eint);