Commit 0db6095d authored by David Brownell's avatar David Brownell Committed by Dominik Brodowski

[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: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarDominik Brodowski <linux@dominikbrodowski.net>
parent 5040cb8b
...@@ -214,11 +214,10 @@ static struct pccard_operations at91_cf_ops = { ...@@ -214,11 +214,10 @@ static struct pccard_operations at91_cf_ops = {
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
static int __init at91_cf_probe(struct device *dev) static int __init at91_cf_probe(struct platform_device *pdev)
{ {
struct at91_cf_socket *cf; struct at91_cf_socket *cf;
struct at91_cf_data *board = dev->platform_data; struct at91_cf_data *board = pdev->dev.platform_data;
struct platform_device *pdev = to_platform_device(dev);
struct resource *io; struct resource *io;
unsigned int csa; unsigned int csa;
int status; int status;
...@@ -236,7 +235,7 @@ static int __init at91_cf_probe(struct device *dev) ...@@ -236,7 +235,7 @@ static int __init at91_cf_probe(struct device *dev)
cf->board = board; cf->board = board;
cf->pdev = pdev; cf->pdev = pdev;
dev_set_drvdata(dev, cf); platform_set_drvdata(pdev, cf);
/* CF takes over CS4, CS5, CS6 */ /* CF takes over CS4, CS5, CS6 */
csa = at91_sys_read(AT91_EBI_CSA); csa = at91_sys_read(AT91_EBI_CSA);
...@@ -271,6 +270,7 @@ static int __init at91_cf_probe(struct device *dev) ...@@ -271,6 +270,7 @@ static int __init at91_cf_probe(struct device *dev)
SA_SAMPLE_RANDOM, driver_name, cf); SA_SAMPLE_RANDOM, driver_name, cf);
if (status < 0) if (status < 0)
goto fail0; goto fail0;
device_init_wakeup(&pdev->dev, 1);
/* /*
* The card driver will request this irq later as needed. * The card driver will request this irq later as needed.
...@@ -301,7 +301,7 @@ static int __init at91_cf_probe(struct device *dev) ...@@ -301,7 +301,7 @@ static int __init at91_cf_probe(struct device *dev)
board->det_pin, board->irq_pin); board->det_pin, board->irq_pin);
cf->socket.owner = THIS_MODULE; cf->socket.owner = THIS_MODULE;
cf->socket.dev.dev = dev; cf->socket.dev.dev = &pdev->dev;
cf->socket.ops = &at91_cf_ops; cf->socket.ops = &at91_cf_ops;
cf->socket.resource_ops = &pccard_static_ops; cf->socket.resource_ops = &pccard_static_ops;
cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
...@@ -323,21 +323,25 @@ fail1: ...@@ -323,21 +323,25 @@ fail1:
free_irq(board->irq_pin, cf); free_irq(board->irq_pin, cf);
fail0a: fail0a:
free_irq(board->det_pin, cf); free_irq(board->det_pin, cf);
device_init_wakeup(&pdev->dev, 0);
fail0: fail0:
at91_sys_write(AT91_EBI_CSA, csa); at91_sys_write(AT91_EBI_CSA, csa);
kfree(cf); kfree(cf);
return status; return status;
} }
static int __exit at91_cf_remove(struct device *dev) static int __exit at91_cf_remove(struct platform_device *pdev)
{ {
struct at91_cf_socket *cf = dev_get_drvdata(dev); struct at91_cf_socket *cf = platform_get_drvdata(pdev);
struct at91_cf_data *board = cf->board;
struct resource *io = cf->socket.io[0].res; struct resource *io = cf->socket.io[0].res;
unsigned int csa; unsigned int csa;
pcmcia_unregister_socket(&cf->socket); pcmcia_unregister_socket(&cf->socket);
free_irq(cf->board->irq_pin, cf); if (board->irq_pin)
free_irq(cf->board->det_pin, cf); free_irq(board->irq_pin, cf);
free_irq(board->det_pin, cf);
device_init_wakeup(&pdev->dev, 0);
iounmap((void __iomem *) cf->socket.io_offset); iounmap((void __iomem *) cf->socket.io_offset);
release_mem_region(io->start, io->end + 1 - io->start); release_mem_region(io->start, io->end + 1 - io->start);
...@@ -348,26 +352,65 @@ static int __exit at91_cf_remove(struct device *dev) ...@@ -348,26 +352,65 @@ static int __exit at91_cf_remove(struct device *dev)
return 0; return 0;
} }
static struct device_driver at91_cf_driver = { #ifdef CONFIG_PM
.name = (char *) driver_name,
.bus = &platform_bus_type, 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;
pcmcia_socket_dev_suspend(&pdev->dev, mesg);
if (device_may_wakeup(&pdev->dev))
enable_irq_wake(board->det_pin);
else {
disable_irq_wake(board->det_pin);
disable_irq(board->det_pin);
}
if (board->irq_pin)
disable_irq(board->irq_pin);
return 0;
}
static int at91_cf_resume(struct platform_device *pdev)
{
struct at91_cf_socket *cf = platform_get_drvdata(pdev);
struct at91_cf_data *board = cf->board;
if (board->irq_pin)
enable_irq(board->irq_pin);
if (!device_may_wakeup(&pdev->dev))
enable_irq(board->det_pin);
pcmcia_socket_dev_resume(&pdev->dev);
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,
},
.probe = at91_cf_probe, .probe = at91_cf_probe,
.remove = __exit_p(at91_cf_remove), .remove = __exit_p(at91_cf_remove),
.suspend = pcmcia_socket_dev_suspend, .suspend = at91_cf_suspend,
.resume = pcmcia_socket_dev_resume, .resume = at91_cf_resume,
}; };
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
static int __init at91_cf_init(void) static int __init at91_cf_init(void)
{ {
return driver_register(&at91_cf_driver); return platform_driver_register(&at91_cf_driver);
} }
module_init(at91_cf_init); module_init(at91_cf_init);
static void __exit at91_cf_exit(void) static void __exit at91_cf_exit(void)
{ {
driver_unregister(&at91_cf_driver); platform_driver_unregister(&at91_cf_driver);
} }
module_exit(at91_cf_exit); module_exit(at91_cf_exit);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment