diff options
Diffstat (limited to 'drivers/pcmcia/sa1111_lubbock.c')
-rw-r--r-- | drivers/pcmcia/sa1111_lubbock.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/drivers/pcmcia/sa1111_lubbock.c b/drivers/pcmcia/sa1111_lubbock.c new file mode 100644 index 000000000000..c5caf5790451 --- /dev/null +++ b/drivers/pcmcia/sa1111_lubbock.c | |||
@@ -0,0 +1,236 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/pxa2xx_lubbock.c | ||
3 | * | ||
4 | * Author: George Davis | ||
5 | * Created: Jan 10, 2002 | ||
6 | * Copyright: MontaVista Software Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c | ||
13 | * | ||
14 | * Lubbock PCMCIA specific routines. | ||
15 | * | ||
16 | */ | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/delay.h> | ||
23 | |||
24 | #include <mach/hardware.h> | ||
25 | #include <asm/hardware/sa1111.h> | ||
26 | #include <asm/mach-types.h> | ||
27 | #include <mach/lubbock.h> | ||
28 | |||
29 | #include "sa1111_generic.h" | ||
30 | |||
31 | static int | ||
32 | lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | ||
33 | const socket_state_t *state) | ||
34 | { | ||
35 | struct sa1111_pcmcia_socket *s = to_skt(skt); | ||
36 | unsigned int pa_dwr_mask, pa_dwr_set, misc_mask, misc_set; | ||
37 | int ret = 0; | ||
38 | |||
39 | pa_dwr_mask = pa_dwr_set = misc_mask = misc_set = 0; | ||
40 | |||
41 | /* Lubbock uses the Maxim MAX1602, with the following connections: | ||
42 | * | ||
43 | * Socket 0 (PCMCIA): | ||
44 | * MAX1602 Lubbock Register | ||
45 | * Pin Signal | ||
46 | * ----- ------- ---------------------- | ||
47 | * A0VPP S0_PWR0 SA-1111 GPIO A<0> | ||
48 | * A1VPP S0_PWR1 SA-1111 GPIO A<1> | ||
49 | * A0VCC S0_PWR2 SA-1111 GPIO A<2> | ||
50 | * A1VCC S0_PWR3 SA-1111 GPIO A<3> | ||
51 | * VX VCC | ||
52 | * VY +3.3V | ||
53 | * 12IN +12V | ||
54 | * CODE +3.3V Cirrus Code, CODE = High (VY) | ||
55 | * | ||
56 | * Socket 1 (CF): | ||
57 | * MAX1602 Lubbock Register | ||
58 | * Pin Signal | ||
59 | * ----- ------- ---------------------- | ||
60 | * A0VPP GND VPP is not connected | ||
61 | * A1VPP GND VPP is not connected | ||
62 | * A0VCC S1_PWR0 MISC_WR<14> | ||
63 | * A1VCC S1_PWR1 MISC_WR<15> | ||
64 | * VX VCC | ||
65 | * VY +3.3V | ||
66 | * 12IN GND VPP is not connected | ||
67 | * CODE +3.3V Cirrus Code, CODE = High (VY) | ||
68 | * | ||
69 | */ | ||
70 | |||
71 | again: | ||
72 | switch (skt->nr) { | ||
73 | case 0: | ||
74 | pa_dwr_mask = GPIO_A0 | GPIO_A1 | GPIO_A2 | GPIO_A3; | ||
75 | |||
76 | switch (state->Vcc) { | ||
77 | case 0: /* Hi-Z */ | ||
78 | break; | ||
79 | |||
80 | case 33: /* VY */ | ||
81 | pa_dwr_set |= GPIO_A3; | ||
82 | break; | ||
83 | |||
84 | case 50: /* VX */ | ||
85 | pa_dwr_set |= GPIO_A2; | ||
86 | break; | ||
87 | |||
88 | default: | ||
89 | printk(KERN_ERR "%s(): unrecognized Vcc %u\n", | ||
90 | __func__, state->Vcc); | ||
91 | ret = -1; | ||
92 | } | ||
93 | |||
94 | switch (state->Vpp) { | ||
95 | case 0: /* Hi-Z */ | ||
96 | break; | ||
97 | |||
98 | case 120: /* 12IN */ | ||
99 | pa_dwr_set |= GPIO_A1; | ||
100 | break; | ||
101 | |||
102 | default: /* VCC */ | ||
103 | if (state->Vpp == state->Vcc) | ||
104 | pa_dwr_set |= GPIO_A0; | ||
105 | else { | ||
106 | printk(KERN_ERR "%s(): unrecognized Vpp %u\n", | ||
107 | __func__, state->Vpp); | ||
108 | ret = -1; | ||
109 | break; | ||
110 | } | ||
111 | } | ||
112 | break; | ||
113 | |||
114 | case 1: | ||
115 | misc_mask = (1 << 15) | (1 << 14); | ||
116 | |||
117 | switch (state->Vcc) { | ||
118 | case 0: /* Hi-Z */ | ||
119 | break; | ||
120 | |||
121 | case 33: /* VY */ | ||
122 | misc_set |= 1 << 15; | ||
123 | break; | ||
124 | |||
125 | case 50: /* VX */ | ||
126 | misc_set |= 1 << 14; | ||
127 | break; | ||
128 | |||
129 | default: | ||
130 | printk(KERN_ERR "%s(): unrecognized Vcc %u\n", | ||
131 | __func__, state->Vcc); | ||
132 | ret = -1; | ||
133 | break; | ||
134 | } | ||
135 | |||
136 | if (state->Vpp != state->Vcc && state->Vpp != 0) { | ||
137 | printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", | ||
138 | __func__, state->Vpp); | ||
139 | ret = -1; | ||
140 | break; | ||
141 | } | ||
142 | break; | ||
143 | |||
144 | default: | ||
145 | ret = -1; | ||
146 | } | ||
147 | |||
148 | if (ret == 0) | ||
149 | ret = sa1111_pcmcia_configure_socket(skt, state); | ||
150 | |||
151 | if (ret == 0) { | ||
152 | lubbock_set_misc_wr(misc_mask, misc_set); | ||
153 | sa1111_set_io(s->dev, pa_dwr_mask, pa_dwr_set); | ||
154 | } | ||
155 | |||
156 | #if 1 | ||
157 | if (ret == 0 && state->Vcc == 33) { | ||
158 | struct pcmcia_state new_state; | ||
159 | |||
160 | /* | ||
161 | * HACK ALERT: | ||
162 | * We can't sense the voltage properly on Lubbock before | ||
163 | * actually applying some power to the socket (catch 22). | ||
164 | * Resense the socket Voltage Sense pins after applying | ||
165 | * socket power. | ||
166 | * | ||
167 | * Note: It takes about 2.5ms for the MAX1602 VCC output | ||
168 | * to rise. | ||
169 | */ | ||
170 | mdelay(3); | ||
171 | |||
172 | sa1111_pcmcia_socket_state(skt, &new_state); | ||
173 | |||
174 | if (!new_state.vs_3v && !new_state.vs_Xv) { | ||
175 | /* | ||
176 | * Switch to 5V, Configure socket with 5V voltage | ||
177 | */ | ||
178 | lubbock_set_misc_wr(misc_mask, 0); | ||
179 | sa1111_set_io(s->dev, pa_dwr_mask, 0); | ||
180 | |||
181 | /* | ||
182 | * It takes about 100ms to turn off Vcc. | ||
183 | */ | ||
184 | mdelay(100); | ||
185 | |||
186 | /* | ||
187 | * We need to hack around the const qualifier as | ||
188 | * well to keep this ugly workaround localized and | ||
189 | * not force it to the rest of the code. Barf bags | ||
190 | * available in the seat pocket in front of you! | ||
191 | */ | ||
192 | ((socket_state_t *)state)->Vcc = 50; | ||
193 | ((socket_state_t *)state)->Vpp = 50; | ||
194 | goto again; | ||
195 | } | ||
196 | } | ||
197 | #endif | ||
198 | |||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static struct pcmcia_low_level lubbock_pcmcia_ops = { | ||
203 | .owner = THIS_MODULE, | ||
204 | .configure_socket = lubbock_pcmcia_configure_socket, | ||
205 | .first = 0, | ||
206 | .nr = 2, | ||
207 | }; | ||
208 | |||
209 | #include "pxa2xx_base.h" | ||
210 | |||
211 | int pcmcia_lubbock_init(struct sa1111_dev *sadev) | ||
212 | { | ||
213 | int ret = -ENODEV; | ||
214 | |||
215 | if (machine_is_lubbock()) { | ||
216 | /* | ||
217 | * Set GPIO_A<3:0> to be outputs for the MAX1600, | ||
218 | * and switch to standby mode. | ||
219 | */ | ||
220 | sa1111_set_io_dir(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0, 0); | ||
221 | sa1111_set_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); | ||
222 | sa1111_set_sleep_io(sadev, GPIO_A0|GPIO_A1|GPIO_A2|GPIO_A3, 0); | ||
223 | |||
224 | /* Set CF Socket 1 power to standby mode. */ | ||
225 | lubbock_set_misc_wr((1 << 15) | (1 << 14), 0); | ||
226 | |||
227 | pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops); | ||
228 | pxa2xx_configure_sockets(&sadev->dev); | ||
229 | ret = sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops, | ||
230 | pxa2xx_drv_pcmcia_add_one); | ||
231 | } | ||
232 | |||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | MODULE_LICENSE("GPL"); | ||