mirror of https://gitee.com/openkylin/linux.git
drivers/rtc/rtc-sirfsoc.c: fix kernel panic of backing from hibernation
RTC settings will be lost if power supply is cut off after hibernation finished, but the current "restore" function does not restore RTC related settings, this causes rtc_read_time failure and kernel panic: rtc rtc0: **** DPM device timeout **** Stack trace: unwind_backtrace+0x0/0xf4 show_stack+0x10/0x14 dpm_wd_handler+0x24/0x28 call_timer_fn.isra.33+0x24/0x88 run_timer_softirq+0x178/0x1f0 __do_softirq+0x120/0x200 do_softirq+0x54/0x5c irq_exit+0x9c/0xd0 handle_IRQ+0x44/0x90 __irq_svc+0x40/0x70 _raw_spin_unlock_irqrestore+0x10/0x48 sirfsoc_rtc_iobrg_readl+0x34/0x3c sirfsoc_rtc_read_time+0x24/0x48 __rtc_read_time.isra.3+0x48/0x5c rtc_read_time+0x30/0x44 rtc_resume.part.9+0x20/0x104 rtc_resume+0x5c/0x64 dpm_run_callback.isra.4+0x2c/0x74 device_resume+0x9c/0x144 dpm_resume+0x100/0x224 hibernation_snapshot+0x170/0x398 hibernate+0x13c/0x1d8 state_store+0xb4/0xb8 kobj_attr_store+0x14/0x20 sysfs_write_file+0x160/0x190 vfs_write+0xb4/0x194 SyS_write+0x3c/0x78 this patch uses SIMPLE_DEV_PM_OPS() to make restore() execute the existing resume() function which will restore the set of RTC. Signed-off-by: Xianglong Du <Xianglong.Du@csr.com> Signed-off-by: Barry Song <Baohua.Song@csr.com> Cc: Grant Likely <grant.likely@linaro.org> Cc: Rob Herring <robh+dt@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
c2c0eed7f2
commit
3916b09eed
|
@ -331,39 +331,29 @@ static int sirfsoc_rtc_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sirfsoc_rtc_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
|
||||
struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev);
|
||||
rtcdrv->overflow_rtc =
|
||||
sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE);
|
||||
|
||||
rtcdrv->saved_counter =
|
||||
sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
|
||||
rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc;
|
||||
if (device_may_wakeup(&pdev->dev) && !enable_irq_wake(rtcdrv->irq))
|
||||
if (device_may_wakeup(dev) && !enable_irq_wake(rtcdrv->irq))
|
||||
rtcdrv->irq_wake = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sirfsoc_rtc_freeze(struct device *dev)
|
||||
{
|
||||
sirfsoc_rtc_suspend(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sirfsoc_rtc_thaw(struct device *dev)
|
||||
static int sirfsoc_rtc_resume(struct device *dev)
|
||||
{
|
||||
u32 tmp;
|
||||
struct sirfsoc_rtc_drv *rtcdrv;
|
||||
rtcdrv = dev_get_drvdata(dev);
|
||||
struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* if resume from snapshot and the rtc power is losed,
|
||||
* if resume from snapshot and the rtc power is lost,
|
||||
* restroe the rtc settings
|
||||
*/
|
||||
if (SIRFSOC_RTC_CLK != sirfsoc_rtc_iobrg_readl(
|
||||
|
@ -403,57 +393,23 @@ static int sirfsoc_rtc_thaw(struct device *dev)
|
|||
sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc,
|
||||
rtcdrv->rtc_base + RTC_SW_VALUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sirfsoc_rtc_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
|
||||
sirfsoc_rtc_thaw(dev);
|
||||
if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) {
|
||||
if (device_may_wakeup(dev) && rtcdrv->irq_wake) {
|
||||
disable_irq_wake(rtcdrv->irq);
|
||||
rtcdrv->irq_wake = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sirfsoc_rtc_restore(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
|
||||
|
||||
if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) {
|
||||
disable_irq_wake(rtcdrv->irq);
|
||||
rtcdrv->irq_wake = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define sirfsoc_rtc_suspend NULL
|
||||
#define sirfsoc_rtc_resume NULL
|
||||
#define sirfsoc_rtc_freeze NULL
|
||||
#define sirfsoc_rtc_thaw NULL
|
||||
#define sirfsoc_rtc_restore NULL
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops sirfsoc_rtc_pm_ops = {
|
||||
.suspend = sirfsoc_rtc_suspend,
|
||||
.resume = sirfsoc_rtc_resume,
|
||||
.freeze = sirfsoc_rtc_freeze,
|
||||
.thaw = sirfsoc_rtc_thaw,
|
||||
.restore = sirfsoc_rtc_restore,
|
||||
};
|
||||
static SIMPLE_DEV_PM_OPS(sirfsoc_rtc_pm_ops,
|
||||
sirfsoc_rtc_suspend, sirfsoc_rtc_resume);
|
||||
|
||||
static struct platform_driver sirfsoc_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "sirfsoc-rtc",
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &sirfsoc_rtc_pm_ops,
|
||||
#endif
|
||||
.of_match_table = sirfsoc_rtc_of_match,
|
||||
},
|
||||
.probe = sirfsoc_rtc_probe,
|
||||
|
|
Loading…
Reference in New Issue