0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/gpio.h>
0014 #include <linux/delay.h>
0015
0016 #include <asm/mach-types.h>
0017 #include "palmtc.h"
0018 #include <pcmcia/soc_common.h>
0019
0020 static struct gpio palmtc_pcmcia_gpios[] = {
0021 { GPIO_NR_PALMTC_PCMCIA_POWER1, GPIOF_INIT_LOW, "PCMCIA Power 1" },
0022 { GPIO_NR_PALMTC_PCMCIA_POWER2, GPIOF_INIT_LOW, "PCMCIA Power 2" },
0023 { GPIO_NR_PALMTC_PCMCIA_POWER3, GPIOF_INIT_LOW, "PCMCIA Power 3" },
0024 { GPIO_NR_PALMTC_PCMCIA_RESET, GPIOF_INIT_HIGH,"PCMCIA Reset" },
0025 { GPIO_NR_PALMTC_PCMCIA_PWRREADY, GPIOF_IN, "PCMCIA Power Ready" },
0026 };
0027
0028 static int palmtc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
0029 {
0030 int ret;
0031
0032 ret = gpio_request_array(palmtc_pcmcia_gpios,
0033 ARRAY_SIZE(palmtc_pcmcia_gpios));
0034
0035 skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMTC_PCMCIA_READY;
0036 skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
0037
0038 return ret;
0039 }
0040
0041 static void palmtc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
0042 {
0043 gpio_free_array(palmtc_pcmcia_gpios, ARRAY_SIZE(palmtc_pcmcia_gpios));
0044 }
0045
0046 static void palmtc_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
0047 struct pcmcia_state *state)
0048 {
0049 state->detect = 1;
0050 state->vs_3v = 1;
0051 state->vs_Xv = 0;
0052 }
0053
0054 static int palmtc_wifi_powerdown(void)
0055 {
0056 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
0057 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 0);
0058 mdelay(40);
0059 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 0);
0060 return 0;
0061 }
0062
0063 static int palmtc_wifi_powerup(void)
0064 {
0065 int timeout = 50;
0066
0067 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 1);
0068 mdelay(50);
0069
0070
0071 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 1);
0072 mdelay(100);
0073 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 1);
0074
0075
0076 while (!gpio_get_value(GPIO_NR_PALMTC_PCMCIA_PWRREADY) &&
0077 timeout) {
0078 mdelay(1);
0079 timeout--;
0080 }
0081
0082
0083 if (!timeout) {
0084 palmtc_wifi_powerdown();
0085 return 1;
0086 }
0087
0088
0089 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
0090 mdelay(20);
0091 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 0);
0092 mdelay(25);
0093
0094 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 0);
0095
0096 return 0;
0097 }
0098
0099 static int palmtc_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
0100 const socket_state_t *state)
0101 {
0102 int ret = 1;
0103
0104 if (state->Vcc == 0)
0105 ret = palmtc_wifi_powerdown();
0106 else if (state->Vcc == 33)
0107 ret = palmtc_wifi_powerup();
0108
0109 return ret;
0110 }
0111
0112 static struct pcmcia_low_level palmtc_pcmcia_ops = {
0113 .owner = THIS_MODULE,
0114
0115 .first = 0,
0116 .nr = 1,
0117
0118 .hw_init = palmtc_pcmcia_hw_init,
0119 .hw_shutdown = palmtc_pcmcia_hw_shutdown,
0120
0121 .socket_state = palmtc_pcmcia_socket_state,
0122 .configure_socket = palmtc_pcmcia_configure_socket,
0123 };
0124
0125 static struct platform_device *palmtc_pcmcia_device;
0126
0127 static int __init palmtc_pcmcia_init(void)
0128 {
0129 int ret;
0130
0131 if (!machine_is_palmtc())
0132 return -ENODEV;
0133
0134 palmtc_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
0135 if (!palmtc_pcmcia_device)
0136 return -ENOMEM;
0137
0138 ret = platform_device_add_data(palmtc_pcmcia_device, &palmtc_pcmcia_ops,
0139 sizeof(palmtc_pcmcia_ops));
0140
0141 if (!ret)
0142 ret = platform_device_add(palmtc_pcmcia_device);
0143
0144 if (ret)
0145 platform_device_put(palmtc_pcmcia_device);
0146
0147 return ret;
0148 }
0149
0150 static void __exit palmtc_pcmcia_exit(void)
0151 {
0152 platform_device_unregister(palmtc_pcmcia_device);
0153 }
0154
0155 module_init(palmtc_pcmcia_init);
0156 module_exit(palmtc_pcmcia_exit);
0157
0158 MODULE_AUTHOR("Alex Osborne <ato@meshy.org>,"
0159 " Marek Vasut <marek.vasut@gmail.com>");
0160 MODULE_DESCRIPTION("PCMCIA support for Palm Tungsten|C");
0161 MODULE_ALIAS("platform:pxa2xx-pcmcia");
0162 MODULE_LICENSE("GPL");