pxa2xx_trizeps4.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * linux/drivers/pcmcia/pxa2xx_trizeps4.c
  4. *
  5. * TRIZEPS PCMCIA specific routines.
  6. *
  7. * Author: Jürgen Schindele
  8. * Created: 20 02, 2006
  9. * Copyright: Jürgen Schindele
  10. */
  11. #include <linux/module.h>
  12. #include <linux/init.h>
  13. #include <linux/kernel.h>
  14. #include <linux/gpio.h>
  15. #include <linux/interrupt.h>
  16. #include <linux/platform_device.h>
  17. #include <asm/mach-types.h>
  18. #include <asm/irq.h>
  19. #include <mach/pxa2xx-regs.h>
  20. #include <mach/trizeps4.h>
  21. #include "soc_common.h"
  22. extern void board_pcmcia_power(int power);
  23. static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
  24. {
  25. /* we dont have voltage/card/ready detection
  26. * so we dont need interrupts for it
  27. */
  28. switch (skt->nr) {
  29. case 0:
  30. skt->stat[SOC_STAT_CD].gpio = GPIO_PCD;
  31. skt->stat[SOC_STAT_CD].name = "cs0_cd";
  32. skt->stat[SOC_STAT_RDY].gpio = GPIO_PRDY;
  33. skt->stat[SOC_STAT_RDY].name = "cs0_rdy";
  34. break;
  35. default:
  36. break;
  37. }
  38. /* release the reset of this card */
  39. pr_debug("%s: sock %d irq %d\n", __func__, skt->nr, skt->socket.pci_irq);
  40. return 0;
  41. }
  42. static unsigned long trizeps_pcmcia_status[2];
  43. static void trizeps_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
  44. struct pcmcia_state *state)
  45. {
  46. unsigned short status = 0, change;
  47. status = CFSR_readw();
  48. change = (status ^ trizeps_pcmcia_status[skt->nr]) &
  49. ConXS_CFSR_BVD_MASK;
  50. if (change) {
  51. trizeps_pcmcia_status[skt->nr] = status;
  52. if (status & ConXS_CFSR_BVD1) {
  53. /* enable_irq empty */
  54. } else {
  55. /* disable_irq empty */
  56. }
  57. }
  58. switch (skt->nr) {
  59. case 0:
  60. /* just fill in fix states */
  61. state->bvd1 = (status & ConXS_CFSR_BVD1) ? 1 : 0;
  62. state->bvd2 = (status & ConXS_CFSR_BVD2) ? 1 : 0;
  63. state->vs_3v = (status & ConXS_CFSR_VS1) ? 0 : 1;
  64. state->vs_Xv = (status & ConXS_CFSR_VS2) ? 0 : 1;
  65. break;
  66. #ifndef CONFIG_MACH_TRIZEPS_CONXS
  67. /* on ConXS we only have one slot. Second is inactive */
  68. case 1:
  69. state->detect = 0;
  70. state->ready = 0;
  71. state->bvd1 = 0;
  72. state->bvd2 = 0;
  73. state->vs_3v = 0;
  74. state->vs_Xv = 0;
  75. break;
  76. #endif
  77. }
  78. }
  79. static int trizeps_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
  80. const socket_state_t *state)
  81. {
  82. int ret = 0;
  83. unsigned short power = 0;
  84. /* we do nothing here just check a bit */
  85. switch (state->Vcc) {
  86. case 0: power &= 0xfc; break;
  87. case 33: power |= ConXS_BCR_S0_VCC_3V3; break;
  88. case 50:
  89. pr_err("%s(): Vcc 5V not supported in socket\n", __func__);
  90. break;
  91. default:
  92. pr_err("%s(): bad Vcc %u\n", __func__, state->Vcc);
  93. ret = -1;
  94. }
  95. switch (state->Vpp) {
  96. case 0: power &= 0xf3; break;
  97. case 33: power |= ConXS_BCR_S0_VPP_3V3; break;
  98. case 120:
  99. pr_err("%s(): Vpp 12V not supported in socket\n", __func__);
  100. break;
  101. default:
  102. if (state->Vpp != state->Vcc) {
  103. pr_err("%s(): bad Vpp %u\n", __func__, state->Vpp);
  104. ret = -1;
  105. }
  106. }
  107. switch (skt->nr) {
  108. case 0: /* we only have 3.3V */
  109. board_pcmcia_power(power);
  110. break;
  111. #ifndef CONFIG_MACH_TRIZEPS_CONXS
  112. /* on ConXS we only have one slot. Second is inactive */
  113. case 1:
  114. #endif
  115. default:
  116. break;
  117. }
  118. return ret;
  119. }
  120. static void trizeps_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
  121. {
  122. /* default is on */
  123. board_pcmcia_power(0x9);
  124. }
  125. static void trizeps_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
  126. {
  127. board_pcmcia_power(0x0);
  128. }
  129. static struct pcmcia_low_level trizeps_pcmcia_ops = {
  130. .owner = THIS_MODULE,
  131. .hw_init = trizeps_pcmcia_hw_init,
  132. .socket_state = trizeps_pcmcia_socket_state,
  133. .configure_socket = trizeps_pcmcia_configure_socket,
  134. .socket_init = trizeps_pcmcia_socket_init,
  135. .socket_suspend = trizeps_pcmcia_socket_suspend,
  136. #ifdef CONFIG_MACH_TRIZEPS_CONXS
  137. .nr = 1,
  138. #else
  139. .nr = 2,
  140. #endif
  141. .first = 0,
  142. };
  143. static struct platform_device *trizeps_pcmcia_device;
  144. static int __init trizeps_pcmcia_init(void)
  145. {
  146. int ret;
  147. if (!machine_is_trizeps4() && !machine_is_trizeps4wl())
  148. return -ENODEV;
  149. trizeps_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
  150. if (!trizeps_pcmcia_device)
  151. return -ENOMEM;
  152. ret = platform_device_add_data(trizeps_pcmcia_device,
  153. &trizeps_pcmcia_ops, sizeof(trizeps_pcmcia_ops));
  154. if (ret == 0)
  155. ret = platform_device_add(trizeps_pcmcia_device);
  156. if (ret)
  157. platform_device_put(trizeps_pcmcia_device);
  158. return ret;
  159. }
  160. static void __exit trizeps_pcmcia_exit(void)
  161. {
  162. platform_device_unregister(trizeps_pcmcia_device);
  163. }
  164. fs_initcall(trizeps_pcmcia_init);
  165. module_exit(trizeps_pcmcia_exit);
  166. MODULE_LICENSE("GPL");
  167. MODULE_AUTHOR("Juergen Schindele");
  168. MODULE_ALIAS("platform:pxa2xx-pcmcia");