giu.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:6k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * FILE NAME
  3.  * arch/mips/vr41xx/common/giu.c
  4.  *
  5.  * BRIEF MODULE DESCRIPTION
  6.  * General-purpose I/O Unit Interrupt routines for NEC VR4100 series.
  7.  *
  8.  * Author: Yoichi Yuasa
  9.  *         yyuasa@mvista.com or source@mvista.com
  10.  *
  11.  * Copyright 2002 MontaVista Software Inc.
  12.  *
  13.  *  This program is free software; you can redistribute it and/or modify it
  14.  *  under the terms of the GNU General Public License as published by the
  15.  *  Free Software Foundation; either version 2 of the License, or (at your
  16.  *  option) any later version.
  17.  *
  18.  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  19.  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  20.  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21.  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22.  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23.  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24.  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25.  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  26.  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  27.  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28.  *
  29.  *  You should have received a copy of the GNU General Public License along
  30.  *  with this program; if not, write to the Free Software Foundation, Inc.,
  31.  *  675 Mass Ave, Cambridge, MA 02139, USA.
  32.  */
  33. /*
  34.  * Changes:
  35.  *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
  36.  *  - New creation, NEC VR4111, VR4121, VR4122 and VR4131 are supported.
  37.  */
  38. #include <linux/errno.h>
  39. #include <linux/init.h>
  40. #include <linux/irq.h>
  41. #include <linux/kernel.h>
  42. #include <linux/types.h>
  43. #include <asm/addrspace.h>
  44. #include <asm/cpu.h>
  45. #include <asm/io.h>
  46. #include <asm/vr41xx/vr41xx.h>
  47. #define VR4111_GIUIOSELL KSEG1ADDR(0x0b000100)
  48. #define VR4122_GIUIOSELL KSEG1ADDR(0x0f000140)
  49. #define GIUIOSELL 0x00
  50. #define GIUIOSELH 0x02
  51. #define GIUINTSTATL 0x08
  52. #define GIUINTSTATH 0x0a
  53. #define GIUINTENL 0x0c
  54. #define GIUINTENH 0x0e
  55. #define GIUINTTYPL 0x10
  56. #define GIUINTTYPH 0x12
  57. #define GIUINTALSELL 0x14
  58. #define GIUINTALSELH 0x16
  59. #define GIUINTHTSELL 0x18
  60. #define GIUINTHTSELH 0x1a
  61. u32 vr41xx_giu_base = 0;
  62. #define read_giuint(offset) readw(vr41xx_giu_base + (offset))
  63. #define write_giuint(val, offset) writew((val), vr41xx_giu_base + (offset))
  64. static inline u16 set_giuint(u16 offset, u16 set)
  65. {
  66. u16 res;
  67. res = read_giuint(offset);
  68. res |= set;
  69. write_giuint(res, offset);
  70. return res;
  71. }
  72. static inline u16 clear_giuint(u16 offset, u16 clear)
  73. {
  74. u16 res;
  75. res = read_giuint(offset);
  76. res &= ~clear;
  77. write_giuint(res, offset);
  78. return res;
  79. }
  80. void vr41xx_enable_giuint(u8 pin)
  81. {
  82. if (pin < 16)
  83. set_giuint(GIUINTENL, (u16)1 << pin);
  84. else
  85. set_giuint(GIUINTENH, (u16)1 << (pin - 16));
  86. }
  87. void vr41xx_disable_giuint(u8 pin)
  88. {
  89. if (pin < 16)
  90. clear_giuint(GIUINTENL, (u16)1 << pin);
  91. else
  92. clear_giuint(GIUINTENH, (u16)1 << (pin - 16));
  93. }
  94. void vr41xx_clear_giuint(u8 pin)
  95. {
  96. if (pin < 16)
  97. write_giuint(GIUINTSTATL, (u16)1 << pin);
  98. else
  99. write_giuint(GIUINTSTATH, (u16)1 << (pin - 16));
  100. }
  101. void vr41xx_set_irq_trigger(u8 pin, u8 trigger, u8 hold)
  102. {
  103. u16 mask;
  104. if (pin < 16) {
  105. mask = (u16)1 << pin;
  106. if (trigger == TRIGGER_EDGE) {
  107.          set_giuint(GIUINTTYPL, mask);
  108. if (hold == SIGNAL_HOLD)
  109. set_giuint(GIUINTHTSELL, mask);
  110. else
  111. clear_giuint(GIUINTHTSELL, mask);
  112. } else {
  113. clear_giuint(GIUINTTYPL, mask);
  114. clear_giuint(GIUINTHTSELL, mask);
  115. }
  116. } else {
  117. mask = (u16)1 << (pin - 16);
  118. if (trigger == TRIGGER_EDGE) {
  119. set_giuint(GIUINTTYPH, mask);
  120. if (hold == SIGNAL_HOLD)
  121. set_giuint(GIUINTHTSELH, mask);
  122. else
  123. clear_giuint(GIUINTHTSELH, mask);
  124. } else {
  125. clear_giuint(GIUINTTYPH, mask);
  126. clear_giuint(GIUINTHTSELH, mask);
  127. }
  128. }
  129. vr41xx_clear_giuint(pin);
  130. }
  131. void vr41xx_set_irq_level(u8 pin, u8 level)
  132. {
  133. u16 mask;
  134. if (pin < 16) {
  135. mask = (u16)1 << pin;
  136. if (level == LEVEL_HIGH)
  137. set_giuint(GIUINTALSELL, mask);
  138. else
  139. clear_giuint(GIUINTALSELL, mask);
  140. } else {
  141. mask = (u16)1 << (pin - 16);
  142. if (level == LEVEL_HIGH)
  143. set_giuint(GIUINTALSELH, mask);
  144. else
  145. clear_giuint(GIUINTALSELH, mask);
  146. }
  147. vr41xx_clear_giuint(pin);
  148. }
  149. #define GIUINT_CASCADE_IRQ 16
  150. #define GIUINT_NR_IRQS 32
  151. enum {
  152. GIUINT_NO_CASCADE,
  153. GIUINT_CASCADE
  154. };
  155. struct vr41xx_giuint_cascade {
  156. unsigned int flag;
  157. int (*get_irq_number)(int irq);
  158. };
  159. static struct vr41xx_giuint_cascade giuint_cascade[GIUINT_NR_IRQS];
  160. static struct irqaction giu_cascade = {no_action, 0, 0, "cascade", NULL, NULL};
  161. static int no_irq_number(int irq)
  162. {
  163. return -EINVAL;
  164. }
  165. int vr41xx_cascade_irq(unsigned int irq, int (*get_irq_number)(int irq))
  166. {
  167. unsigned int pin;
  168. int retval;
  169. if (irq < GIU_IRQ(0) || irq > GIU_IRQ(31))
  170. return -EINVAL;
  171. if(!get_irq_number)
  172. return -EINVAL;
  173. pin = irq - GIU_IRQ(0);
  174. giuint_cascade[pin].flag = GIUINT_CASCADE;
  175. giuint_cascade[pin].get_irq_number = get_irq_number;
  176. retval = setup_irq(irq, &giu_cascade);
  177. if (retval) {
  178. giuint_cascade[pin].flag = GIUINT_NO_CASCADE;
  179. giuint_cascade[pin].get_irq_number = no_irq_number;
  180. }
  181. return retval;
  182. }
  183. extern unsigned int do_IRQ(int irq, struct pt_regs *regs);
  184. unsigned int giuint_do_IRQ(int pin, struct pt_regs *regs)
  185. {
  186. struct vr41xx_giuint_cascade *cascade;
  187. unsigned int retval = 0;
  188. int giuint_irq, cascade_irq;
  189. disable_irq(GIUINT_CASCADE_IRQ);
  190. cascade = &giuint_cascade[pin];
  191. giuint_irq = pin + GIU_IRQ(0);
  192. if (cascade->flag == GIUINT_CASCADE) {
  193. cascade_irq = cascade->get_irq_number(giuint_irq);
  194. disable_irq(giuint_irq);
  195. if (cascade_irq > 0)
  196. retval = do_IRQ(cascade_irq, regs);
  197. enable_irq(giuint_irq);
  198. } else
  199. retval = do_IRQ(giuint_irq, regs);
  200. enable_irq(GIUINT_CASCADE_IRQ);
  201. return retval;
  202. }
  203. void (*board_irq_init)(void) = NULL;
  204. void __init vr41xx_giuint_init(void)
  205. {
  206. int i;
  207. switch (mips_cpu.cputype) {
  208. case CPU_VR4111:
  209. case CPU_VR4121:
  210. vr41xx_giu_base = VR4111_GIUIOSELL;
  211. break;
  212. case CPU_VR4122:
  213. case CPU_VR4131:
  214. vr41xx_giu_base = VR4122_GIUIOSELL;
  215. break;
  216. default:
  217. panic("GIU: Unexpected CPU of NEC VR4100 series");
  218. break;
  219. }
  220. for (i = 0; i < GIUINT_NR_IRQS; i++) {
  221.                 vr41xx_disable_giuint(i);
  222. giuint_cascade[i].flag = GIUINT_NO_CASCADE;
  223. giuint_cascade[i].get_irq_number = no_irq_number;
  224. }
  225. if (setup_irq(GIUINT_CASCADE_IRQ, &giu_cascade))
  226. printk("GIUINT: Can not cascade IRQ %d.n", GIUINT_CASCADE_IRQ);
  227. if (board_irq_init)
  228. board_irq_init();
  229. }