Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6
[linux/fpc-iii.git] / drivers / pcmcia / pxa2xx_palmtc.c
blob3a8993ed562120f7da811620c770d98f23430831
1 /*
2 * linux/drivers/pcmcia/pxa2xx_palmtc.c
4 * Driver for Palm Tungsten|C PCMCIA
6 * Copyright (C) 2008 Alex Osborne <ato@meshy.org>
7 * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
15 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/gpio.h>
18 #include <linux/delay.h>
20 #include <asm/mach-types.h>
21 #include <mach/palmtc.h>
22 #include "soc_common.h"
24 static int palmtc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
26 int ret;
28 ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_POWER1, "PCMCIA PWR1");
29 if (ret)
30 goto err1;
31 ret = gpio_direction_output(GPIO_NR_PALMTC_PCMCIA_POWER1, 0);
32 if (ret)
33 goto err2;
35 ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_POWER2, "PCMCIA PWR2");
36 if (ret)
37 goto err2;
38 ret = gpio_direction_output(GPIO_NR_PALMTC_PCMCIA_POWER2, 0);
39 if (ret)
40 goto err3;
42 ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_POWER3, "PCMCIA PWR3");
43 if (ret)
44 goto err3;
45 ret = gpio_direction_output(GPIO_NR_PALMTC_PCMCIA_POWER3, 0);
46 if (ret)
47 goto err4;
49 ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_RESET, "PCMCIA RST");
50 if (ret)
51 goto err4;
52 ret = gpio_direction_output(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
53 if (ret)
54 goto err5;
56 ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_READY, "PCMCIA RDY");
57 if (ret)
58 goto err5;
59 ret = gpio_direction_input(GPIO_NR_PALMTC_PCMCIA_READY);
60 if (ret)
61 goto err6;
63 ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_PWRREADY, "PCMCIA PWRRDY");
64 if (ret)
65 goto err6;
66 ret = gpio_direction_input(GPIO_NR_PALMTC_PCMCIA_PWRREADY);
67 if (ret)
68 goto err7;
70 skt->irq = IRQ_GPIO(GPIO_NR_PALMTC_PCMCIA_READY);
71 return 0;
73 err7:
74 gpio_free(GPIO_NR_PALMTC_PCMCIA_PWRREADY);
75 err6:
76 gpio_free(GPIO_NR_PALMTC_PCMCIA_READY);
77 err5:
78 gpio_free(GPIO_NR_PALMTC_PCMCIA_RESET);
79 err4:
80 gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER3);
81 err3:
82 gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER2);
83 err2:
84 gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER1);
85 err1:
86 return ret;
89 static void palmtc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
91 gpio_free(GPIO_NR_PALMTC_PCMCIA_PWRREADY);
92 gpio_free(GPIO_NR_PALMTC_PCMCIA_READY);
93 gpio_free(GPIO_NR_PALMTC_PCMCIA_RESET);
94 gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER3);
95 gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER2);
96 gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER1);
99 static void palmtc_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
100 struct pcmcia_state *state)
102 state->detect = 1; /* always inserted */
103 state->ready = !!gpio_get_value(GPIO_NR_PALMTC_PCMCIA_READY);
104 state->bvd1 = 1;
105 state->bvd2 = 1;
106 state->wrprot = 0;
107 state->vs_3v = 1;
108 state->vs_Xv = 0;
111 static int palmtc_wifi_powerdown(void)
113 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
114 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 0);
115 mdelay(40);
116 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 0);
117 return 0;
120 static int palmtc_wifi_powerup(void)
122 int timeout = 50;
124 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 1);
125 mdelay(50);
127 /* Power up the card, 1.8V first, after a while 3.3V */
128 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 1);
129 mdelay(100);
130 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 1);
132 /* Wait till the card is ready */
133 while (!gpio_get_value(GPIO_NR_PALMTC_PCMCIA_PWRREADY) &&
134 timeout) {
135 mdelay(1);
136 timeout--;
139 /* Power down the WiFi in case of error */
140 if (!timeout) {
141 palmtc_wifi_powerdown();
142 return 1;
145 /* Reset the card */
146 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
147 mdelay(20);
148 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 0);
149 mdelay(25);
151 gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 0);
153 return 0;
156 static int palmtc_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
157 const socket_state_t *state)
159 int ret = 1;
161 if (state->Vcc == 0)
162 ret = palmtc_wifi_powerdown();
163 else if (state->Vcc == 33)
164 ret = palmtc_wifi_powerup();
166 return ret;
169 static void palmtc_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
173 static void palmtc_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
177 static struct pcmcia_low_level palmtc_pcmcia_ops = {
178 .owner = THIS_MODULE,
180 .first = 0,
181 .nr = 1,
183 .hw_init = palmtc_pcmcia_hw_init,
184 .hw_shutdown = palmtc_pcmcia_hw_shutdown,
186 .socket_state = palmtc_pcmcia_socket_state,
187 .configure_socket = palmtc_pcmcia_configure_socket,
189 .socket_init = palmtc_pcmcia_socket_init,
190 .socket_suspend = palmtc_pcmcia_socket_suspend,
193 static struct platform_device *palmtc_pcmcia_device;
195 static int __init palmtc_pcmcia_init(void)
197 int ret;
199 if (!machine_is_palmtc())
200 return -ENODEV;
202 palmtc_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
203 if (!palmtc_pcmcia_device)
204 return -ENOMEM;
206 ret = platform_device_add_data(palmtc_pcmcia_device, &palmtc_pcmcia_ops,
207 sizeof(palmtc_pcmcia_ops));
209 if (!ret)
210 ret = platform_device_add(palmtc_pcmcia_device);
212 if (ret)
213 platform_device_put(palmtc_pcmcia_device);
215 return ret;
218 static void __exit palmtc_pcmcia_exit(void)
220 platform_device_unregister(palmtc_pcmcia_device);
223 module_init(palmtc_pcmcia_init);
224 module_exit(palmtc_pcmcia_exit);
226 MODULE_AUTHOR("Alex Osborne <ato@meshy.org>,"
227 " Marek Vasut <marek.vasut@gmail.com>");
228 MODULE_DESCRIPTION("PCMCIA support for Palm Tungsten|C");
229 MODULE_ALIAS("platform:pxa2xx-pcmcia");
230 MODULE_LICENSE("GPL");