aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXianglong Du <Xianglong.Du@csr.com>2014-04-03 17:49:53 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-03 19:21:19 -0400
commit3916b09eed268705f738957aba6fd380470e994a (patch)
treede6982f68c2ee5ae10b362e1b07b84cce8eaac5b
parentc2c0eed7f20cbfb20b346f1854afaf485bc6c207 (diff)
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>
-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)
331 return 0; 331 return 0;
332} 332}
333 333
334#ifdef CONFIG_PM 334#ifdef CONFIG_PM_SLEEP
335
336static int sirfsoc_rtc_suspend(struct device *dev) 335static int sirfsoc_rtc_suspend(struct device *dev)
337{ 336{
338 struct platform_device *pdev = to_platform_device(dev); 337 struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev);
339 struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
340 rtcdrv->overflow_rtc = 338 rtcdrv->overflow_rtc =
341 sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE); 339 sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE);
342 340
343 rtcdrv->saved_counter = 341 rtcdrv->saved_counter =
344 sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); 342 sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
345 rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc; 343 rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc;
346 if (device_may_wakeup(&pdev->dev) && !enable_irq_wake(rtcdrv->irq)) 344 if (device_may_wakeup(dev) && !enable_irq_wake(rtcdrv->irq))
347 rtcdrv->irq_wake = 1; 345 rtcdrv->irq_wake = 1;
348 346
349 return 0; 347 return 0;
350} 348}
351 349
352static int sirfsoc_rtc_freeze(struct device *dev) 350static int sirfsoc_rtc_resume(struct device *dev)
353{
354 sirfsoc_rtc_suspend(dev);
355
356 return 0;
357}
358
359static int sirfsoc_rtc_thaw(struct device *dev)
360{ 351{
361 u32 tmp; 352 u32 tmp;
362 struct sirfsoc_rtc_drv *rtcdrv; 353 struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev);
363 rtcdrv = dev_get_drvdata(dev);
364 354
365 /* 355 /*
366 * if resume from snapshot and the rtc power is losed, 356 * if resume from snapshot and the rtc power is lost,
367 * restroe the rtc settings 357 * restroe the rtc settings
368 */ 358 */
369 if (SIRFSOC_RTC_CLK != sirfsoc_rtc_iobrg_readl( 359 if (SIRFSOC_RTC_CLK != sirfsoc_rtc_iobrg_readl(
@@ -403,57 +393,23 @@ static int sirfsoc_rtc_thaw(struct device *dev)
403 sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc, 393 sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc,
404 rtcdrv->rtc_base + RTC_SW_VALUE); 394 rtcdrv->rtc_base + RTC_SW_VALUE);
405 395
406 return 0; 396 if (device_may_wakeup(dev) && rtcdrv->irq_wake) {
407}
408
409static int sirfsoc_rtc_resume(struct device *dev)
410{
411 struct platform_device *pdev = to_platform_device(dev);
412 struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
413 sirfsoc_rtc_thaw(dev);
414 if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) {
415 disable_irq_wake(rtcdrv->irq); 397 disable_irq_wake(rtcdrv->irq);
416 rtcdrv->irq_wake = 0; 398 rtcdrv->irq_wake = 0;
417 } 399 }
418 400
419 return 0; 401 return 0;
420} 402}
421
422static int sirfsoc_rtc_restore(struct device *dev)
423{
424 struct platform_device *pdev = to_platform_device(dev);
425 struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
426
427 if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) {
428 disable_irq_wake(rtcdrv->irq);
429 rtcdrv->irq_wake = 0;
430 }
431 return 0;
432}
433
434#else
435#define sirfsoc_rtc_suspend NULL
436#define sirfsoc_rtc_resume NULL
437#define sirfsoc_rtc_freeze NULL
438#define sirfsoc_rtc_thaw NULL
439#define sirfsoc_rtc_restore NULL
440#endif 403#endif
441 404
442static const struct dev_pm_ops sirfsoc_rtc_pm_ops = { 405static SIMPLE_DEV_PM_OPS(sirfsoc_rtc_pm_ops,
443 .suspend = sirfsoc_rtc_suspend, 406 sirfsoc_rtc_suspend, sirfsoc_rtc_resume);
444 .resume = sirfsoc_rtc_resume,
445 .freeze = sirfsoc_rtc_freeze,
446 .thaw = sirfsoc_rtc_thaw,
447 .restore = sirfsoc_rtc_restore,
448};
449 407
450static struct platform_driver sirfsoc_rtc_driver = { 408static struct platform_driver sirfsoc_rtc_driver = {
451 .driver = { 409 .driver = {
452 .name = "sirfsoc-rtc", 410 .name = "sirfsoc-rtc",
453 .owner = THIS_MODULE, 411 .owner = THIS_MODULE,
454#ifdef CONFIG_PM
455 .pm = &sirfsoc_rtc_pm_ops, 412 .pm = &sirfsoc_rtc_pm_ops,
456#endif
457 .of_match_table = sirfsoc_rtc_of_match, 413 .of_match_table = sirfsoc_rtc_of_match,
458 }, 414 },
459 .probe = sirfsoc_rtc_probe, 415 .probe = sirfsoc_rtc_probe,