Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+59 −16
Original line number Original line Diff line number Diff line
@@ -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)


	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)
			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)
		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 @@ static int __init at91_cf_probe(struct device *dev)
		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)
	return 0;
	return 0;
}
}


static struct device_driver at91_cf_driver = {
#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,
		.name		= (char *) driver_name,
	.bus		= &platform_bus_type,
		.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);