[ARM] pxa: Gumstix Verdex PCMCIA support
[linux-2.6/verdex.git] / drivers / pcmcia / bfin_cf_pcmcia.c
blob300b368605c92c43b2b2e2e7a324cc5645489ee4
1 /*
2 * file: drivers/pcmcia/bfin_cf.c
4 * based on: drivers/pcmcia/omap_cf.c
5 * omap_cf.c -- OMAP 16xx CompactFlash controller driver
7 * Copyright (c) 2005 David Brownell
8 * Copyright (c) 2006-2008 Michael Hennerich Analog Devices Inc.
10 * bugs: enter bugs at http://blackfin.uclinux.org/
12 * this program is free software; you can redistribute it and/or modify
13 * it under the terms of the gnu general public license as published by
14 * the free software foundation; either version 2, or (at your option)
15 * any later version.
17 * this program is distributed in the hope that it will be useful,
18 * but without any warranty; without even the implied warranty of
19 * merchantability or fitness for a particular purpose. see the
20 * gnu general public license for more details.
22 * you should have received a copy of the gnu general public license
23 * along with this program; see the file copying.
24 * if not, write to the free software foundation,
25 * 59 temple place - suite 330, boston, ma 02111-1307, usa.
28 #include <linux/module.h>
29 #include <linux/kernel.h>
30 #include <linux/sched.h>
31 #include <linux/platform_device.h>
32 #include <linux/errno.h>
33 #include <linux/init.h>
34 #include <linux/delay.h>
35 #include <linux/interrupt.h>
36 #include <linux/irq.h>
37 #include <linux/io.h>
39 #include <pcmcia/ss.h>
40 #include <pcmcia/cisreg.h>
41 #include <asm/gpio.h>
43 #define SZ_1K 0x00000400
44 #define SZ_8K 0x00002000
45 #define SZ_2K (2 * SZ_1K)
47 #define POLL_INTERVAL (2 * HZ)
49 #define CF_ATASEL_ENA 0x20311802 /* Inverts RESET */
50 #define CF_ATASEL_DIS 0x20311800
52 #define bfin_cf_present(pfx) (gpio_get_value(pfx))
54 /*--------------------------------------------------------------------------*/
56 static const char driver_name[] = "bfin_cf_pcmcia";
58 struct bfin_cf_socket {
59 struct pcmcia_socket socket;
61 struct timer_list timer;
62 unsigned present:1;
63 unsigned active:1;
65 struct platform_device *pdev;
66 unsigned long phys_cf_io;
67 unsigned long phys_cf_attr;
68 u_int irq;
69 u_short cd_pfx;
72 /*--------------------------------------------------------------------------*/
73 static int bfin_cf_reset(void)
75 outw(0, CF_ATASEL_ENA);
76 mdelay(200);
77 outw(0, CF_ATASEL_DIS);
79 return 0;
82 static int bfin_cf_ss_init(struct pcmcia_socket *s)
84 return 0;
87 /* the timer is primarily to kick this socket's pccardd */
88 static void bfin_cf_timer(unsigned long _cf)
90 struct bfin_cf_socket *cf = (void *)_cf;
91 unsigned short present = bfin_cf_present(cf->cd_pfx);
93 if (present != cf->present) {
94 cf->present = present;
95 dev_dbg(&cf->pdev->dev, ": card %s\n",
96 present ? "present" : "gone");
97 pcmcia_parse_events(&cf->socket, SS_DETECT);
100 if (cf->active)
101 mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
104 static int bfin_cf_get_status(struct pcmcia_socket *s, u_int *sp)
106 struct bfin_cf_socket *cf;
108 if (!sp)
109 return -EINVAL;
111 cf = container_of(s, struct bfin_cf_socket, socket);
113 if (bfin_cf_present(cf->cd_pfx)) {
114 *sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
115 s->irq.AssignedIRQ = 0;
116 s->pci_irq = cf->irq;
118 } else
119 *sp = 0;
120 return 0;
123 static int
124 bfin_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
127 struct bfin_cf_socket *cf;
128 cf = container_of(sock, struct bfin_cf_socket, socket);
130 switch (s->Vcc) {
131 case 0:
132 case 33:
133 break;
134 case 50:
135 break;
136 default:
137 return -EINVAL;
140 if (s->flags & SS_RESET) {
141 disable_irq(cf->irq);
142 bfin_cf_reset();
143 enable_irq(cf->irq);
146 dev_dbg(&cf->pdev->dev, ": Vcc %d, io_irq %d, flags %04x csc %04x\n",
147 s->Vcc, s->io_irq, s->flags, s->csc_mask);
149 return 0;
152 static int bfin_cf_ss_suspend(struct pcmcia_socket *s)
154 return bfin_cf_set_socket(s, &dead_socket);
157 /* regions are 2K each: mem, attrib, io (and reserved-for-ide) */
159 static int bfin_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
161 struct bfin_cf_socket *cf;
163 cf = container_of(s, struct bfin_cf_socket, socket);
164 io->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT;
165 io->start = cf->phys_cf_io;
166 io->stop = io->start + SZ_2K - 1;
167 return 0;
170 static int
171 bfin_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map)
173 struct bfin_cf_socket *cf;
175 if (map->card_start)
176 return -EINVAL;
177 cf = container_of(s, struct bfin_cf_socket, socket);
178 map->static_start = cf->phys_cf_io;
179 map->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT;
180 if (map->flags & MAP_ATTRIB)
181 map->static_start = cf->phys_cf_attr;
183 return 0;
186 static struct pccard_operations bfin_cf_ops = {
187 .init = bfin_cf_ss_init,
188 .suspend = bfin_cf_ss_suspend,
189 .get_status = bfin_cf_get_status,
190 .set_socket = bfin_cf_set_socket,
191 .set_io_map = bfin_cf_set_io_map,
192 .set_mem_map = bfin_cf_set_mem_map,
195 /*--------------------------------------------------------------------------*/
197 static int __devinit bfin_cf_probe(struct platform_device *pdev)
199 struct bfin_cf_socket *cf;
200 struct resource *io_mem, *attr_mem;
201 int irq;
202 unsigned short cd_pfx;
203 int status = 0;
205 dev_info(&pdev->dev, "Blackfin CompactFlash/PCMCIA Socket Driver\n");
207 irq = platform_get_irq(pdev, 0);
208 if (!irq)
209 return -EINVAL;
211 cd_pfx = platform_get_irq(pdev, 1); /*Card Detect GPIO PIN */
213 if (gpio_request(cd_pfx, "pcmcia: CD")) {
214 dev_err(&pdev->dev,
215 "Failed ro request Card Detect GPIO_%d\n",
216 cd_pfx);
217 return -EBUSY;
219 gpio_direction_input(cd_pfx);
221 cf = kzalloc(sizeof *cf, GFP_KERNEL);
222 if (!cf) {
223 gpio_free(cd_pfx);
224 return -ENOMEM;
227 cf->cd_pfx = cd_pfx;
229 setup_timer(&cf->timer, bfin_cf_timer, (unsigned long)cf);
231 cf->pdev = pdev;
232 platform_set_drvdata(pdev, cf);
234 cf->irq = irq;
235 cf->socket.pci_irq = irq;
237 set_irq_type(irq, IRQF_TRIGGER_LOW);
239 io_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
240 attr_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
242 if (!io_mem || !attr_mem)
243 goto fail0;
245 cf->phys_cf_io = io_mem->start;
246 cf->phys_cf_attr = attr_mem->start;
248 /* pcmcia layer only remaps "real" memory */
249 cf->socket.io_offset = (unsigned long)
250 ioremap(cf->phys_cf_io, SZ_2K);
252 if (!cf->socket.io_offset)
253 goto fail0;
255 dev_err(&pdev->dev, ": on irq %d\n", irq);
257 dev_dbg(&pdev->dev, ": %s\n",
258 bfin_cf_present(cf->cd_pfx) ? "present" : "(not present)");
260 cf->socket.owner = THIS_MODULE;
261 cf->socket.dev.parent = &pdev->dev;
262 cf->socket.ops = &bfin_cf_ops;
263 cf->socket.resource_ops = &pccard_static_ops;
264 cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
265 | SS_CAP_MEM_ALIGN;
266 cf->socket.map_size = SZ_2K;
268 status = pcmcia_register_socket(&cf->socket);
269 if (status < 0)
270 goto fail2;
272 cf->active = 1;
273 mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
274 return 0;
276 fail2:
277 iounmap((void __iomem *)cf->socket.io_offset);
278 release_mem_region(cf->phys_cf_io, SZ_8K);
280 fail0:
281 gpio_free(cf->cd_pfx);
282 kfree(cf);
283 platform_set_drvdata(pdev, NULL);
285 return status;
288 static int __devexit bfin_cf_remove(struct platform_device *pdev)
290 struct bfin_cf_socket *cf = platform_get_drvdata(pdev);
292 gpio_free(cf->cd_pfx);
293 cf->active = 0;
294 pcmcia_unregister_socket(&cf->socket);
295 del_timer_sync(&cf->timer);
296 iounmap((void __iomem *)cf->socket.io_offset);
297 release_mem_region(cf->phys_cf_io, SZ_8K);
298 platform_set_drvdata(pdev, NULL);
299 kfree(cf);
300 return 0;
303 static int bfin_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
305 return pcmcia_socket_dev_suspend(&pdev->dev);
308 static int bfin_cf_resume(struct platform_device *pdev)
310 return pcmcia_socket_dev_resume(&pdev->dev);
313 static struct platform_driver bfin_cf_driver = {
314 .driver = {
315 .name = (char *)driver_name,
316 .owner = THIS_MODULE,
318 .probe = bfin_cf_probe,
319 .remove = __devexit_p(bfin_cf_remove),
320 .suspend = bfin_cf_suspend,
321 .resume = bfin_cf_resume,
324 static int __init bfin_cf_init(void)
326 return platform_driver_register(&bfin_cf_driver);
329 static void __exit bfin_cf_exit(void)
331 platform_driver_unregister(&bfin_cf_driver);
334 module_init(bfin_cf_init);
335 module_exit(bfin_cf_exit);
337 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
338 MODULE_DESCRIPTION("BFIN CF/PCMCIA Driver");
339 MODULE_LICENSE("GPL");