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)
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>
39 #include <pcmcia/ss.h>
40 #include <pcmcia/cisreg.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
;
65 struct platform_device
*pdev
;
66 unsigned long phys_cf_io
;
67 unsigned long phys_cf_attr
;
72 /*--------------------------------------------------------------------------*/
73 static int bfin_cf_reset(void)
75 outw(0, CF_ATASEL_ENA
);
77 outw(0, CF_ATASEL_DIS
);
82 static int bfin_cf_ss_init(struct pcmcia_socket
*s
)
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
);
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
;
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
;
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
);
140 if (s
->flags
& SS_RESET
) {
141 disable_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
);
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;
171 bfin_cf_set_mem_map(struct pcmcia_socket
*s
, struct pccard_mem_map
*map
)
173 struct bfin_cf_socket
*cf
;
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
;
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
;
202 unsigned short cd_pfx
;
205 dev_info(&pdev
->dev
, "Blackfin CompactFlash/PCMCIA Socket Driver\n");
207 irq
= platform_get_irq(pdev
, 0);
211 cd_pfx
= platform_get_irq(pdev
, 1); /*Card Detect GPIO PIN */
213 if (gpio_request(cd_pfx
, "pcmcia: CD")) {
215 "Failed ro request Card Detect GPIO_%d\n",
219 gpio_direction_input(cd_pfx
);
221 cf
= kzalloc(sizeof *cf
, GFP_KERNEL
);
229 setup_timer(&cf
->timer
, bfin_cf_timer
, (unsigned long)cf
);
232 platform_set_drvdata(pdev
, cf
);
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
)
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
)
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
266 cf
->socket
.map_size
= SZ_2K
;
268 status
= pcmcia_register_socket(&cf
->socket
);
273 mod_timer(&cf
->timer
, jiffies
+ POLL_INTERVAL
);
277 iounmap((void __iomem
*)cf
->socket
.io_offset
);
278 release_mem_region(cf
->phys_cf_io
, SZ_8K
);
281 gpio_free(cf
->cd_pfx
);
283 platform_set_drvdata(pdev
, NULL
);
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
);
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
);
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
= {
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");