summary refs log tree commit diff
path: root/drivers/rtc/rtc-sirfsoc.c
diff options
context:
space:
mode:
authorXianglong Du <Xianglong.Du@csr.com>2014-04-03 14:49:53 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-03 16:21:19 -0700
commit3916b09eed268705f738957aba6fd380470e994a (patch)
treede6982f68c2ee5ae10b362e1b07b84cce8eaac5b /drivers/rtc/rtc-sirfsoc.c
parentc2c0eed7f20cbfb20b346f1854afaf485bc6c207 (diff)
downloadlinux-3916b09eed268705f738957aba6fd380470e994a.tar.gz
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>
Diffstat (limited to 'drivers/rtc/rtc-sirfsoc.c')
-rw-r--r--drivers/rtc/rtc-sirfsoc.c62
1 files changed, 9 insertions, 53 deletions
diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c
index 9e3cbce56ec1..76e38007ba90 100644
--- a/drivers/rtc/rtc-sirfsoc.c
+++ b/drivers/rtc/rtc-sirfsoc.c
@@ -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,