2 * Copyright (C) 2007 PA Semi, Inc
4 * Maintained by: Olof Johansson <olof@lixom.net>
6 * Based on drivers/pcmcia/omap_cf.c
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/sched.h>
26 #include <linux/platform_device.h>
27 #include <linux/errno.h>
28 #include <linux/init.h>
29 #include <linux/delay.h>
30 #include <linux/interrupt.h>
32 #include <linux/vmalloc.h>
33 #include <linux/of_platform.h>
34 #include <linux/slab.h>
36 #include <pcmcia/ss.h>
38 static const char driver_name
[] = "electra-cf";
40 struct electra_cf_socket
{
41 struct pcmcia_socket socket
;
43 struct timer_list timer
;
47 struct of_device
*ofdev
;
48 unsigned long mem_phys
;
49 void __iomem
* mem_base
;
50 unsigned long mem_size
;
51 void __iomem
* io_virt
;
55 struct resource iomem
;
56 void __iomem
* gpio_base
;
63 #define POLL_INTERVAL (2 * HZ)
66 static int electra_cf_present(struct electra_cf_socket
*cf
)
70 gpio
= in_le32(cf
->gpio_base
+0x40);
71 return !(gpio
& (1 << cf
->gpio_detect
));
74 static int electra_cf_ss_init(struct pcmcia_socket
*s
)
79 /* the timer is primarily to kick this socket's pccardd */
80 static void electra_cf_timer(unsigned long _cf
)
82 struct electra_cf_socket
*cf
= (void *) _cf
;
83 int present
= electra_cf_present(cf
);
85 if (present
!= cf
->present
) {
86 cf
->present
= present
;
87 pcmcia_parse_events(&cf
->socket
, SS_DETECT
);
91 mod_timer(&cf
->timer
, jiffies
+ POLL_INTERVAL
);
94 static irqreturn_t
electra_cf_irq(int irq
, void *_cf
)
96 electra_cf_timer((unsigned long)_cf
);
100 static int electra_cf_get_status(struct pcmcia_socket
*s
, u_int
*sp
)
102 struct electra_cf_socket
*cf
;
107 cf
= container_of(s
, struct electra_cf_socket
, socket
);
109 /* NOTE CF is always 3VCARD */
110 if (electra_cf_present(cf
)) {
111 *sp
= SS_READY
| SS_DETECT
| SS_POWERON
| SS_3VCARD
;
113 s
->pci_irq
= cf
->irq
;
119 static int electra_cf_set_socket(struct pcmcia_socket
*sock
,
120 struct socket_state_t
*s
)
124 struct electra_cf_socket
*cf
;
126 cf
= container_of(sock
, struct electra_cf_socket
, socket
);
128 /* "reset" means no power in our case */
129 vcc
= (s
->flags
& SS_RESET
) ? 0 : s
->Vcc
;
136 gpio
= (1 << cf
->gpio_3v
);
139 gpio
= (1 << cf
->gpio_5v
);
145 gpio
|= 1 << (cf
->gpio_3v
+ 16); /* enwr */
146 gpio
|= 1 << (cf
->gpio_5v
+ 16); /* enwr */
147 out_le32(cf
->gpio_base
+0x90, gpio
);
149 pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n",
150 driver_name
, s
->Vcc
, s
->io_irq
, s
->flags
, s
->csc_mask
);
155 static int electra_cf_set_io_map(struct pcmcia_socket
*s
,
156 struct pccard_io_map
*io
)
161 static int electra_cf_set_mem_map(struct pcmcia_socket
*s
,
162 struct pccard_mem_map
*map
)
164 struct electra_cf_socket
*cf
;
168 cf
= container_of(s
, struct electra_cf_socket
, socket
);
169 map
->static_start
= cf
->mem_phys
;
170 map
->flags
&= MAP_ACTIVE
|MAP_ATTRIB
;
171 if (!(map
->flags
& MAP_ATTRIB
))
172 map
->static_start
+= 0x800;
176 static struct pccard_operations electra_cf_ops
= {
177 .init
= electra_cf_ss_init
,
178 .get_status
= electra_cf_get_status
,
179 .set_socket
= electra_cf_set_socket
,
180 .set_io_map
= electra_cf_set_io_map
,
181 .set_mem_map
= electra_cf_set_mem_map
,
184 static int __devinit
electra_cf_probe(struct of_device
*ofdev
,
185 const struct of_device_id
*match
)
187 struct device
*device
= &ofdev
->dev
;
188 struct device_node
*np
= ofdev
->dev
.of_node
;
189 struct electra_cf_socket
*cf
;
190 struct resource mem
, io
;
192 const unsigned int *prop
;
194 struct vm_struct
*area
;
196 err
= of_address_to_resource(np
, 0, &mem
);
200 err
= of_address_to_resource(np
, 1, &io
);
204 cf
= kzalloc(sizeof *cf
, GFP_KERNEL
);
208 setup_timer(&cf
->timer
, electra_cf_timer
, (unsigned long)cf
);
212 cf
->mem_phys
= mem
.start
;
213 cf
->mem_size
= PAGE_ALIGN(mem
.end
- mem
.start
);
214 cf
->mem_base
= ioremap(cf
->mem_phys
, cf
->mem_size
);
215 cf
->io_size
= PAGE_ALIGN(io
.end
- io
.start
);
217 area
= __get_vm_area(cf
->io_size
, 0, PHB_IO_BASE
, PHB_IO_END
);
221 cf
->io_virt
= (void __iomem
*)(area
->addr
);
223 cf
->gpio_base
= ioremap(0xfc103000, 0x1000);
224 dev_set_drvdata(device
, cf
);
226 if (!cf
->mem_base
|| !cf
->io_virt
|| !cf
->gpio_base
||
227 (__ioremap_at(io
.start
, cf
->io_virt
, cf
->io_size
,
228 _PAGE_NO_CACHE
| _PAGE_GUARDED
) == NULL
)) {
229 dev_err(device
, "can't ioremap ranges\n");
235 cf
->io_base
= (unsigned long)cf
->io_virt
- VMALLOC_END
;
237 cf
->iomem
.start
= (unsigned long)cf
->mem_base
;
238 cf
->iomem
.end
= (unsigned long)cf
->mem_base
+ (mem
.end
- mem
.start
);
239 cf
->iomem
.flags
= IORESOURCE_MEM
;
241 cf
->irq
= irq_of_parse_and_map(np
, 0);
243 status
= request_irq(cf
->irq
, electra_cf_irq
, IRQF_SHARED
,
246 dev_err(device
, "request_irq failed\n");
250 cf
->socket
.pci_irq
= cf
->irq
;
252 prop
= of_get_property(np
, "card-detect-gpio", NULL
);
255 cf
->gpio_detect
= *prop
;
257 prop
= of_get_property(np
, "card-vsense-gpio", NULL
);
260 cf
->gpio_vsense
= *prop
;
262 prop
= of_get_property(np
, "card-3v-gpio", NULL
);
267 prop
= of_get_property(np
, "card-5v-gpio", NULL
);
272 cf
->socket
.io_offset
= cf
->io_base
;
274 /* reserve chip-select regions */
275 if (!request_mem_region(cf
->mem_phys
, cf
->mem_size
, driver_name
)) {
277 dev_err(device
, "Can't claim memory region\n");
281 if (!request_region(cf
->io_base
, cf
->io_size
, driver_name
)) {
283 dev_err(device
, "Can't claim I/O region\n");
287 cf
->socket
.owner
= THIS_MODULE
;
288 cf
->socket
.dev
.parent
= &ofdev
->dev
;
289 cf
->socket
.ops
= &electra_cf_ops
;
290 cf
->socket
.resource_ops
= &pccard_static_ops
;
291 cf
->socket
.features
= SS_CAP_PCCARD
| SS_CAP_STATIC_MAP
|
293 cf
->socket
.map_size
= 0x800;
295 status
= pcmcia_register_socket(&cf
->socket
);
297 dev_err(device
, "pcmcia_register_socket failed\n");
301 dev_info(device
, "at mem 0x%lx io 0x%llx irq %d\n",
302 cf
->mem_phys
, io
.start
, cf
->irq
);
305 electra_cf_timer((unsigned long)cf
);
309 release_region(cf
->io_base
, cf
->io_size
);
311 release_mem_region(cf
->mem_phys
, cf
->mem_size
);
313 if (cf
->irq
!= NO_IRQ
)
314 free_irq(cf
->irq
, cf
);
317 __iounmap_at(cf
->io_virt
, cf
->io_size
);
319 iounmap(cf
->mem_base
);
321 iounmap(cf
->gpio_base
);
322 device_init_wakeup(&ofdev
->dev
, 0);
328 static int __devexit
electra_cf_remove(struct of_device
*ofdev
)
330 struct device
*device
= &ofdev
->dev
;
331 struct electra_cf_socket
*cf
;
333 cf
= dev_get_drvdata(device
);
336 pcmcia_unregister_socket(&cf
->socket
);
337 free_irq(cf
->irq
, cf
);
338 del_timer_sync(&cf
->timer
);
340 __iounmap_at(cf
->io_virt
, cf
->io_size
);
341 iounmap(cf
->mem_base
);
342 iounmap(cf
->gpio_base
);
343 release_mem_region(cf
->mem_phys
, cf
->mem_size
);
344 release_region(cf
->io_base
, cf
->io_size
);
351 static const struct of_device_id electra_cf_match
[] = {
353 .compatible
= "electra-cf",
357 MODULE_DEVICE_TABLE(of
, electra_cf_match
);
359 static struct of_platform_driver electra_cf_driver
= {
361 .name
= (char *)driver_name
,
362 .owner
= THIS_MODULE
,
363 .of_match_table
= electra_cf_match
,
365 .probe
= electra_cf_probe
,
366 .remove
= electra_cf_remove
,
369 static int __init
electra_cf_init(void)
371 return of_register_platform_driver(&electra_cf_driver
);
373 module_init(electra_cf_init
);
375 static void __exit
electra_cf_exit(void)
377 of_unregister_platform_driver(&electra_cf_driver
);
379 module_exit(electra_cf_exit
);
381 MODULE_LICENSE("GPL");
382 MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
383 MODULE_DESCRIPTION("PA Semi Electra CF driver");