irq.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (C) 2002 MIZI Research, Inc.
  3.  *
  4.  * machine dependent irq handling routine
  5.  *
  6.  * Author: Nandy Lyu <nandy@mizi.com>
  7.  * Date  : $Date: 2002/05/14 02:19:42 $ 
  8.  *
  9.  * $Revision: 1.1.2.4 $
  10.    Tue May 21 2002 Nandy Lyu <nandy@mizi.com>
  11.    - initial
  12.    - BUG:
  13. 1) set_EINT_IRQ_edge 颊毫具 凳
  14. 2) INTSUBMSK绰 阿 device driver俊辑 力绢窍档废 秦具 窃.
  15.    Wed Aug 14 2002 Yong-iL Joh <tolkien@mizi.com>
  16.    - new irq scheme阑 利侩, 困俊 攫鞭等 bug 绊魔
  17.  *
  18.  * This file is subject to the terms and conditions of the GNU General Public
  19.  * License.  See the file COPYING in the main directory of this archive
  20.  * for more details.
  21.  */
  22. #include <linux/config.h>
  23. #include <linux/kernel.h>
  24. #include <linux/module.h>
  25. #include <linux/init.h>
  26. #include <linux/sched.h>
  27. #include <linux/ioport.h>
  28. #include <linux/interrupt.h>
  29. #include <asm/hardware.h>
  30. #include <asm/irq.h>
  31. #include <asm/mach/irq.h>
  32. #define ClearPending(x) {
  33.   SRCPND = (1 << (x));
  34.   INTPND = (1 << (x));
  35. }
  36. #define EINT_OFFSET(x) ((x) - NORMAL_IRQ_OFFSET + 4)
  37. #define SUBIRQ_OFFSET(x) ((x) - EXT_IRQ_OFFSET)
  38. #define EXTINT_MASK 0x7
  39. #if 0
  40. /*
  41.  * set_GPIO_IRQ_edge - set interrupt signal for External Interrupts
  42.  *
  43.  * parameters:
  44.  * irq number of external interrupt (IRQ_EINT0 ~ IRQ_EINT23)
  45.  * edge signal method
  46.  */
  47. #define EXTINT_OFFSET 0x4
  48. #define EXTINT_MASK 0x7
  49. int set_EXT_IRQ_mode(int irq, int edge) {
  50. unsigned long flags;
  51. int shift_value;
  52. if (!(((IRQ_EINT4 <= irq) && (irq <= IRQ_EINT23)) ||
  53.       ((IRQ_EINT0 <= irq) && (irq <= IRQ_EINT3))))
  54.   return -EINVAL;
  55. local_irq_save(flags);
  56. if (irq < IRQ_EINT4) { /* IRQ_EINT0 ~ IRQ_EINT3 */
  57.   shift_value = (irq % 8) * EXTINT_OFFSET;
  58.   EXTINT0 &= ~(EXTINT_MASK << shift_value);
  59.   EXTINT0 |= (edge << shift_value);
  60.   ClearPending(irq);
  61. } else {
  62.   shift_value = ((irq + 4) % 8) * EXTINT_OFFSET;
  63.   if (irq < IRQ_EINT8) { /* IRQ_EINT4 ~ IRQ_EINT7 */
  64.     EXTINT0 &= ~(EXTINT_MASK << shift_value);
  65.     EXTINT0 |= (edge << shift_value);
  66.     EINTPEND = (1 << shift_value);
  67.     ClearPending(IRQ_EINT4_7);
  68.   } else if (irq < IRQ_EINT16) { /* IRQ_EINT8 ~ IRQ_EINT15 */
  69.     EXTINT1 &= ~(EXTINT_MASK << shift_value);
  70.     EXTINT1 |= (edge << shift_value);
  71.     EINTPEND = (1 << shift_value);
  72.     ClearPending(IRQ_EINT8_23);
  73.   } else { /* IRQ_EINT16 ~ IRQ_EINT23 */
  74.     EXTINT2 &= ~(EXTINT_MASK << shift_value);
  75.     EXTINT2 |= (edge << shift_value);
  76.     EINTPEND = (1 << shift_value);
  77.     ClearPending(IRQ_EINT8_23);
  78.   }
  79. }
  80. irq_desc[irq].valid = 1;
  81. restore_flags(flags);
  82. return 0;
  83. }
  84. EXPORT_SYMBOL(set_EXT_IRQ_mode);
  85. #endif
  86. /*
  87.  * External IRQ甫 力寇茄 IRQ甸阑 request_irq()肺 殿废窍扁 傈俊
  88.  * 购啊 秦林绢具 瞪 老甸捞 乐阑鳖夸? 力 积阿俊绰 绝促绊 壕聪促.
  89.  * IRQ甸 吝俊辑 External IRQ(伙己俊辑 林厘窍绰 侩绢)父捞 GPIO甫
  90.  * 固府 汲沥窍绊 甸绢啊具 邓聪促. 弊贰辑 窍唱狼 窃荐俊辑
  91.  * 葛电 巴阑 秦搬秦 滚府绰 巴篮 绢冻鳖 酵焙夸.
  92.  *
  93.  * 2002.09.03 厘绕.
  94.  */
  95. static int inline
  96. fixup_irq_num(int irq)
  97. {
  98. if (irq < IRQ_EINT4) return irq;
  99. else return ((irq + 4) - NORMAL_IRQ_OFFSET);
  100. }
  101. static void inline
  102. set_gpios(int irq, int pullup)
  103. {
  104. int shift;
  105. if (irq < 8) {
  106. shift = 2*irq;
  107. GPFCON &= ~(0x3 << shift);
  108. GPFCON |= (0x2 << shift);
  109. GPFUP &= ~(GRAB_PULLUP(pullup) << irq);
  110. GPFUP |= (GRAB_PULLUP(pullup) << irq);
  111. } else {
  112. shift = 2*(irq - 8);
  113. GPGCON &= ~(0x3 << shift);
  114. GPGCON |= (0x2 << shift);
  115. GPGUP &= ~(GRAB_PULLUP(pullup) << (irq - 8));
  116. GPGUP |= (GRAB_PULLUP(pullup) << (irq - 8));
  117. }
  118. int 
  119. set_external_irq(int irq, int edge, int pullup)
  120. {
  121. unsigned long flags;
  122. int real_irq, reg_ofs, shift;
  123. volatile u32 *extint = (volatile u32 *)io_p2v(0x56000088);
  124. //printk(__FUNCTION__" calledn");
  125. if (((irq < IRQ_EINT0) && (irq > IRQ_EINT23)) ||
  126.     ((irq > IRQ_EINT3) && (irq < IRQ_EINT4)))
  127. return -EINVAL;
  128. real_irq = fixup_irq_num(irq);
  129. //printk(__FUNCTION__"(): real_irq = %dn", real_irq);
  130. set_gpios(real_irq, pullup);
  131. local_irq_save(flags);
  132. reg_ofs = (real_irq / 8);
  133. //printk(__FUNCTION__"(): regs_ofs = %dn", reg_ofs);
  134. shift = 4 * (real_irq - 8 * reg_ofs);
  135. extint += reg_ofs;
  136. *extint &= ~(EXTINT_MASK << shift);
  137. *extint |= (edge << shift);
  138. if (irq < 4) {
  139. SRCPND |= (1 << real_irq);
  140. INTPND |= (1 << real_irq);
  141. } else {
  142. EINTPEND |= (1 << real_irq);
  143. }
  144. irq_desc[irq].valid = 1;
  145. restore_flags(flags);
  146. return 0;
  147. }
  148. EXPORT_SYMBOL(set_external_irq);
  149. /*
  150.  * Defined irq handlers
  151.  */
  152. static void s3c2410_mask_ack_irq(unsigned int irq)
  153. {
  154. INTMSK |= (1 << irq);
  155. SRCPND = (1 << irq);
  156. INTPND = (1 << irq);
  157. }
  158. static void s3c2410_mask_irq(unsigned int irq)
  159. {
  160. INTMSK |= (1 << irq);
  161. }
  162. static void s3c2410_unmask_irq(unsigned int irq)
  163. {
  164. INTMSK &= ~(1 << irq);
  165. }
  166. /* for EINT? */
  167. static void EINT4_23mask_ack_irq(unsigned int irq)
  168. {
  169. irq = EINT_OFFSET(irq);
  170. EINTMASK |= (1 << irq);
  171. EINTPEND = (1 << irq);
  172. if (irq < EINT_OFFSET(IRQ_EINT8)) {
  173. //   INTMSK |= (1 << SHIFT_EINT4_7);
  174.   ClearPending(SHIFT_EINT4_7);
  175. } else {
  176. //   INTMSK |= (1 << SHIFT_EINT8_23);
  177.   ClearPending(SHIFT_EINT8_23);
  178. }
  179. }
  180. static void EINT4_23mask_irq(unsigned int irq)
  181. {
  182. #if 0
  183. if (irq < IRQ_EINT8) {
  184.   INTMSK |= (1 << SHIFT_EINT4_7);
  185. } else {
  186.   INTMSK |= (1 << SHIFT_EINT8_23);
  187. }
  188. #endif
  189. irq = EINT_OFFSET(irq);
  190. EINTMASK |= (1 << irq);
  191. }
  192. static void EINT4_23unmask_irq(unsigned int irq)
  193. {
  194. EINTMASK &= ~(1 << EINT_OFFSET(irq));
  195. if (irq < IRQ_EINT8) {
  196.   INTMSK &= ~(1 << SHIFT_EINT4_7);
  197. } else {
  198.   INTMSK &= ~(1 << SHIFT_EINT8_23);
  199. }
  200. }
  201. /* for sub_IRQ */
  202. static void SUB_mask_ack_irq(unsigned int irq)
  203. {
  204. INTSUBMSK |= (1 << SUBIRQ_OFFSET(irq));
  205. SUBSRCPND = (1 << SUBIRQ_OFFSET(irq));
  206. if (irq <= IRQ_ERR0) {
  207.   ClearPending(SHIFT_UART0);
  208.         } else if (irq <= IRQ_ERR1) {
  209.   ClearPending(SHIFT_UART1);
  210. } else if (irq <= IRQ_ERR2){
  211.   ClearPending(SHIFT_UART2);
  212.         } else { /* if ( irq <= IRQ_ADC_DONE ) { */
  213.   ClearPending(SHIFT_ADCTC);
  214. }
  215. }
  216. static void SUB_mask_irq(unsigned int irq)
  217. {
  218. INTSUBMSK |= (1 << SUBIRQ_OFFSET(irq));
  219. }
  220. static void SUB_unmask_irq(unsigned int irq)
  221. {
  222. INTSUBMSK &= ~(1 << SUBIRQ_OFFSET(irq));
  223. if (irq <= IRQ_ERR0) {
  224. INTMSK &= ~(1 << SHIFT_UART0); 
  225.         } else if (irq <= IRQ_ERR1) {
  226. INTMSK &= ~(1 << SHIFT_UART1);
  227. } else if (irq <= IRQ_ERR2){
  228.      INTMSK &= ~(1 << SHIFT_UART2);
  229.         } else { /* if ( irq <= IRQ_ADC_DONE ) { */
  230. INTMSK &= ~(1 << SHIFT_ADCTC);
  231.         }
  232. }
  233. /*
  234.  *  fixup_irq() for do_IRQ() in kernel/irq.c
  235.  */
  236. inline unsigned int get_subIRQ(int irq, int begin, int end, int fail_irq) {
  237. int i;
  238. for(i=begin; i <= end; i++) {
  239.   if (irq & (1 << i))
  240.     return (EXT_IRQ_OFFSET + i);
  241. }
  242. return fail_irq;
  243. }
  244. inline unsigned int get_extIRQ(int irq, int begin, int end, int fail_irq) {
  245. int i;
  246. for(i=begin; i <= end; i++) {
  247.   if (irq & (1 << i))
  248.     return (NORMAL_IRQ_OFFSET - 4 + i);
  249. }
  250. return fail_irq;
  251. }
  252. unsigned int fixup_irq(int irq) {
  253.     unsigned int ret;
  254.     unsigned long sub_mask, ext_mask;
  255.     if (irq == OS_TIMER)
  256.       return irq;
  257.     switch (irq) {
  258.     case IRQ_UART0:
  259.       sub_mask = SUBSRCPND & ~INTSUBMSK;
  260.       ret = get_subIRQ(sub_mask, 0, 2, irq);
  261.       break;
  262.     case IRQ_UART1:
  263.       sub_mask = SUBSRCPND & ~INTSUBMSK;
  264.       ret = get_subIRQ(sub_mask, 3, 5, irq);
  265.       break;
  266.     case IRQ_UART2:
  267.       sub_mask = SUBSRCPND & ~INTSUBMSK;
  268.       ret = get_subIRQ(sub_mask, 6, 8, irq);
  269.       break;
  270.     case IRQ_ADCTC:
  271.       sub_mask = SUBSRCPND & ~INTSUBMSK;
  272.       ret = get_subIRQ(sub_mask, 9, 10, irq);
  273.       break;
  274.     case IRQ_EINT4_7:
  275.       ext_mask = EINTPEND & ~EINTMASK;
  276.       ret = get_extIRQ(ext_mask, 4, 7, irq);
  277.       break;
  278.     case IRQ_EINT8_23:
  279.       ext_mask = EINTPEND & ~EINTMASK;
  280.       ret = get_extIRQ(ext_mask, 8, 23, irq);
  281.       break;
  282.     default:
  283.       ret = irq;
  284.     }
  285.     return ret;
  286. }
  287. static struct resource irq_resource = {
  288. name: "irqs",
  289. start: 0x4a000000,
  290. end: 0x4a00001f,
  291. };
  292. static struct resource eint_resource = {
  293. name: "ext irqs",
  294. start: 0x56000088,
  295. end: 0x560000ab,
  296. };
  297. void __init s3c2410_init_irq(void) {
  298.     int irq;
  299.     request_resource(&iomem_resource, &irq_resource);
  300.     request_resource(&iomem_resource, &eint_resource);
  301.     /* disable all IRQs */
  302.     INTMSK = 0xffffffff;
  303.     INTSUBMSK = 0x7ff;
  304.     EINTMASK = 0x00fffff0;
  305.     /* all IRQs are IRQ, not FIQ
  306.        0 : IRQ mode
  307.        1 : FIQ mode
  308.     */
  309.     INTMOD = 0x00000000;
  310.     /* clear Source/Interrupt Pending Register */
  311.     SRCPND = 0xffffffff;
  312.     INTPND = 0xffffffff;
  313.     SUBSRCPND = 0x7ff;
  314.     EINTPEND = 0x00fffff0;
  315.     /* Define irq handler */
  316.     for (irq=0; irq < NORMAL_IRQ_OFFSET; irq++) {
  317.       irq_desc[irq].valid = 1;
  318.       irq_desc[irq].probe_ok = 1;
  319.       irq_desc[irq].mask_ack = s3c2410_mask_ack_irq;
  320.       irq_desc[irq].mask = s3c2410_mask_irq;
  321.       irq_desc[irq].unmask = s3c2410_unmask_irq;
  322.     }
  323.       irq_desc[IRQ_RESERVED6].valid = 0;
  324.       irq_desc[IRQ_RESERVED24].valid = 0;
  325.       irq_desc[IRQ_EINT4_7].valid = 0;
  326.       irq_desc[IRQ_EINT8_23].valid = 0;
  327.       irq_desc[IRQ_EINT0].valid = 0;
  328.       irq_desc[IRQ_EINT1].valid = 0;
  329.       irq_desc[IRQ_EINT2].valid = 0;
  330.       irq_desc[IRQ_EINT3].valid = 0;
  331.     for (irq=NORMAL_IRQ_OFFSET; irq < EXT_IRQ_OFFSET; irq++) {
  332.       irq_desc[irq].valid = 0;
  333.       irq_desc[irq].probe_ok = 1;
  334.       irq_desc[irq].mask_ack = EINT4_23mask_ack_irq;
  335.       irq_desc[irq].mask = EINT4_23mask_irq;
  336.       irq_desc[irq].unmask = EINT4_23unmask_irq;
  337.     }
  338.     for (irq=EXT_IRQ_OFFSET; irq < SUB_IRQ_OFFSET; irq++) {
  339.       irq_desc[irq].valid = 1;
  340.       irq_desc[irq].probe_ok = 1;
  341.       irq_desc[irq].mask_ack = SUB_mask_ack_irq;
  342.       irq_desc[irq].mask = SUB_mask_irq;
  343.       irq_desc[irq].unmask = SUB_unmask_irq;
  344.     }  
  345. }
  346. /*
  347.  | $Id: event.c,v 1.1.2.4 2002/05/14 02:19:42 tolkien Exp $
  348.  |
  349.  | Local Variables:
  350.  | mode: c
  351.  | mode: font-lock
  352.  | version-control: t
  353.  | delete-old-versions: t
  354.  | End:
  355.  |
  356.  | -*- End-Of-File -*-
  357.  */