Root/
1 | /* |
2 | * linux/drivers/pcmcia/pxa2xx_palmtc.c |
3 | * |
4 | * Driver for Palm Tungsten|C PCMCIA |
5 | * |
6 | * Copyright (C) 2008 Alex Osborne <ato@meshy.org> |
7 | * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com> |
8 | * |
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. |
12 | * |
13 | */ |
14 | |
15 | #include <linux/module.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/gpio.h> |
18 | #include <linux/delay.h> |
19 | |
20 | #include <asm/mach-types.h> |
21 | #include <mach/palmtc.h> |
22 | #include "soc_common.h" |
23 | |
24 | static int palmtc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) |
25 | { |
26 | int ret; |
27 | |
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; |
34 | |
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; |
41 | |
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; |
48 | |
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; |
55 | |
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; |
62 | |
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; |
69 | |
70 | skt->socket.pci_irq = IRQ_GPIO(GPIO_NR_PALMTC_PCMCIA_READY); |
71 | return 0; |
72 | |
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; |
87 | } |
88 | |
89 | static void palmtc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) |
90 | { |
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); |
97 | } |
98 | |
99 | static void palmtc_pcmcia_socket_state(struct soc_pcmcia_socket *skt, |
100 | struct pcmcia_state *state) |
101 | { |
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; |
109 | } |
110 | |
111 | static int palmtc_wifi_powerdown(void) |
112 | { |
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; |
118 | } |
119 | |
120 | static int palmtc_wifi_powerup(void) |
121 | { |
122 | int timeout = 50; |
123 | |
124 | gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 1); |
125 | mdelay(50); |
126 | |
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); |
131 | |
132 | /* Wait till the card is ready */ |
133 | while (!gpio_get_value(GPIO_NR_PALMTC_PCMCIA_PWRREADY) && |
134 | timeout) { |
135 | mdelay(1); |
136 | timeout--; |
137 | } |
138 | |
139 | /* Power down the WiFi in case of error */ |
140 | if (!timeout) { |
141 | palmtc_wifi_powerdown(); |
142 | return 1; |
143 | } |
144 | |
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); |
150 | |
151 | gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 0); |
152 | |
153 | return 0; |
154 | } |
155 | |
156 | static int palmtc_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, |
157 | const socket_state_t *state) |
158 | { |
159 | int ret = 1; |
160 | |
161 | if (state->Vcc == 0) |
162 | ret = palmtc_wifi_powerdown(); |
163 | else if (state->Vcc == 33) |
164 | ret = palmtc_wifi_powerup(); |
165 | |
166 | return ret; |
167 | } |
168 | |
169 | static void palmtc_pcmcia_socket_init(struct soc_pcmcia_socket *skt) |
170 | { |
171 | } |
172 | |
173 | static void palmtc_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) |
174 | { |
175 | } |
176 | |
177 | static struct pcmcia_low_level palmtc_pcmcia_ops = { |
178 | .owner = THIS_MODULE, |
179 | |
180 | .first = 0, |
181 | .nr = 1, |
182 | |
183 | .hw_init = palmtc_pcmcia_hw_init, |
184 | .hw_shutdown = palmtc_pcmcia_hw_shutdown, |
185 | |
186 | .socket_state = palmtc_pcmcia_socket_state, |
187 | .configure_socket = palmtc_pcmcia_configure_socket, |
188 | |
189 | .socket_init = palmtc_pcmcia_socket_init, |
190 | .socket_suspend = palmtc_pcmcia_socket_suspend, |
191 | }; |
192 | |
193 | static struct platform_device *palmtc_pcmcia_device; |
194 | |
195 | static int __init palmtc_pcmcia_init(void) |
196 | { |
197 | int ret; |
198 | |
199 | if (!machine_is_palmtc()) |
200 | return -ENODEV; |
201 | |
202 | palmtc_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); |
203 | if (!palmtc_pcmcia_device) |
204 | return -ENOMEM; |
205 | |
206 | ret = platform_device_add_data(palmtc_pcmcia_device, &palmtc_pcmcia_ops, |
207 | sizeof(palmtc_pcmcia_ops)); |
208 | |
209 | if (!ret) |
210 | ret = platform_device_add(palmtc_pcmcia_device); |
211 | |
212 | if (ret) |
213 | platform_device_put(palmtc_pcmcia_device); |
214 | |
215 | return ret; |
216 | } |
217 | |
218 | static void __exit palmtc_pcmcia_exit(void) |
219 | { |
220 | platform_device_unregister(palmtc_pcmcia_device); |
221 | } |
222 | |
223 | module_init(palmtc_pcmcia_init); |
224 | module_exit(palmtc_pcmcia_exit); |
225 | |
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"); |
231 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9