pxa2xx_palmtc.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * linux/drivers/pcmcia/pxa2xx_palmtc.c
  4. *
  5. * Driver for Palm Tungsten|C PCMCIA
  6. *
  7. * Copyright (C) 2008 Alex Osborne <ato@meshy.org>
  8. * Copyright (C) 2009-2011 Marek Vasut <marek.vasut@gmail.com>
  9. */
  10. #include <linux/module.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/gpio.h>
  13. #include <linux/delay.h>
  14. #include <asm/mach-types.h>
  15. #include <mach/palmtc.h>
  16. #include "soc_common.h"
  17. static struct gpio palmtc_pcmcia_gpios[] = {
  18. { GPIO_NR_PALMTC_PCMCIA_POWER1, GPIOF_INIT_LOW, "PCMCIA Power 1" },
  19. { GPIO_NR_PALMTC_PCMCIA_POWER2, GPIOF_INIT_LOW, "PCMCIA Power 2" },
  20. { GPIO_NR_PALMTC_PCMCIA_POWER3, GPIOF_INIT_LOW, "PCMCIA Power 3" },
  21. { GPIO_NR_PALMTC_PCMCIA_RESET, GPIOF_INIT_HIGH,"PCMCIA Reset" },
  22. { GPIO_NR_PALMTC_PCMCIA_PWRREADY, GPIOF_IN, "PCMCIA Power Ready" },
  23. };
  24. static int palmtc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
  25. {
  26. int ret;
  27. ret = gpio_request_array(palmtc_pcmcia_gpios,
  28. ARRAY_SIZE(palmtc_pcmcia_gpios));
  29. skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMTC_PCMCIA_READY;
  30. skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
  31. return ret;
  32. }
  33. static void palmtc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
  34. {
  35. gpio_free_array(palmtc_pcmcia_gpios, ARRAY_SIZE(palmtc_pcmcia_gpios));
  36. }
  37. static void palmtc_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
  38. struct pcmcia_state *state)
  39. {
  40. state->detect = 1; /* always inserted */
  41. state->vs_3v = 1;
  42. state->vs_Xv = 0;
  43. }
  44. static int palmtc_wifi_powerdown(void)
  45. {
  46. gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
  47. gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 0);
  48. mdelay(40);
  49. gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 0);
  50. return 0;
  51. }
  52. static int palmtc_wifi_powerup(void)
  53. {
  54. int timeout = 50;
  55. gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 1);
  56. mdelay(50);
  57. /* Power up the card, 1.8V first, after a while 3.3V */
  58. gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 1);
  59. mdelay(100);
  60. gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 1);
  61. /* Wait till the card is ready */
  62. while (!gpio_get_value(GPIO_NR_PALMTC_PCMCIA_PWRREADY) &&
  63. timeout) {
  64. mdelay(1);
  65. timeout--;
  66. }
  67. /* Power down the WiFi in case of error */
  68. if (!timeout) {
  69. palmtc_wifi_powerdown();
  70. return 1;
  71. }
  72. /* Reset the card */
  73. gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
  74. mdelay(20);
  75. gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 0);
  76. mdelay(25);
  77. gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 0);
  78. return 0;
  79. }
  80. static int palmtc_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
  81. const socket_state_t *state)
  82. {
  83. int ret = 1;
  84. if (state->Vcc == 0)
  85. ret = palmtc_wifi_powerdown();
  86. else if (state->Vcc == 33)
  87. ret = palmtc_wifi_powerup();
  88. return ret;
  89. }
  90. static struct pcmcia_low_level palmtc_pcmcia_ops = {
  91. .owner = THIS_MODULE,
  92. .first = 0,
  93. .nr = 1,
  94. .hw_init = palmtc_pcmcia_hw_init,
  95. .hw_shutdown = palmtc_pcmcia_hw_shutdown,
  96. .socket_state = palmtc_pcmcia_socket_state,
  97. .configure_socket = palmtc_pcmcia_configure_socket,
  98. };
  99. static struct platform_device *palmtc_pcmcia_device;
  100. static int __init palmtc_pcmcia_init(void)
  101. {
  102. int ret;
  103. if (!machine_is_palmtc())
  104. return -ENODEV;
  105. palmtc_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
  106. if (!palmtc_pcmcia_device)
  107. return -ENOMEM;
  108. ret = platform_device_add_data(palmtc_pcmcia_device, &palmtc_pcmcia_ops,
  109. sizeof(palmtc_pcmcia_ops));
  110. if (!ret)
  111. ret = platform_device_add(palmtc_pcmcia_device);
  112. if (ret)
  113. platform_device_put(palmtc_pcmcia_device);
  114. return ret;
  115. }
  116. static void __exit palmtc_pcmcia_exit(void)
  117. {
  118. platform_device_unregister(palmtc_pcmcia_device);
  119. }
  120. module_init(palmtc_pcmcia_init);
  121. module_exit(palmtc_pcmcia_exit);
  122. MODULE_AUTHOR("Alex Osborne <ato@meshy.org>,"
  123. " Marek Vasut <marek.vasut@gmail.com>");
  124. MODULE_DESCRIPTION("PCMCIA support for Palm Tungsten|C");
  125. MODULE_ALIAS("platform:pxa2xx-pcmcia");
  126. MODULE_LICENSE("GPL");