[PATCH 8/15] pcmcia: at91_cf suspend/resume/wakeup

Dominik Brodowski linux at dominikbrodowski.net
Fri Jun 30 15:57:53 EDT 2006


From: David Brownell <david-b at pacbell.net>
Date: Wed, 19 Apr 2006 06:37:48 -0700
Subject: [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 at users.sourceforge.net>
Signed-off-by: Dominik Brodowski <linux at dominikbrodowski.net>
---
 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 a4d5094..5256342 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -214,11 +214,10 @@ static struct pccard_operations at91_cf_
 
 /*--------------------------------------------------------------------------*/
 
-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_data	*board = dev->platform_data;
-	struct platform_device	*pdev = to_platform_device(dev);
+	struct at91_cf_data	*board = pdev->dev.platform_data;
 	struct resource		*io;
 	unsigned int		csa;
 	int			status;
@@ -236,7 +235,7 @@ static int __init at91_cf_probe(struct d
 
 	cf->board = board;
 	cf->pdev = pdev;
-	dev_set_drvdata(dev, cf);
+	platform_set_drvdata(pdev, cf);
 
 	/* CF takes over CS4, CS5, CS6 */
 	csa = at91_sys_read(AT91_EBI_CSA);
@@ -271,6 +270,7 @@ static int __init at91_cf_probe(struct d
 			SA_SAMPLE_RANDOM, driver_name, cf);
 	if (status < 0)
 		goto fail0;
+	device_init_wakeup(&pdev->dev, 1);
 
 	/*
 	 * The card driver will request this irq later as needed.
@@ -301,7 +301,7 @@ static int __init at91_cf_probe(struct d
 		board->det_pin, board->irq_pin);
 
 	cf->socket.owner = THIS_MODULE;
-	cf->socket.dev.dev = dev;
+	cf->socket.dev.dev = &pdev->dev;
 	cf->socket.ops = &at91_cf_ops;
 	cf->socket.resource_ops = &pccard_static_ops;
 	cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
@@ -323,21 +323,25 @@ fail1:
 		free_irq(board->irq_pin, cf);
 fail0a:
 	free_irq(board->det_pin, cf);
+	device_init_wakeup(&pdev->dev, 0);
 fail0:
 	at91_sys_write(AT91_EBI_CSA, csa);
 	kfree(cf);
 	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;
 	unsigned int		csa;
 
 	pcmcia_unregister_socket(&cf->socket);
-	free_irq(cf->board->irq_pin, cf);
-	free_irq(cf->board->det_pin, cf);
+	if (board->irq_pin)
+		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);
 	release_mem_region(io->start, io->end + 1 - io->start);
 
@@ -348,26 +352,65 @@ static int __exit at91_cf_remove(struct 
 	return 0;
 }
 
-static struct device_driver at91_cf_driver = {
-	.name		= (char *) driver_name,
-	.bus		= &platform_bus_type,
+#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;
+
+	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,
 	.remove		= __exit_p(at91_cf_remove),
-	.suspend	= pcmcia_socket_dev_suspend,
-	.resume		= pcmcia_socket_dev_resume,
+	.suspend	= at91_cf_suspend,
+	.resume		= at91_cf_resume,
 };
 
 /*--------------------------------------------------------------------------*/
 
 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);
 
 static void __exit at91_cf_exit(void)
 {
-	driver_unregister(&at91_cf_driver);
+	platform_driver_unregister(&at91_cf_driver);
 }
 module_exit(at91_cf_exit);
 
-- 
1.4.0




More information about the linux-pcmcia mailing list