Commit 0db6095d4ff8918350797dfe299d572980e82fa0
Committed by
Dominik Brodowski
1 parent
5040cb8b7e
Exists in
master
and in
4 other branches
[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>
Showing 1 changed file with 59 additions and 16 deletions Side-by-side Diff
drivers/pcmcia/at91_cf.c
| ... | ... | @@ -214,11 +214,10 @@ |
| 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 | 219 | struct at91_cf_socket *cf; |
| 220 | - struct at91_cf_data *board = dev->platform_data; | |
| 221 | - struct platform_device *pdev = to_platform_device(dev); | |
| 220 | + struct at91_cf_data *board = pdev->dev.platform_data; | |
| 222 | 221 | struct resource *io; |
| 223 | 222 | unsigned int csa; |
| 224 | 223 | int status; |
| ... | ... | @@ -236,7 +235,7 @@ |
| 236 | 235 | |
| 237 | 236 | cf->board = board; |
| 238 | 237 | cf->pdev = pdev; |
| 239 | - dev_set_drvdata(dev, cf); | |
| 238 | + platform_set_drvdata(pdev, cf); | |
| 240 | 239 | |
| 241 | 240 | /* CF takes over CS4, CS5, CS6 */ |
| 242 | 241 | csa = at91_sys_read(AT91_EBI_CSA); |
| ... | ... | @@ -271,6 +270,7 @@ |
| 271 | 270 | SA_SAMPLE_RANDOM, driver_name, cf); |
| 272 | 271 | if (status < 0) |
| 273 | 272 | goto fail0; |
| 273 | + device_init_wakeup(&pdev->dev, 1); | |
| 274 | 274 | |
| 275 | 275 | /* |
| 276 | 276 | * The card driver will request this irq later as needed. |
| ... | ... | @@ -301,7 +301,7 @@ |
| 301 | 301 | board->det_pin, board->irq_pin); |
| 302 | 302 | |
| 303 | 303 | cf->socket.owner = THIS_MODULE; |
| 304 | - cf->socket.dev.dev = dev; | |
| 304 | + cf->socket.dev.dev = &pdev->dev; | |
| 305 | 305 | cf->socket.ops = &at91_cf_ops; |
| 306 | 306 | cf->socket.resource_ops = &pccard_static_ops; |
| 307 | 307 | cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP |
| 308 | 308 | |
| 309 | 309 | |
| 310 | 310 | |
| ... | ... | @@ -323,21 +323,25 @@ |
| 323 | 323 | free_irq(board->irq_pin, cf); |
| 324 | 324 | fail0a: |
| 325 | 325 | free_irq(board->det_pin, cf); |
| 326 | + device_init_wakeup(&pdev->dev, 0); | |
| 326 | 327 | fail0: |
| 327 | 328 | at91_sys_write(AT91_EBI_CSA, csa); |
| 328 | 329 | kfree(cf); |
| 329 | 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 | 337 | struct resource *io = cf->socket.io[0].res; |
| 336 | 338 | unsigned int csa; |
| 337 | 339 | |
| 338 | 340 | pcmcia_unregister_socket(&cf->socket); |
| 339 | - free_irq(cf->board->irq_pin, cf); | |
| 340 | - free_irq(cf->board->det_pin, cf); | |
| 341 | + if (board->irq_pin) | |
| 342 | + free_irq(board->irq_pin, cf); | |
| 343 | + free_irq(board->det_pin, cf); | |
| 344 | + device_init_wakeup(&pdev->dev, 0); | |
| 341 | 345 | iounmap((void __iomem *) cf->socket.io_offset); |
| 342 | 346 | release_mem_region(io->start, io->end + 1 - io->start); |
| 343 | 347 | |
| 344 | 348 | |
| 345 | 349 | |
| 346 | 350 | |
| ... | ... | @@ -348,26 +352,65 @@ |
| 348 | 352 | return 0; |
| 349 | 353 | } |
| 350 | 354 | |
| 351 | -static struct device_driver at91_cf_driver = { | |
| 352 | - .name = (char *) driver_name, | |
| 353 | - .bus = &platform_bus_type, | |
| 355 | +#ifdef CONFIG_PM | |
| 356 | + | |
| 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 | 397 | .probe = at91_cf_probe, |
| 355 | 398 | .remove = __exit_p(at91_cf_remove), |
| 356 | - .suspend = pcmcia_socket_dev_suspend, | |
| 357 | - .resume = pcmcia_socket_dev_resume, | |
| 399 | + .suspend = at91_cf_suspend, | |
| 400 | + .resume = at91_cf_resume, | |
| 358 | 401 | }; |
| 359 | 402 | |
| 360 | 403 | /*--------------------------------------------------------------------------*/ |
| 361 | 404 | |
| 362 | 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 | 409 | module_init(at91_cf_init); |
| 367 | 410 | |
| 368 | 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 | 415 | module_exit(at91_cf_exit); |
| 373 | 416 |