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/slab.h>
35 #include <linux/delay.h>
36 #include <linux/interrupt.h>
37 #include <linux/irq.h>
40 #include <pcmcia/ss.h>
41 #include <pcmcia/cisreg.h>
44 #define SZ_1K 0x00000400
45 #define SZ_8K 0x00002000
46 #define SZ_2K (2 * SZ_1K)
48 #define POLL_INTERVAL (2 * HZ)
50 #define CF_ATASEL_ENA 0x20311802 /* Inverts RESET */
51 #define CF_ATASEL_DIS 0x20311800
53 #define bfin_cf_present(pfx) (gpio_get_value(pfx))
55 /*--------------------------------------------------------------------------*/
57 static const char driver_name
[] = "bfin_cf_pcmcia";
59 struct bfin_cf_socket
{
60 struct pcmcia_socket socket
;
62 struct timer_list timer
;
66 struct platform_device
*pdev
;
67 unsigned long phys_cf_io
;
68 unsigned long phys_cf_attr
;
73 /*--------------------------------------------------------------------------*/
74 static int bfin_cf_reset(void)
76 outw(0, CF_ATASEL_ENA
);
78 outw(0, CF_ATASEL_DIS
);
83 static int bfin_cf_ss_init(struct pcmcia_socket
*s
)
88 /* the timer is primarily to kick this socket's pccardd */
89 static void bfin_cf_timer(unsigned long _cf
)
91 struct bfin_cf_socket
*cf
= (void *)_cf
;
92 unsigned short present
= bfin_cf_present(cf
->cd_pfx
);
94 if (present
!= cf
->present
) {
95 cf
->present
= present
;
96 dev_dbg(&cf
->pdev
->dev
, ": card %s\n",
97 present
? "present" : "gone");
98 pcmcia_parse_events(&cf
->socket
, SS_DETECT
);
102 mod_timer(&cf
->timer
, jiffies
+ POLL_INTERVAL
);
105 static int bfin_cf_get_status(struct pcmcia_socket
*s
, u_int
*sp
)
107 struct bfin_cf_socket
*cf
;
112 cf
= container_of(s
, struct bfin_cf_socket
, socket
);
114 if (bfin_cf_present(cf
->cd_pfx
)) {
115 *sp
= SS_READY
| SS_DETECT
| SS_POWERON
| SS_3VCARD
;
117 s
->pci_irq
= cf
->irq
;
125 bfin_cf_set_socket(struct pcmcia_socket
*sock
, struct socket_state_t
*s
)
128 struct bfin_cf_socket
*cf
;
129 cf
= container_of(sock
, struct bfin_cf_socket
, socket
);
141 if (s
->flags
& SS_RESET
) {
142 disable_irq(cf
->irq
);
147 dev_dbg(&cf
->pdev
->dev
, ": Vcc %d, io_irq %d, flags %04x csc %04x\n",
148 s
->Vcc
, s
->io_irq
, s
->flags
, s
->csc_mask
);
153 static int bfin_cf_ss_suspend(struct pcmcia_socket
*s
)
155 return bfin_cf_set_socket(s
, &dead_socket
);
158 /* regions are 2K each: mem, attrib, io (and reserved-for-ide) */
160 static int bfin_cf_set_io_map(struct pcmcia_socket
*s
, struct pccard_io_map
*io
)
162 struct bfin_cf_socket
*cf
;
164 cf
= container_of(s
, struct bfin_cf_socket
, socket
);
165 io
->flags
&= MAP_ACTIVE
| MAP_ATTRIB
| MAP_16BIT
;
166 io
->start
= cf
->phys_cf_io
;
167 io
->stop
= io
->start
+ SZ_2K
- 1;
172 bfin_cf_set_mem_map(struct pcmcia_socket
*s
, struct pccard_mem_map
*map
)
174 struct bfin_cf_socket
*cf
;
178 cf
= container_of(s
, struct bfin_cf_socket
, socket
);
179 map
->static_start
= cf
->phys_cf_io
;
180 map
->flags
&= MAP_ACTIVE
| MAP_ATTRIB
| MAP_16BIT
;
181 if (map
->flags
& MAP_ATTRIB
)
182 map
->static_start
= cf
->phys_cf_attr
;
187 static struct pccard_operations bfin_cf_ops
= {
188 .init
= bfin_cf_ss_init
,
189 .suspend
= bfin_cf_ss_suspend
,
190 .get_status
= bfin_cf_get_status
,
191 .set_socket
= bfin_cf_set_socket
,
192 .set_io_map
= bfin_cf_set_io_map
,
193 .set_mem_map
= bfin_cf_set_mem_map
,
196 /*--------------------------------------------------------------------------*/
198 static int __devinit
bfin_cf_probe(struct platform_device
*pdev
)
200 struct bfin_cf_socket
*cf
;
201 struct resource
*io_mem
, *attr_mem
;
203 unsigned short cd_pfx
;
206 dev_info(&pdev
->dev
, "Blackfin CompactFlash/PCMCIA Socket Driver\n");
208 irq
= platform_get_irq(pdev
, 0);
212 cd_pfx
= platform_get_irq(pdev
, 1); /*Card Detect GPIO PIN */
214 if (gpio_request(cd_pfx
, "pcmcia: CD")) {
216 "Failed ro request Card Detect GPIO_%d\n",
220 gpio_direction_input(cd_pfx
);
222 cf
= kzalloc(sizeof *cf
, GFP_KERNEL
);
230 setup_timer(&cf
->timer
, bfin_cf_timer
, (unsigned long)cf
);
233 platform_set_drvdata(pdev
, cf
);
236 cf
->socket
.pci_irq
= irq
;
238 irq_set_irq_type(irq
, IRQF_TRIGGER_LOW
);
240 io_mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
241 attr_mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 1);
243 if (!io_mem
|| !attr_mem
)
246 cf
->phys_cf_io
= io_mem
->start
;
247 cf
->phys_cf_attr
= attr_mem
->start
;
249 /* pcmcia layer only remaps "real" memory */
250 cf
->socket
.io_offset
= (unsigned long)
251 ioremap(cf
->phys_cf_io
, SZ_2K
);
253 if (!cf
->socket
.io_offset
)
256 dev_err(&pdev
->dev
, ": on irq %d\n", irq
);
258 dev_dbg(&pdev
->dev
, ": %s\n",
259 bfin_cf_present(cf
->cd_pfx
) ? "present" : "(not present)");
261 cf
->socket
.owner
= THIS_MODULE
;
262 cf
->socket
.dev
.parent
= &pdev
->dev
;
263 cf
->socket
.ops
= &bfin_cf_ops
;
264 cf
->socket
.resource_ops
= &pccard_static_ops
;
265 cf
->socket
.features
= SS_CAP_PCCARD
| SS_CAP_STATIC_MAP
267 cf
->socket
.map_size
= SZ_2K
;
269 status
= pcmcia_register_socket(&cf
->socket
);
274 mod_timer(&cf
->timer
, jiffies
+ POLL_INTERVAL
);
278 iounmap((void __iomem
*)cf
->socket
.io_offset
);
279 release_mem_region(cf
->phys_cf_io
, SZ_8K
);
282 gpio_free(cf
->cd_pfx
);
284 platform_set_drvdata(pdev
, NULL
);
289 static int __devexit
bfin_cf_remove(struct platform_device
*pdev
)
291 struct bfin_cf_socket
*cf
= platform_get_drvdata(pdev
);
293 gpio_free(cf
->cd_pfx
);
295 pcmcia_unregister_socket(&cf
->socket
);
296 del_timer_sync(&cf
->timer
);
297 iounmap((void __iomem
*)cf
->socket
.io_offset
);
298 release_mem_region(cf
->phys_cf_io
, SZ_8K
);
299 platform_set_drvdata(pdev
, NULL
);
304 static struct platform_driver bfin_cf_driver
= {
306 .name
= (char *)driver_name
,
307 .owner
= THIS_MODULE
,
309 .probe
= bfin_cf_probe
,
310 .remove
= __devexit_p(bfin_cf_remove
),
313 static int __init
bfin_cf_init(void)
315 return platform_driver_register(&bfin_cf_driver
);
318 static void __exit
bfin_cf_exit(void)
320 platform_driver_unregister(&bfin_cf_driver
);
323 module_init(bfin_cf_init
);
324 module_exit(bfin_cf_exit
);
326 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
327 MODULE_DESCRIPTION("BFIN CF/PCMCIA Driver");
328 MODULE_LICENSE("GPL");