ARM: sa1111: fix pcmcia suspend/resume
SA1111 PCMCIA was broken when PCMCIA switched to using dev_pm_ops for
the PCMCIA socket class. PCMCIA used to handle suspend/resume via the
socket hosting device, which happened at normal device suspend/resume
time.
However, the referenced commit changed this: much of the resume now
happens much earlier, in the noirq resume handler of dev_pm_ops.
However, on SA1111, the PCMCIA device is not accessible as the SA1111
has not been resumed at _noirq time. It's slightly worse than that,
because the SA1111 has already been put to sleep at _noirq time, so
suspend doesn't work properly.
Fix this by converting the core SA1111 code to use dev_pm_ops as well,
and performing its own suspend/resume at noirq time.
This fixes these errors in the kernel log:
pcmcia_socket pcmcia_socket0: time out after reset
pcmcia_socket pcmcia_socket1: time out after reset
and the resulting lack of PCMCIA cards after a S2RAM cycle.
Fixes: d7646f7632
("pcmcia: use dev_pm_ops for class pcmcia_socket_class")
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
hifive-unleashed-5.1
parent
7c0091ecea
commit
06dfe5cc0c
|
@ -869,9 +869,9 @@ struct sa1111_save_data {
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
|
||||||
static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
|
static int sa1111_suspend_noirq(struct device *dev)
|
||||||
{
|
{
|
||||||
struct sa1111 *sachip = platform_get_drvdata(dev);
|
struct sa1111 *sachip = dev_get_drvdata(dev);
|
||||||
struct sa1111_save_data *save;
|
struct sa1111_save_data *save;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
|
@ -934,9 +934,9 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
|
||||||
* restored by their respective drivers, and must be called
|
* restored by their respective drivers, and must be called
|
||||||
* via LDM after this function.
|
* via LDM after this function.
|
||||||
*/
|
*/
|
||||||
static int sa1111_resume(struct platform_device *dev)
|
static int sa1111_resume_noirq(struct device *dev)
|
||||||
{
|
{
|
||||||
struct sa1111 *sachip = platform_get_drvdata(dev);
|
struct sa1111 *sachip = dev_get_drvdata(dev);
|
||||||
struct sa1111_save_data *save;
|
struct sa1111_save_data *save;
|
||||||
unsigned long flags, id;
|
unsigned long flags, id;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
|
@ -952,7 +952,7 @@ static int sa1111_resume(struct platform_device *dev)
|
||||||
id = sa1111_readl(sachip->base + SA1111_SKID);
|
id = sa1111_readl(sachip->base + SA1111_SKID);
|
||||||
if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
|
if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
|
||||||
__sa1111_remove(sachip);
|
__sa1111_remove(sachip);
|
||||||
platform_set_drvdata(dev, NULL);
|
dev_set_drvdata(dev, NULL);
|
||||||
kfree(save);
|
kfree(save);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1003,8 +1003,8 @@ static int sa1111_resume(struct platform_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define sa1111_suspend NULL
|
#define sa1111_suspend_noirq NULL
|
||||||
#define sa1111_resume NULL
|
#define sa1111_resume_noirq NULL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int sa1111_probe(struct platform_device *pdev)
|
static int sa1111_probe(struct platform_device *pdev)
|
||||||
|
@ -1038,6 +1038,11 @@ static int sa1111_remove(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct dev_pm_ops sa1111_pm_ops = {
|
||||||
|
.suspend_noirq = sa1111_suspend_noirq,
|
||||||
|
.resume_noirq = sa1111_resume_noirq,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Not sure if this should be on the system bus or not yet.
|
* Not sure if this should be on the system bus or not yet.
|
||||||
* We really want some way to register a system device at
|
* We really want some way to register a system device at
|
||||||
|
@ -1050,10 +1055,9 @@ static int sa1111_remove(struct platform_device *pdev)
|
||||||
static struct platform_driver sa1111_device_driver = {
|
static struct platform_driver sa1111_device_driver = {
|
||||||
.probe = sa1111_probe,
|
.probe = sa1111_probe,
|
||||||
.remove = sa1111_remove,
|
.remove = sa1111_remove,
|
||||||
.suspend = sa1111_suspend,
|
|
||||||
.resume = sa1111_resume,
|
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "sa1111",
|
.name = "sa1111",
|
||||||
|
.pm = &sa1111_pm_ops,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue