drivers/rtc/rtc-sirfsoc.c: fix kernel panic of backing from hibernation
authorXianglong Du <Xianglong.Du@csr.com>
Thu, 3 Apr 2014 21:49:53 +0000 (14:49 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 3 Apr 2014 23:21:19 +0000 (16:21 -0700)
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>
drivers/rtc/rtc-sirfsoc.c

index 9e3cbce..76e3800 100644 (file)
@@ -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,