[ARM] pxa: add support for Voipac PXA270 PCMCIA
[linux-2.6.git] / drivers / pcmcia / pxa2xx_vpac270.c
1 /*
2  * linux/drivers/pcmcia/pxa2xx_vpac270.c
3  *
4  * Driver for Voipac PXA270 PCMCIA and CF sockets
5  *
6  * Copyright (C) 2010
7  * 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
18 #include <asm/mach-types.h>
19
20 #include <mach/gpio.h>
21 #include <mach/vpac270.h>
22
23 #include "soc_common.h"
24
25 static struct pcmcia_irqs cd_irqs[] = {
26         {
27                 .sock = 0,
28                 .irq  = IRQ_GPIO(GPIO84_VPAC270_PCMCIA_CD),
29                 .str  = "PCMCIA CD"
30         },
31         {
32                 .sock = 1,
33                 .irq  = IRQ_GPIO(GPIO17_VPAC270_CF_CD),
34                 .str  = "CF CD"
35         },
36 };
37
38 static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
39 {
40         int ret;
41
42         if (skt->nr == 0) {
43                 ret = gpio_request(GPIO84_VPAC270_PCMCIA_CD, "PCMCIA CD");
44                 if (ret)
45                         goto err1;
46                 ret = gpio_direction_input(GPIO84_VPAC270_PCMCIA_CD);
47                 if (ret)
48                         goto err2;
49
50                 ret = gpio_request(GPIO35_VPAC270_PCMCIA_RDY, "PCMCIA RDY");
51                 if (ret)
52                         goto err2;
53                 ret = gpio_direction_input(GPIO35_VPAC270_PCMCIA_RDY);
54                 if (ret)
55                         goto err3;
56
57                 ret = gpio_request(GPIO107_VPAC270_PCMCIA_PPEN, "PCMCIA PPEN");
58                 if (ret)
59                         goto err3;
60                 ret = gpio_direction_output(GPIO107_VPAC270_PCMCIA_PPEN, 0);
61                 if (ret)
62                         goto err4;
63
64                 ret = gpio_request(GPIO11_VPAC270_PCMCIA_RESET, "PCMCIA RESET");
65                 if (ret)
66                         goto err4;
67                 ret = gpio_direction_output(GPIO11_VPAC270_PCMCIA_RESET, 0);
68                 if (ret)
69                         goto err5;
70
71                 skt->socket.pci_irq = gpio_to_irq(GPIO35_VPAC270_PCMCIA_RDY);
72
73                 return soc_pcmcia_request_irqs(skt, &cd_irqs[0], 1);
74
75 err5:
76                 gpio_free(GPIO11_VPAC270_PCMCIA_RESET);
77 err4:
78                 gpio_free(GPIO107_VPAC270_PCMCIA_PPEN);
79 err3:
80                 gpio_free(GPIO35_VPAC270_PCMCIA_RDY);
81 err2:
82                 gpio_free(GPIO84_VPAC270_PCMCIA_CD);
83 err1:
84                 return ret;
85
86         } else {
87                 ret = gpio_request(GPIO17_VPAC270_CF_CD, "CF CD");
88                 if (ret)
89                         goto err6;
90                 ret = gpio_direction_input(GPIO17_VPAC270_CF_CD);
91                 if (ret)
92                         goto err7;
93
94                 ret = gpio_request(GPIO12_VPAC270_CF_RDY, "CF RDY");
95                 if (ret)
96                         goto err7;
97                 ret = gpio_direction_input(GPIO12_VPAC270_CF_RDY);
98                 if (ret)
99                         goto err8;
100
101                 ret = gpio_request(GPIO16_VPAC270_CF_RESET, "CF RESET");
102                 if (ret)
103                         goto err8;
104                 ret = gpio_direction_output(GPIO16_VPAC270_CF_RESET, 0);
105                 if (ret)
106                         goto err9;
107
108                 skt->socket.pci_irq = gpio_to_irq(GPIO12_VPAC270_CF_RDY);
109
110                 return soc_pcmcia_request_irqs(skt, &cd_irqs[1], 1);
111
112 err9:
113                 gpio_free(GPIO16_VPAC270_CF_RESET);
114 err8:
115                 gpio_free(GPIO12_VPAC270_CF_RDY);
116 err7:
117                 gpio_free(GPIO17_VPAC270_CF_CD);
118 err6:
119                 return ret;
120
121         }
122 }
123
124 static void vpac270_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
125 {
126         gpio_free(GPIO11_VPAC270_PCMCIA_RESET);
127         gpio_free(GPIO107_VPAC270_PCMCIA_PPEN);
128         gpio_free(GPIO35_VPAC270_PCMCIA_RDY);
129         gpio_free(GPIO84_VPAC270_PCMCIA_CD);
130         gpio_free(GPIO16_VPAC270_CF_RESET);
131         gpio_free(GPIO12_VPAC270_CF_RDY);
132         gpio_free(GPIO17_VPAC270_CF_CD);
133 }
134
135 static void vpac270_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
136                                         struct pcmcia_state *state)
137 {
138         if (skt->nr == 0) {
139                 state->detect = !gpio_get_value(GPIO84_VPAC270_PCMCIA_CD);
140                 state->ready  = !!gpio_get_value(GPIO35_VPAC270_PCMCIA_RDY);
141         } else {
142                 state->detect = !gpio_get_value(GPIO17_VPAC270_CF_CD);
143                 state->ready  = !!gpio_get_value(GPIO12_VPAC270_CF_RDY);
144         }
145         state->bvd1   = 1;
146         state->bvd2   = 1;
147         state->wrprot = 0;
148         state->vs_3v  = 1;
149         state->vs_Xv  = 0;
150 }
151
152 static int
153 vpac270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
154                                 const socket_state_t *state)
155 {
156         if (skt->nr == 0) {
157                 gpio_set_value(GPIO11_VPAC270_PCMCIA_RESET,
158                         (state->flags & SS_RESET));
159                 gpio_set_value(GPIO107_VPAC270_PCMCIA_PPEN,
160                         !(state->Vcc == 33 || state->Vcc == 50));
161         } else {
162                 gpio_set_value(GPIO16_VPAC270_CF_RESET,
163                         (state->flags & SS_RESET));
164         }
165
166         return 0;
167 }
168
169 static void vpac270_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
170 {
171 }
172
173 static void vpac270_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
174 {
175 }
176
177 static struct pcmcia_low_level vpac270_pcmcia_ops = {
178         .owner                  = THIS_MODULE,
179
180         .first                  = 0,
181         .nr                     = 2,
182
183         .hw_init                = vpac270_pcmcia_hw_init,
184         .hw_shutdown            = vpac270_pcmcia_hw_shutdown,
185
186         .socket_state           = vpac270_pcmcia_socket_state,
187         .configure_socket       = vpac270_pcmcia_configure_socket,
188
189         .socket_init            = vpac270_pcmcia_socket_init,
190         .socket_suspend         = vpac270_pcmcia_socket_suspend,
191 };
192
193 static struct platform_device *vpac270_pcmcia_device;
194
195 static int __init vpac270_pcmcia_init(void)
196 {
197         int ret;
198
199         if (!machine_is_vpac270())
200                 return -ENODEV;
201
202         vpac270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
203         if (!vpac270_pcmcia_device)
204                 return -ENOMEM;
205
206         ret = platform_device_add_data(vpac270_pcmcia_device,
207                 &vpac270_pcmcia_ops, sizeof(vpac270_pcmcia_ops));
208
209         if (!ret)
210                 ret = platform_device_add(vpac270_pcmcia_device);
211
212         if (ret)
213                 platform_device_put(vpac270_pcmcia_device);
214
215         return ret;
216 }
217
218 static void __exit vpac270_pcmcia_exit(void)
219 {
220         platform_device_unregister(vpac270_pcmcia_device);
221 }
222
223 module_init(vpac270_pcmcia_init);
224 module_exit(vpac270_pcmcia_exit);
225
226 MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
227 MODULE_DESCRIPTION("PCMCIA support for Voipac PXA270");
228 MODULE_ALIAS("platform:pxa2xx-pcmcia");
229 MODULE_LICENSE("GPL");