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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * linux/arch/sh/kernel/setup_ec3104.c
  3.  *  EC3104 companion chip support
  4.  *
  5.  * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
  6.  *
  7.  */
  8. /* EC3104 note:
  9.  * This code was written without any documentation about the EC3104 chip.  While
  10.  * I hope I got most of the basic functionality right, the register names I use
  11.  * are most likely completely different from those in the chip documentation.
  12.  *
  13.  * If you have any further information about the EC3104, please tell me
  14.  * (prumpf@tux.org).
  15.  */
  16. #include <linux/sched.h>
  17. #include <linux/kernel.h>
  18. #include <linux/param.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/init.h>
  21. #include <linux/irq.h>
  22. #include <linux/types.h>
  23. #include <asm/io.h>
  24. #include <asm/irq.h>
  25. #include <asm/ec3104.h>
  26. /* This is for debugging mostly;  here's the table that I intend to keep
  27.  * in here:
  28.  *
  29.  *   index function base addr power interrupt bit   
  30.  *  0 power b0ec0000 --- 00000001 (unused)
  31.  *  1 irqs b0ec1000 --- 00000002 (unused)
  32.  *  2 ?? b0ec2000 b0ec0008 00000004
  33.  *  3 PS2 (1) b0ec3000 b0ec000c 00000008
  34.  *  4 PS2 (2) b0ec4000 b0ec0010 00000010
  35.  *  5 ?? b0ec5000 b0ec0014 00000020
  36.  *  6 I2C b0ec6000 b0ec0018 00000040
  37.  *  7 serial (1) b0ec7000 b0ec001c 00000080
  38.  *  8 serial (2) b0ec8000 b0ec0020 00000100
  39.  *  9 serial (3) b0ec9000 b0ec0024 00000200
  40.  * 10 serial (4) b0eca000 b0ec0028 00000400
  41.  * 12 GPIO (1) b0ecc000 b0ec0030
  42.  * 13      GPIO (2) b0ecc000 b0ec0030
  43.  * 16 pcmcia (1) b0ed0000 b0ec0040 00010000
  44.  * 17 pcmcia (2) b0ed1000 b0ec0044 00020000
  45.  */
  46. /* I used the register names from another interrupt controller I worked with,
  47.  * since it seems to be identical to the ec3104 except that all bits are
  48.  * inverted:
  49.  *
  50.  * IRR: Interrupt Request Register (pending and enabled interrupts)
  51.  * IMR: Interrupt Mask Register (which interrupts are enabled)
  52.  * IPR: Interrupt Pending Register (pending interrupts, even disabled ones)
  53.  *
  54.  * 0 bits mean pending or enabled, 1 bits mean not pending or disabled.  all
  55.  * IRQs seem to be level-triggered.
  56.  */
  57. #define EC3104_IRR (EC3104_BASE + 0x1000)
  58. #define EC3104_IMR (EC3104_BASE + 0x1004)
  59. #define EC3104_IPR (EC3104_BASE + 0x1008)
  60. #define ctrl_readl(addr) (*(volatile u32 *)(addr))
  61. #define ctrl_writel(data,addr) (*(volatile u32 *)(addr) = (data))
  62. #define ctrl_readb(addr) (*(volatile u8 *)(addr))
  63. static char *ec3104_name(unsigned index)
  64. {
  65. switch(index) {
  66. case 0:
  67. return "power management";
  68. case 1:
  69. return "interrupts";
  70. case 3:
  71. return "PS2 (1)";
  72. case 4:
  73. return "PS2 (2)";
  74. case 5:
  75. return "I2C (1)";
  76. case 6:
  77. return "I2C (2)";
  78. case 7:
  79. return "serial (1)";
  80. case 8:
  81. return "serial (2)";
  82. case 9:
  83. return "serial (3)";
  84. case 10:
  85. return "serial (4)";
  86. case 16:
  87. return "pcmcia (1)";
  88. case 17:
  89. return "pcmcia (2)";
  90. default: {
  91. static char buf[32];
  92. sprintf(buf, "unknown (%d)", index);
  93. return buf;
  94. }
  95. }
  96. }
  97. int get_pending_interrupts(char *buf)
  98. {
  99. u32 ipr;
  100. u32 bit;
  101. char *p = buf;
  102.         p += sprintf(p, "pending: (");
  103. ipr = ctrl_inl(EC3104_IPR);
  104. for (bit = 1; bit < 32; bit++)
  105. if (!(ipr & (1<<bit)))
  106. p += sprintf(p, "%s ", ec3104_name(bit));
  107. p += sprintf(p, ")n");
  108. return p - buf;
  109. }
  110. static inline u32 ec3104_irq2mask(unsigned int irq)
  111. {
  112. return (1 << (irq - EC3104_IRQBASE));
  113. }
  114. static inline void mask_ec3104_irq(unsigned int irq)
  115. {
  116. u32 mask;
  117. mask = ctrl_readl(EC3104_IMR);
  118. mask |= ec3104_irq2mask(irq);
  119. ctrl_writel(mask, EC3104_IMR);
  120. }
  121. static inline void unmask_ec3104_irq(unsigned int irq)
  122. {
  123. u32 mask;
  124. mask = ctrl_readl(EC3104_IMR);
  125. mask &= ~ec3104_irq2mask(irq);
  126. ctrl_writel(mask, EC3104_IMR);
  127. }
  128. static void disable_ec3104_irq(unsigned int irq)
  129. {
  130. mask_ec3104_irq(irq);
  131. }
  132. static void enable_ec3104_irq(unsigned int irq)
  133. {
  134. unmask_ec3104_irq(irq);
  135. }
  136. static void mask_and_ack_ec3104_irq(unsigned int irq)
  137. {
  138. mask_ec3104_irq(irq);
  139. }
  140. static void end_ec3104_irq(unsigned int irq)
  141. {
  142. if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  143. unmask_ec3104_irq(irq);
  144. }
  145. static unsigned int startup_ec3104_irq(unsigned int irq)
  146. {
  147. unmask_ec3104_irq(irq);
  148. return 0;
  149. }
  150. static void shutdown_ec3104_irq(unsigned int irq)
  151. {
  152. mask_ec3104_irq(irq);
  153. }
  154. static struct hw_interrupt_type ec3104_int = {
  155. typename: "EC3104",
  156. enable: enable_ec3104_irq,
  157. disable: disable_ec3104_irq,
  158. ack: mask_and_ack_ec3104_irq,
  159. end: end_ec3104_irq,
  160. startup: startup_ec3104_irq,
  161. shutdown: shutdown_ec3104_irq,
  162. };
  163. /* Yuck.  the _demux API is ugly */
  164. int ec3104_irq_demux(int irq)
  165. {
  166. if (irq == EC3104_IRQ) {
  167. unsigned int mask;
  168. mask = ctrl_readl(EC3104_IRR);
  169. if (mask == 0xffffffff)
  170. return EC3104_IRQ;
  171. else
  172. return EC3104_IRQBASE + ffz(mask);
  173. }
  174. return irq;
  175. }
  176. int __init setup_ec3104(void)
  177. {
  178. char str[8];
  179. int i;
  180. if (!MACH_EC3104)
  181. printk("!MACH_EC3104n");
  182. if (0)
  183. return 0;
  184. for (i=0; i<8; i++)
  185. str[i] = ctrl_readb(EC3104_BASE + i);
  186. for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
  187. irq_desc[i].handler = &ec3104_int;
  188. printk("initializing EC3104 "%.8s" at %08x, IRQ %d, IRQ base %dn",
  189.        str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
  190. /* mask all interrupts.  this should have been done by the boot
  191.  * loader for us but we want to be sure ... */
  192. ctrl_writel(0xffffffff, EC3104_IMR);
  193. return 0;
  194. }
  195. module_init(setup_ec3104);