Blame view
drivers/pcmcia/at91_cf.c
9.97 KB
2c1f3b7a3 [PATCH] pcmcia: A... |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* * at91_cf.c -- AT91 CompactFlash controller driver * * Copyright (C) 2005 David Brownell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include <linux/module.h> #include <linux/kernel.h> |
2c1f3b7a3 [PATCH] pcmcia: A... |
14 15 16 17 |
#include <linux/platform_device.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/interrupt.h> |
5a0e3ad6a include cleanup: ... |
18 |
#include <linux/slab.h> |
2c1f3b7a3 [PATCH] pcmcia: A... |
19 20 |
#include <pcmcia/ss.h> |
a09e64fbc [ARM] Move includ... |
21 |
#include <mach/hardware.h> |
2c1f3b7a3 [PATCH] pcmcia: A... |
22 23 |
#include <asm/io.h> #include <asm/sizes.h> |
4c1fc445c at91_cf: use gene... |
24 |
#include <asm/gpio.h> |
2c1f3b7a3 [PATCH] pcmcia: A... |
25 |
|
a09e64fbc [ARM] Move includ... |
26 27 |
#include <mach/board.h> #include <mach/at91rm9200_mc.h> |
2c1f3b7a3 [PATCH] pcmcia: A... |
28 |
|
2c1f3b7a3 [PATCH] pcmcia: A... |
29 30 31 32 |
/* * A0..A10 work in each range; A23 indicates I/O space; A25 is CFRNW; * some other bit in {A24,A22..A11} is nREG to flag memory access * (vs attributes). So more than 2KB/region would just be waste. |
ebe5cfb3b [PATCH] pcmcia: a... |
33 |
* Note: These are offsets from the physical base address. |
2c1f3b7a3 [PATCH] pcmcia: A... |
34 |
*/ |
ebe5cfb3b [PATCH] pcmcia: a... |
35 36 37 |
#define CF_ATTR_PHYS (0) #define CF_IO_PHYS (1 << 23) #define CF_MEM_PHYS (0x017ff800) |
2c1f3b7a3 [PATCH] pcmcia: A... |
38 39 40 41 42 43 44 45 46 47 48 49 |
/*--------------------------------------------------------------------------*/ static const char driver_name[] = "at91_cf"; struct at91_cf_socket { struct pcmcia_socket socket; unsigned present:1; struct platform_device *pdev; struct at91_cf_data *board; |
ebe5cfb3b [PATCH] pcmcia: a... |
50 51 |
unsigned long phys_baseaddr; |
2c1f3b7a3 [PATCH] pcmcia: A... |
52 |
}; |
2c1f3b7a3 [PATCH] pcmcia: A... |
53 54 |
static inline int at91_cf_present(struct at91_cf_socket *cf) { |
4c1fc445c at91_cf: use gene... |
55 |
return !gpio_get_value(cf->board->det_pin); |
2c1f3b7a3 [PATCH] pcmcia: A... |
56 57 58 59 60 61 62 63 |
} /*--------------------------------------------------------------------------*/ static int at91_cf_ss_init(struct pcmcia_socket *s) { return 0; } |
7d12e780e IRQ: Maintain reg... |
64 |
static irqreturn_t at91_cf_irq(int irq, void *_cf) |
2c1f3b7a3 [PATCH] pcmcia: A... |
65 |
{ |
c7bec5aba Various drivers' ... |
66 |
struct at91_cf_socket *cf = _cf; |
2c1f3b7a3 [PATCH] pcmcia: A... |
67 68 69 70 71 72 73 |
if (irq == cf->board->det_pin) { unsigned present = at91_cf_present(cf); /* kick pccard as needed */ if (present != cf->present) { cf->present = present; |
2c5362007 Fix AT91RM9200 bu... |
74 75 76 |
pr_debug("%s: card %s ", driver_name, present ? "present" : "gone"); |
2c1f3b7a3 [PATCH] pcmcia: A... |
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
pcmcia_parse_events(&cf->socket, SS_DETECT); } } return IRQ_HANDLED; } static int at91_cf_get_status(struct pcmcia_socket *s, u_int *sp) { struct at91_cf_socket *cf; if (!sp) return -EINVAL; cf = container_of(s, struct at91_cf_socket, socket); |
2c5362007 Fix AT91RM9200 bu... |
92 |
/* NOTE: CF is always 3VCARD */ |
2c1f3b7a3 [PATCH] pcmcia: A... |
93 94 95 96 97 |
if (at91_cf_present(cf)) { int rdy = cf->board->irq_pin; /* RDY/nIRQ */ int vcc = cf->board->vcc_pin; *sp = SS_DETECT | SS_3VCARD; |
4c1fc445c at91_cf: use gene... |
98 |
if (!rdy || gpio_get_value(rdy)) |
2c1f3b7a3 [PATCH] pcmcia: A... |
99 |
*sp |= SS_READY; |
4c1fc445c at91_cf: use gene... |
100 |
if (!vcc || gpio_get_value(vcc)) |
2c1f3b7a3 [PATCH] pcmcia: A... |
101 102 103 104 105 106 |
*sp |= SS_POWERON; } else *sp = 0; return 0; } |
2c5362007 Fix AT91RM9200 bu... |
107 108 |
static int at91_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s) |
2c1f3b7a3 [PATCH] pcmcia: A... |
109 110 111 112 113 114 115 116 117 |
{ struct at91_cf_socket *cf; cf = container_of(sock, struct at91_cf_socket, socket); /* switch Vcc if needed and possible */ if (cf->board->vcc_pin) { switch (s->Vcc) { case 0: |
4c1fc445c at91_cf: use gene... |
118 |
gpio_set_value(cf->board->vcc_pin, 0); |
2c1f3b7a3 [PATCH] pcmcia: A... |
119 120 |
break; case 33: |
4c1fc445c at91_cf: use gene... |
121 |
gpio_set_value(cf->board->vcc_pin, 1); |
2c1f3b7a3 [PATCH] pcmcia: A... |
122 123 124 125 126 127 128 |
break; default: return -EINVAL; } } /* toggle reset if needed */ |
4c1fc445c at91_cf: use gene... |
129 |
gpio_set_value(cf->board->rst_pin, s->flags & SS_RESET); |
2c1f3b7a3 [PATCH] pcmcia: A... |
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x ", driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask); return 0; } static int at91_cf_ss_suspend(struct pcmcia_socket *s) { return at91_cf_set_socket(s, &dead_socket); } /* we already mapped the I/O region */ static int at91_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) { struct at91_cf_socket *cf; u32 csr; cf = container_of(s, struct at91_cf_socket, socket); io->flags &= (MAP_ACTIVE | MAP_16BIT | MAP_AUTOSZ); /* * Use 16 bit accesses unless/until we need 8-bit i/o space. |
2c1f3b7a3 [PATCH] pcmcia: A... |
154 |
*/ |
40a0017eb [PATCH] pcmcia: a... |
155 |
csr = at91_sys_read(AT91_SMC_CSR(cf->board->chipselect)) & ~AT91_SMC_DBW; |
2c1f3b7a3 [PATCH] pcmcia: A... |
156 157 158 159 160 161 162 163 164 165 166 |
/* * NOTE: this CF controller ignores IOIS16, so we can't really do * MAP_AUTOSZ. The 16bit mode allows single byte access on either * D0-D7 (even addr) or D8-D15 (odd), so it's close enough for many * purposes (and handles ide-cs). * * The 8bit mode is needed for odd byte access on D0-D7. It seems * some cards only like that way to get at the odd byte, despite * CF 3.0 spec table 35 also giving the D8-D15 option. */ |
ebe5cfb3b [PATCH] pcmcia: a... |
167 |
if (!(io->flags & (MAP_16BIT | MAP_AUTOSZ))) { |
2c1f3b7a3 [PATCH] pcmcia: A... |
168 169 170 171 172 173 174 175 |
csr |= AT91_SMC_DBW_8; pr_debug("%s: 8bit i/o bus ", driver_name); } else { csr |= AT91_SMC_DBW_16; pr_debug("%s: 16bit i/o bus ", driver_name); } |
40a0017eb [PATCH] pcmcia: a... |
176 |
at91_sys_write(AT91_SMC_CSR(cf->board->chipselect), csr); |
2c1f3b7a3 [PATCH] pcmcia: A... |
177 178 179 180 181 182 183 184 |
io->start = cf->socket.io_offset; io->stop = io->start + SZ_2K - 1; return 0; } /* pcmcia layer maps/unmaps mem regions */ |
2c5362007 Fix AT91RM9200 bu... |
185 186 |
static int at91_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map) |
2c1f3b7a3 [PATCH] pcmcia: A... |
187 188 189 190 191 192 193 |
{ struct at91_cf_socket *cf; if (map->card_start) return -EINVAL; cf = container_of(s, struct at91_cf_socket, socket); |
ebe5cfb3b [PATCH] pcmcia: a... |
194 |
map->flags &= (MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT); |
2c1f3b7a3 [PATCH] pcmcia: A... |
195 |
if (map->flags & MAP_ATTRIB) |
ebe5cfb3b [PATCH] pcmcia: a... |
196 |
map->static_start = cf->phys_baseaddr + CF_ATTR_PHYS; |
2c1f3b7a3 [PATCH] pcmcia: A... |
197 |
else |
ebe5cfb3b [PATCH] pcmcia: a... |
198 |
map->static_start = cf->phys_baseaddr + CF_MEM_PHYS; |
2c1f3b7a3 [PATCH] pcmcia: A... |
199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
return 0; } static struct pccard_operations at91_cf_ops = { .init = at91_cf_ss_init, .suspend = at91_cf_ss_suspend, .get_status = at91_cf_get_status, .set_socket = at91_cf_set_socket, .set_io_map = at91_cf_set_io_map, .set_mem_map = at91_cf_set_mem_map, }; /*--------------------------------------------------------------------------*/ |
0db6095d4 [PATCH] pcmcia: a... |
213 |
static int __init at91_cf_probe(struct platform_device *pdev) |
2c1f3b7a3 [PATCH] pcmcia: A... |
214 215 |
{ struct at91_cf_socket *cf; |
0db6095d4 [PATCH] pcmcia: a... |
216 |
struct at91_cf_data *board = pdev->dev.platform_data; |
2c5362007 Fix AT91RM9200 bu... |
217 |
struct resource *io; |
2c1f3b7a3 [PATCH] pcmcia: A... |
218 219 220 221 |
int status; if (!board || !board->det_pin || !board->rst_pin) return -ENODEV; |
2c5362007 Fix AT91RM9200 bu... |
222 223 224 |
io = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!io) return -ENODEV; |
cd8612808 [PATCH] Fix numer... |
225 |
cf = kzalloc(sizeof *cf, GFP_KERNEL); |
2c1f3b7a3 [PATCH] pcmcia: A... |
226 227 228 229 230 |
if (!cf) return -ENOMEM; cf->board = board; cf->pdev = pdev; |
ebe5cfb3b [PATCH] pcmcia: a... |
231 |
cf->phys_baseaddr = io->start; |
0db6095d4 [PATCH] pcmcia: a... |
232 |
platform_set_drvdata(pdev, cf); |
2c1f3b7a3 [PATCH] pcmcia: A... |
233 |
|
2c1f3b7a3 [PATCH] pcmcia: A... |
234 |
/* must be a GPIO; ergo must trigger on both edges */ |
4c1fc445c at91_cf: use gene... |
235 |
status = gpio_request(board->det_pin, "cf_det"); |
2c1f3b7a3 [PATCH] pcmcia: A... |
236 237 |
if (status < 0) goto fail0; |
4c1fc445c at91_cf: use gene... |
238 239 240 |
status = request_irq(board->det_pin, at91_cf_irq, 0, driver_name, cf); if (status < 0) goto fail00; |
0db6095d4 [PATCH] pcmcia: a... |
241 |
device_init_wakeup(&pdev->dev, 1); |
2c1f3b7a3 [PATCH] pcmcia: A... |
242 |
|
4c1fc445c at91_cf: use gene... |
243 244 245 246 247 248 249 250 251 |
status = gpio_request(board->rst_pin, "cf_rst"); if (status < 0) goto fail0a; if (board->vcc_pin) { status = gpio_request(board->vcc_pin, "cf_vcc"); if (status < 0) goto fail0b; } |
2c1f3b7a3 [PATCH] pcmcia: A... |
252 253 254 255 256 257 258 |
/* * The card driver will request this irq later as needed. * but it causes lots of "irqNN: nobody cared" messages * unless we report that we handle everything (sigh). * (Note: DK board doesn't wire the IRQ pin...) */ if (board->irq_pin) { |
4c1fc445c at91_cf: use gene... |
259 260 261 |
status = gpio_request(board->irq_pin, "cf_irq"); if (status < 0) goto fail0c; |
2c1f3b7a3 [PATCH] pcmcia: A... |
262 |
status = request_irq(board->irq_pin, at91_cf_irq, |
dace14537 [PATCH] irq-flags... |
263 |
IRQF_SHARED, driver_name, cf); |
2c1f3b7a3 [PATCH] pcmcia: A... |
264 |
if (status < 0) |
4c1fc445c at91_cf: use gene... |
265 |
goto fail0d; |
2c1f3b7a3 [PATCH] pcmcia: A... |
266 |
cf->socket.pci_irq = board->irq_pin; |
2c5362007 Fix AT91RM9200 bu... |
267 |
} else |
9130addad drivers/pcmcia: u... |
268 |
cf->socket.pci_irq = nr_irqs + 1; |
2c1f3b7a3 [PATCH] pcmcia: A... |
269 270 |
/* pcmcia layer only remaps "real" memory not iospace */ |
4c1fc445c at91_cf: use gene... |
271 272 |
cf->socket.io_offset = (unsigned long) ioremap(cf->phys_baseaddr + CF_IO_PHYS, SZ_2K); |
ebe5cfb3b [PATCH] pcmcia: a... |
273 274 |
if (!cf->socket.io_offset) { status = -ENXIO; |
2c1f3b7a3 [PATCH] pcmcia: A... |
275 |
goto fail1; |
ebe5cfb3b [PATCH] pcmcia: a... |
276 |
} |
2c1f3b7a3 [PATCH] pcmcia: A... |
277 |
|
40a0017eb [PATCH] pcmcia: a... |
278 |
/* reserve chip-select regions */ |
28f65c11f treewide: Convert... |
279 |
if (!request_mem_region(io->start, resource_size(io), driver_name)) { |
ebe5cfb3b [PATCH] pcmcia: a... |
280 |
status = -ENXIO; |
2c1f3b7a3 [PATCH] pcmcia: A... |
281 |
goto fail1; |
ebe5cfb3b [PATCH] pcmcia: a... |
282 |
} |
2c1f3b7a3 [PATCH] pcmcia: A... |
283 284 285 286 287 288 |
pr_info("%s: irqs det #%d, io #%d ", driver_name, board->det_pin, board->irq_pin); cf->socket.owner = THIS_MODULE; |
e4a3c3f09 pcmcia: some clas... |
289 |
cf->socket.dev.parent = &pdev->dev; |
2c1f3b7a3 [PATCH] pcmcia: A... |
290 291 292 293 294 |
cf->socket.ops = &at91_cf_ops; cf->socket.resource_ops = &pccard_static_ops; cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP | SS_CAP_MEM_ALIGN; cf->socket.map_size = SZ_2K; |
2c5362007 Fix AT91RM9200 bu... |
295 |
cf->socket.io[0].res = io; |
2c1f3b7a3 [PATCH] pcmcia: A... |
296 297 298 299 300 301 302 303 |
status = pcmcia_register_socket(&cf->socket); if (status < 0) goto fail2; return 0; fail2: |
28f65c11f treewide: Convert... |
304 |
release_mem_region(io->start, resource_size(io)); |
2c1f3b7a3 [PATCH] pcmcia: A... |
305 |
fail1: |
3efa9970b [PATCH] ioremap b... |
306 307 |
if (cf->socket.io_offset) iounmap((void __iomem *) cf->socket.io_offset); |
4c1fc445c at91_cf: use gene... |
308 |
if (board->irq_pin) { |
2c1f3b7a3 [PATCH] pcmcia: A... |
309 |
free_irq(board->irq_pin, cf); |
4c1fc445c at91_cf: use gene... |
310 311 312 313 314 315 316 317 |
fail0d: gpio_free(board->irq_pin); } fail0c: if (board->vcc_pin) gpio_free(board->vcc_pin); fail0b: gpio_free(board->rst_pin); |
2c1f3b7a3 [PATCH] pcmcia: A... |
318 |
fail0a: |
1fbece150 [PATCH] pcmcia: a... |
319 |
device_init_wakeup(&pdev->dev, 0); |
2c1f3b7a3 [PATCH] pcmcia: A... |
320 |
free_irq(board->det_pin, cf); |
4c1fc445c at91_cf: use gene... |
321 322 |
fail00: gpio_free(board->det_pin); |
2c1f3b7a3 [PATCH] pcmcia: A... |
323 |
fail0: |
2c1f3b7a3 [PATCH] pcmcia: A... |
324 325 326 |
kfree(cf); return status; } |
0db6095d4 [PATCH] pcmcia: a... |
327 |
static int __exit at91_cf_remove(struct platform_device *pdev) |
2c1f3b7a3 [PATCH] pcmcia: A... |
328 |
{ |
0db6095d4 [PATCH] pcmcia: a... |
329 330 |
struct at91_cf_socket *cf = platform_get_drvdata(pdev); struct at91_cf_data *board = cf->board; |
2c5362007 Fix AT91RM9200 bu... |
331 |
struct resource *io = cf->socket.io[0].res; |
2c1f3b7a3 [PATCH] pcmcia: A... |
332 333 |
pcmcia_unregister_socket(&cf->socket); |
28f65c11f treewide: Convert... |
334 |
release_mem_region(io->start, resource_size(io)); |
4c1fc445c at91_cf: use gene... |
335 336 |
iounmap((void __iomem *) cf->socket.io_offset); if (board->irq_pin) { |
0db6095d4 [PATCH] pcmcia: a... |
337 |
free_irq(board->irq_pin, cf); |
4c1fc445c at91_cf: use gene... |
338 339 340 341 342 |
gpio_free(board->irq_pin); } if (board->vcc_pin) gpio_free(board->vcc_pin); gpio_free(board->rst_pin); |
0db6095d4 [PATCH] pcmcia: a... |
343 |
device_init_wakeup(&pdev->dev, 0); |
ebe5cfb3b [PATCH] pcmcia: a... |
344 |
free_irq(board->det_pin, cf); |
4c1fc445c at91_cf: use gene... |
345 |
gpio_free(board->det_pin); |
2c1f3b7a3 [PATCH] pcmcia: A... |
346 347 348 |
kfree(cf); return 0; } |
0db6095d4 [PATCH] pcmcia: a... |
349 350 351 352 353 354 |
#ifdef CONFIG_PM static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg) { struct at91_cf_socket *cf = platform_get_drvdata(pdev); struct at91_cf_data *board = cf->board; |
1fbece150 [PATCH] pcmcia: a... |
355 |
if (device_may_wakeup(&pdev->dev)) { |
0db6095d4 [PATCH] pcmcia: a... |
356 |
enable_irq_wake(board->det_pin); |
1fbece150 [PATCH] pcmcia: a... |
357 358 |
if (board->irq_pin) enable_irq_wake(board->irq_pin); |
0db6095d4 [PATCH] pcmcia: a... |
359 |
} |
0db6095d4 [PATCH] pcmcia: a... |
360 361 362 363 364 |
return 0; } static int at91_cf_resume(struct platform_device *pdev) { |
9af20376e at91: fix enable/... |
365 366 367 368 369 370 371 372 |
struct at91_cf_socket *cf = platform_get_drvdata(pdev); struct at91_cf_data *board = cf->board; if (device_may_wakeup(&pdev->dev)) { disable_irq_wake(board->det_pin); if (board->irq_pin) disable_irq_wake(board->irq_pin); } |
0db6095d4 [PATCH] pcmcia: a... |
373 374 375 376 377 378 379 380 381 382 383 384 385 |
return 0; } #else #define at91_cf_suspend NULL #define at91_cf_resume NULL #endif static struct platform_driver at91_cf_driver = { .driver = { .name = (char *) driver_name, .owner = THIS_MODULE, }, |
2c1f3b7a3 [PATCH] pcmcia: A... |
386 |
.remove = __exit_p(at91_cf_remove), |
0db6095d4 [PATCH] pcmcia: a... |
387 388 |
.suspend = at91_cf_suspend, .resume = at91_cf_resume, |
2c1f3b7a3 [PATCH] pcmcia: A... |
389 390 391 392 393 394 |
}; /*--------------------------------------------------------------------------*/ static int __init at91_cf_init(void) { |
02c83595b at91_cf, minor fix |
395 |
return platform_driver_probe(&at91_cf_driver, at91_cf_probe); |
2c1f3b7a3 [PATCH] pcmcia: A... |
396 397 398 399 400 |
} module_init(at91_cf_init); static void __exit at91_cf_exit(void) { |
0db6095d4 [PATCH] pcmcia: a... |
401 |
platform_driver_unregister(&at91_cf_driver); |
2c1f3b7a3 [PATCH] pcmcia: A... |
402 403 404 405 406 407 |
} module_exit(at91_cf_exit); MODULE_DESCRIPTION("AT91 Compact Flash Driver"); MODULE_AUTHOR("David Brownell"); MODULE_LICENSE("GPL"); |
12c2c019e pcmcia: fix platf... |
408 |
MODULE_ALIAS("platform:at91_cf"); |