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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * drivers/pcmcia/sa1100_h3600.c
  3.  *
  4.  * PCMCIA implementation routines for H3600
  5.  *
  6.  */
  7. #include <linux/kernel.h>
  8. #include <linux/sched.h>
  9. #include <asm/hardware.h>
  10. #include <asm/irq.h>
  11. #include "sa1100_generic.h"
  12. static struct irqs {
  13. int irq;
  14. const char *str;
  15. } irqs[] = {
  16. { IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" },
  17. { IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" }
  18. };
  19. static int h3600_pcmcia_init(struct pcmcia_init *init)
  20. {
  21. int i, res;
  22. /*
  23.  * Set transition detect
  24.  */
  25. set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_IRQ0 | GPIO_H3600_PCMCIA_IRQ1,
  26.   GPIO_FALLING_EDGE);
  27. /*
  28.  * Register interrupts
  29.  */
  30. for (i = res = 0; i < ARRAY_SIZE(irqs); i++) {
  31. res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
  32.   irqs[i].str, NULL);
  33. if (res)
  34. break;
  35. }
  36. if (res) {
  37. printk(KERN_ERR "h3600_pcmcia: request for IRQ%d failed: %dn",
  38.        irqs[i].irq, res);
  39. while (i--)
  40. free_irq(irqs[i].irq, NULL);
  41. }
  42. return res ? -1 : 2;
  43. }
  44. static int h3600_pcmcia_shutdown(void)
  45. {
  46. int i;
  47. /*
  48.  * disable IRQs
  49.  */
  50. for (i = 0; i < ARRAY_SIZE(irqs); i++)
  51. free_irq(irqs[i].irq, NULL);
  52.   
  53. /* Disable CF bus: */
  54. clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
  55. clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
  56. set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
  57. return 0;
  58. }
  59. static int
  60. h3600_pcmcia_socket_state(struct pcmcia_state_array *state)
  61. {
  62. unsigned long levels;
  63. if (state->size < 2)
  64. return -1;
  65. levels = GPLR;
  66. state->state[0].detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1;
  67. state->state[0].ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0;
  68. state->state[0].bvd1 = 0;
  69. state->state[0].bvd2 = 0;
  70. state->state[0].wrprot = 0; /* Not available on H3600. */
  71. state->state[0].vs_3v = 0;
  72. state->state[0].vs_Xv = 0;
  73. state->state[1].detect = levels & GPIO_H3600_PCMCIA_CD1 ? 0 : 1;
  74. state->state[1].ready = levels & GPIO_H3600_PCMCIA_IRQ1 ? 1 : 0;
  75. state->state[1].bvd1 = 0;
  76. state->state[1].bvd2 = 0;
  77. state->state[1].wrprot = 0; /* Not available on H3600. */
  78. state->state[1].vs_3v = 0;
  79. state->state[1].vs_Xv = 0;
  80. return 1;
  81. }
  82. static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
  83. {
  84. switch (info->sock) {
  85. case 0:
  86. info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ0;
  87. break;
  88. case 1:
  89. info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ1;
  90. break;
  91. default:
  92. return -1;
  93. }
  94. return 0;
  95. }
  96. static int
  97. h3600_pcmcia_configure_socket(const struct pcmcia_configure *conf)
  98. {
  99. if (conf->sock > 1)
  100. return -1;
  101. if (conf->vcc != 0 && conf->vcc != 33 && conf->vcc != 50) {
  102. printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uVn",
  103.        conf->vcc / 10, conf->vcc % 10);
  104. return -1;
  105. }
  106. if (conf->reset)
  107. set_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
  108. else
  109. clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
  110. /* Silently ignore Vpp, output enable, speaker enable. */
  111. return 0;
  112. }
  113. static int h3600_pcmcia_socket_init(int sock)
  114. {
  115. /* Enable CF bus: */
  116. set_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
  117. set_h3600_egpio(IPAQ_EGPIO_OPT_ON);
  118. clr_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
  119. set_current_state(TASK_UNINTERRUPTIBLE);
  120. schedule_timeout(10*HZ / 1000);
  121. switch (sock) {
  122. case 0:
  123. set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD0, GPIO_BOTH_EDGES);
  124. break;
  125. case 1:
  126. set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD1, GPIO_BOTH_EDGES);
  127. break;
  128. }
  129. return 0;
  130. }
  131. static int h3600_pcmcia_socket_suspend(int sock)
  132. {
  133. switch (sock) {
  134. case 0:
  135. set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD0, GPIO_NO_EDGES);
  136. break;
  137. case 1:
  138. set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD1, GPIO_NO_EDGES);
  139. break;
  140. }
  141. /*
  142.  * FIXME:  This doesn't fit well.  We don't have the mechanism in
  143.  * the generic PCMCIA layer to deal with the idea of two sockets
  144.  * on one bus.  We rely on the cs.c behaviour shutting down
  145.  * socket 0 then socket 1.
  146.  */
  147. if (sock == 1) {
  148. clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
  149. clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
  150. /* hmm, does this suck power? */
  151. set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
  152. }
  153. return 0;
  154. }
  155. struct pcmcia_low_level h3600_pcmcia_ops = { 
  156. init: h3600_pcmcia_init,
  157. shutdown: h3600_pcmcia_shutdown,
  158. socket_state: h3600_pcmcia_socket_state,
  159. get_irq_info: h3600_pcmcia_get_irq_info,
  160. configure_socket: h3600_pcmcia_configure_socket,
  161. socket_init: h3600_pcmcia_socket_init,
  162. socket_suspend: h3600_pcmcia_socket_suspend,
  163. };