2014年1月28日 星期二

RTC Wake up bug .......

最近發現 , 我的 system 會無緣無故 wake up 起來 , 經過詳細比對 , 發現 ......
是 RTC  (IRQ 51) 叫它醒來的...

找了一下 RTC 的 Driver , 發現 suspend / resume 有些小邏輯錯誤.
如果有設定 Alarm IRQ , 才需要將這個 IRQ 設定為 wake up source IRQ .
如果沒有設定, 那就不用理會 是否為 wake up source .
這樣確保 不會無緣無故由 RTC wake up 起來 .
Patch file 內容如下:


Index: drivers/rtc/rtc-snvs.c
===================================================================
--- drivers/rtc/rtc-snvs.c    (revision 51)
+++ drivers/rtc/rtc-snvs.c    (working copy)
@@ -400,13 +400,18 @@
     else
         lp_cr &= ~(SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN);

-    if (lp_cr & SNVS_LPCR_ALL_INT_EN) {
-        if (!pdata->irq_enable) {
+    if (lp_cr & SNVS_LPCR_ALL_INT_EN)
+    {
+        if (!pdata->irq_enable)
+        {
             enable_irq(pdata->irq);
             pdata->irq_enable = true;
         }
-    } else {
-        if (pdata->irq_enable) {
+    }
+    else
+    {
+        if (pdata->irq_enable)
+        {
             disable_irq(pdata->irq);
             pdata->irq_enable = false;
         }
@@ -449,8 +454,10 @@

     spin_lock_irqsave(&rtc_lock, lock_flags);

-    if (enable) {
-        if (!pdata->irq_enable) {
+    if (enable)
+    {
+        if (!pdata->irq_enable)
+        {
             enable_irq(pdata->irq);
             pdata->irq_enable = true;
         }
@@ -457,7 +464,9 @@
         lp_cr = __raw_readl(ioaddr + SNVS_LPCR);
         lp_cr |= (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN);
         __raw_writel(lp_cr, ioaddr + SNVS_LPCR);
-    } else {
+    }
+    else
+    {
         lp_cr = __raw_readl(ioaddr + SNVS_LPCR);
         lp_cr &= ~(SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN);
         if (((lp_cr & SNVS_LPCR_ALL_INT_EN) == 0)
@@ -491,7 +500,8 @@
     u64 time_47bit;
     int retVal;

-    switch (cmd) {
+    switch (cmd)
+    {
     case RTC_READ_TIME_47BIT:
         time_47bit = (((u64) (__raw_readl(ioaddr + SNVS_LPSRTCMR) &
             ((0x1 << CNTR_TO_SECS_SH) - 1)) << 32) |
@@ -586,12 +596,16 @@
     __raw_writel(0xFFFFFFFF, ioaddr + SNVS_LPSR);
     udelay(100);

-    if (pdata->irq >= 0) {
+    if (pdata->irq >= 0)
+    {
         if (request_irq(pdata->irq, snvs_rtc_interrupt, IRQF_SHARED,
-                pdev->name, pdev) < 0) {
+                pdev->name, pdev) < 0)
+        {
             dev_warn(&pdev->dev, "interrupt not available.\n");
             pdata->irq = -1;
-        } else {
+        }
+        else
+        {
             disable_irq(pdata->irq);
             pdata->irq_enable = false;
         }
@@ -599,7 +613,8 @@

     rtc = rtc_device_register(pdev->name, &pdev->dev,
                   &snvs_rtc_ops, THIS_MODULE);
-    if (IS_ERR(rtc)) {
+    if (IS_ERR(rtc))
+    {
         ret = PTR_ERR(rtc);
         goto err_out;
     }
@@ -652,13 +667,19 @@
 {
     struct rtc_drv_data *pdata = platform_get_drvdata(pdev);

-    if (device_may_wakeup(&pdev->dev)) {
-        enable_irq_wake(pdata->irq);
-    } else {
+    DEBUG_MSG(">>>>");
+
+//==== Disable irq.
         if (pdata->irq_enable)
+    {
             disable_irq(pdata->irq);
+
+        if (device_may_wakeup(&pdev->dev))
+            enable_irq_wake(pdata->irq);
     }

+    DEBUG_MSG("<<<<");
+
     return 0;
 }

@@ -675,13 +696,17 @@
 {
     struct rtc_drv_data *pdata = platform_get_drvdata(pdev);

-    if (device_may_wakeup(&pdev->dev)) {
+    DEBUG_MSG(">>>>");
+
+    if (pdata->irq_enable)
+    {
+        if (device_may_wakeup(&pdev->dev))
         disable_irq_wake(pdata->irq);
-    } else {
-        if (pdata->irq_enable)
+
             enable_irq(pdata->irq);
     }

+    DEBUG_MSG("<<<<");
     return 0;
 }

@@ -689,7 +714,8 @@
  * Contains pointers to the power management callback functions.
  */
 static struct platform_driver snvs_rtc_driver = {
-    .driver = {
+    .driver =
+    {
            .name = "snvs_rtc",
            },
     .probe = snvs_rtc_probe,


沒有留言:

張貼留言