diff options
author | David Brownell <david-b@pacbell.net> | 2006-04-19 09:37:48 -0400 |
---|---|---|
committer | Dominik Brodowski <linux@dominikbrodowski.net> | 2006-06-30 16:09:12 -0400 |
commit | 0db6095d4ff8918350797dfe299d572980e82fa0 (patch) | |
tree | 72d42bc165a382fe82a279222efc1c5c4cb7addb | |
parent | 5040cb8b7e61b7a03e8837920b9eb2c839bb1947 (diff) |
[PATCH] pcmcia: at91_cf suspend/resume/wakeup
AT91 CF updates, mostly for power management:
- Add suspend/resume methods to the AT91 CF driver, disabling
non-wakeup IRQs during system suspend. The card detect IRQ
serves as a wakeup event source.
- Convert the driver to the more-current "platform_driver" style.
So inserting or removing a CF card will wake the system, unless that
has been disabled by updating the sysfs file; and there will be no
more warnings about spurious IRQs during suspend/resume cycles.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
-rw-r--r-- | drivers/pcmcia/at91_cf.c | 75 |
1 files changed, 59 insertions, 16 deletions
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c index a4d50940ebeb..5256342e8532 100644 --- a/drivers/pcmcia/at91_cf.c +++ b/drivers/pcmcia/at91_cf.c | |||
@@ -214,11 +214,10 @@ static struct pccard_operations at91_cf_ops = { | |||
214 | 214 | ||
215 | /*--------------------------------------------------------------------------*/ | 215 | /*--------------------------------------------------------------------------*/ |
216 | 216 | ||
217 | static int __init at91_cf_probe(struct device *dev) | 217 | static int __init at91_cf_probe(struct platform_device *pdev) |
218 | { | 218 | { |
219 | struct at91_cf_socket *cf; | 219 | struct at91_cf_socket *cf; |
220 | struct at91_cf_data *board = dev->platform_data; | 220 | struct at91_cf_data *board = pdev->dev.platform_data; |
221 | struct platform_device *pdev = to_platform_device(dev); | ||
222 | struct resource *io; | 221 | struct resource *io; |
223 | unsigned int csa; | 222 | unsigned int csa; |
224 | int status; | 223 | int status; |
@@ -236,7 +235,7 @@ static int __init at91_cf_probe(struct device *dev) | |||
236 | 235 | ||
237 | cf->board = board; | 236 | cf->board = board; |
238 | cf->pdev = pdev; | 237 | cf->pdev = pdev; |
239 | dev_set_drvdata(dev, cf); | 238 | platform_set_drvdata(pdev, cf); |
240 | 239 | ||
241 | /* CF takes over CS4, CS5, CS6 */ | 240 | /* CF takes over CS4, CS5, CS6 */ |
242 | csa = at91_sys_read(AT91_EBI_CSA); | 241 | csa = at91_sys_read(AT91_EBI_CSA); |
@@ -271,6 +270,7 @@ static int __init at91_cf_probe(struct device *dev) | |||
271 | SA_SAMPLE_RANDOM, driver_name, cf); | 270 | SA_SAMPLE_RANDOM, driver_name, cf); |
272 | if (status < 0) | 271 | if (status < 0) |
273 | goto fail0; | 272 | goto fail0; |
273 | device_init_wakeup(&pdev->dev, 1); | ||
274 | 274 | ||
275 | /* | 275 | /* |
276 | * The card driver will request this irq later as needed. | 276 | * The card driver will request this irq later as needed. |
@@ -301,7 +301,7 @@ static int __init at91_cf_probe(struct device *dev) | |||
301 | board->det_pin, board->irq_pin); | 301 | board->det_pin, board->irq_pin); |
302 | 302 | ||
303 | cf->socket.owner = THIS_MODULE; | 303 | cf->socket.owner = THIS_MODULE; |
304 | cf->socket.dev.dev = dev; | 304 | cf->socket.dev.dev = &pdev->dev; |
305 | cf->socket.ops = &at91_cf_ops; | 305 | cf->socket.ops = &at91_cf_ops; |
306 | cf->socket.resource_ops = &pccard_static_ops; | 306 | cf->socket.resource_ops = &pccard_static_ops; |
307 | cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP | 307 | cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP |
@@ -323,21 +323,25 @@ fail1: | |||
323 | free_irq(board->irq_pin, cf); | 323 | free_irq(board->irq_pin, cf); |
324 | fail0a: | 324 | fail0a: |
325 | free_irq(board->det_pin, cf); | 325 | free_irq(board->det_pin, cf); |
326 | device_init_wakeup(&pdev->dev, 0); | ||
326 | fail0: | 327 | fail0: |
327 | at91_sys_write(AT91_EBI_CSA, csa); | 328 | at91_sys_write(AT91_EBI_CSA, csa); |
328 | kfree(cf); | 329 | kfree(cf); |
329 | return status; | 330 | return status; |
330 | } | 331 | } |
331 | 332 | ||
332 | static int __exit at91_cf_remove(struct device *dev) | 333 | static int __exit at91_cf_remove(struct platform_device *pdev) |
333 | { | 334 | { |
334 | struct at91_cf_socket *cf = dev_get_drvdata(dev); | 335 | struct at91_cf_socket *cf = platform_get_drvdata(pdev); |
336 | struct at91_cf_data *board = cf->board; | ||
335 | struct resource *io = cf->socket.io[0].res; | 337 | struct resource *io = cf->socket.io[0].res; |
336 | unsigned int csa; | 338 | unsigned int csa; |
337 | 339 | ||
338 | pcmcia_unregister_socket(&cf->socket); | 340 | pcmcia_unregister_socket(&cf->socket); |
339 | free_irq(cf->board->irq_pin, cf); | 341 | if (board->irq_pin) |
340 | free_irq(cf->board->det_pin, cf); | 342 | free_irq(board->irq_pin, cf); |
343 | free_irq(board->det_pin, cf); | ||
344 | device_init_wakeup(&pdev->dev, 0); | ||
341 | iounmap((void __iomem *) cf->socket.io_offset); | 345 | iounmap((void __iomem *) cf->socket.io_offset); |
342 | release_mem_region(io->start, io->end + 1 - io->start); | 346 | release_mem_region(io->start, io->end + 1 - io->start); |
343 | 347 | ||
@@ -348,26 +352,65 @@ static int __exit at91_cf_remove(struct device *dev) | |||
348 | return 0; | 352 | return 0; |
349 | } | 353 | } |
350 | 354 | ||
351 | static struct device_driver at91_cf_driver = { | 355 | #ifdef CONFIG_PM |
352 | .name = (char *) driver_name, | 356 | |
353 | .bus = &platform_bus_type, | 357 | static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg) |
358 | { | ||
359 | struct at91_cf_socket *cf = platform_get_drvdata(pdev); | ||
360 | struct at91_cf_data *board = cf->board; | ||
361 | |||
362 | pcmcia_socket_dev_suspend(&pdev->dev, mesg); | ||
363 | if (device_may_wakeup(&pdev->dev)) | ||
364 | enable_irq_wake(board->det_pin); | ||
365 | else { | ||
366 | disable_irq_wake(board->det_pin); | ||
367 | disable_irq(board->det_pin); | ||
368 | } | ||
369 | if (board->irq_pin) | ||
370 | disable_irq(board->irq_pin); | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int at91_cf_resume(struct platform_device *pdev) | ||
375 | { | ||
376 | struct at91_cf_socket *cf = platform_get_drvdata(pdev); | ||
377 | struct at91_cf_data *board = cf->board; | ||
378 | |||
379 | if (board->irq_pin) | ||
380 | enable_irq(board->irq_pin); | ||
381 | if (!device_may_wakeup(&pdev->dev)) | ||
382 | enable_irq(board->det_pin); | ||
383 | pcmcia_socket_dev_resume(&pdev->dev); | ||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | #else | ||
388 | #define at91_cf_suspend NULL | ||
389 | #define at91_cf_resume NULL | ||
390 | #endif | ||
391 | |||
392 | static struct platform_driver at91_cf_driver = { | ||
393 | .driver = { | ||
394 | .name = (char *) driver_name, | ||
395 | .owner = THIS_MODULE, | ||
396 | }, | ||
354 | .probe = at91_cf_probe, | 397 | .probe = at91_cf_probe, |
355 | .remove = __exit_p(at91_cf_remove), | 398 | .remove = __exit_p(at91_cf_remove), |
356 | .suspend = pcmcia_socket_dev_suspend, | 399 | .suspend = at91_cf_suspend, |
357 | .resume = pcmcia_socket_dev_resume, | 400 | .resume = at91_cf_resume, |
358 | }; | 401 | }; |
359 | 402 | ||
360 | /*--------------------------------------------------------------------------*/ | 403 | /*--------------------------------------------------------------------------*/ |
361 | 404 | ||
362 | static int __init at91_cf_init(void) | 405 | static int __init at91_cf_init(void) |
363 | { | 406 | { |
364 | return driver_register(&at91_cf_driver); | 407 | return platform_driver_register(&at91_cf_driver); |
365 | } | 408 | } |
366 | module_init(at91_cf_init); | 409 | module_init(at91_cf_init); |
367 | 410 | ||
368 | static void __exit at91_cf_exit(void) | 411 | static void __exit at91_cf_exit(void) |
369 | { | 412 | { |
370 | driver_unregister(&at91_cf_driver); | 413 | platform_driver_unregister(&at91_cf_driver); |
371 | } | 414 | } |
372 | module_exit(at91_cf_exit); | 415 | module_exit(at91_cf_exit); |
373 | 416 | ||