rtc: palmas: Clear all interrupt of RTC during init
Laxman Dewangan [Thu, 14 Feb 2013 09:55:20 +0000 (14:55 +0530)]
There is a false wakeup from Palma RTC in suspend state of system.
Following changes are done to fix this issue:
- Clear all intrruprs of RTC during initialization,
- make RTC interrupt as early resume and
- do not enable the interrupt in suspend, as the interrupt get
  enabled when user sets the alarm.

Add debug prints on rtc callbacks for tracing the activity happen with
RTC hardware to catch any false setting/alarm/wakeup.

bug 1227717

Change-Id: I18a5a0a845dcf036d6ffea8a350f5d32fef83e5d
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-on: http://git-master/r/200736
Reviewed-by: Automatic_Commit_Validation_User

drivers/rtc/rtc-palmas.c

index aed71f5..e82cc80 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rtc-palmas.c -- Palmas Real Time Clock interface
  *
- * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2012 - 2013, NVIDIA CORPORATION.  All rights reserved.
  * Author: Kasoju Mallikarjun <mkasoju@nvidia.com>
  *
  * This program is free software; you can redistribute it and/or
@@ -92,6 +92,8 @@ static int palmas_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
        struct palmas *palmas = dev_get_drvdata(dev->parent);
        u8 val = 0;
 
+       dev_info(dev, "%s(): enabled %u\n", __func__, enabled);
+
        if (enabled)
                val = PALMAS_RTC_INTERRUPTS_REG_IT_ALARM;
 
@@ -136,6 +138,9 @@ static int palmas_rtc_read_time(struct device *dev, struct rtc_time *tm)
        tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
        tm->tm_year = bcd2bin(rtc_data[5]) + 100;
 
+       dev_info(dev, "%s() %d %d %d %d %d %d\n",
+               __func__, tm->tm_year, tm->tm_mon, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
        return ret;
 }
 
@@ -152,6 +157,10 @@ static int palmas_rtc_set_time(struct device *dev, struct rtc_time *tm)
        rtc_data[4] = bin2bcd(tm->tm_mon + 1);
        rtc_data[5] = bin2bcd(tm->tm_year - 100);
 
+       dev_info(dev, "%s() %d %d %d %d %d %d\n",
+               __func__, tm->tm_year, tm->tm_mon, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
+
        /* Stop RTC while updating the RTC time registers */
        ret = palmas_rtc_update_bits(palmas, PALMAS_RTC_CTRL_REG,
                PALMAS_RTC_CTRL_REG_STOP_RTC, 0);
@@ -201,6 +210,10 @@ static int palmas_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
        alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1;
        alm->time.tm_year = bcd2bin(alarm_data[5]) + 100;
 
+       dev_info(dev, "%s() %d %d %d %d %d %d\n", __func__,
+               alm->time.tm_year, alm->time.tm_mon, alm->time.tm_mday,
+               alm->time.tm_hour, alm->time.tm_min, alm->time.tm_sec);
+
        ret = palmas_rtc_read(palmas, PALMAS_RTC_INTERRUPTS_REG,
                &int_val);
        if (ret < 0)
@@ -218,6 +231,7 @@ static int palmas_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
        struct palmas *palmas = dev_get_drvdata(dev->parent);
        int ret;
 
+       dev_info(dev, "%s()\n", __func__);
        ret = palmas_rtc_alarm_irq_enable(dev, 0);
        if (ret)
                return ret;
@@ -229,6 +243,10 @@ static int palmas_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
        alarm_data[4] = bin2bcd(alm->time.tm_mon + 1);
        alarm_data[5] = bin2bcd(alm->time.tm_year - 100);
 
+       dev_info(dev, "%s() %d %d %d %d %d %d\n", __func__,
+               alm->time.tm_year, alm->time.tm_mon, alm->time.tm_mday,
+               alm->time.tm_hour, alm->time.tm_min, alm->time.tm_sec);
+
        /* update all the alarm registers in one shot */
        ret = palmas_rtc_bulk_write(palmas,
                PALMAS_ALARM_SECONDS_REG, alarm_data, NUM_TIME_REGS);
@@ -252,11 +270,15 @@ static irqreturn_t palmas_rtc_interrupt(int irq, void *rtc)
        int ret;
        u32 rtc_reg;
 
+       dev_info(dev, "RTC ISR\n");
+
        ret = palmas_rtc_read(palmas, PALMAS_RTC_STATUS_REG,
                &rtc_reg);
        if (ret)
                return IRQ_NONE;
 
+       dev_info(dev, "RTC ISR status 0x%02x\n", rtc_reg);
+
        if (rtc_reg & PALMAS_RTC_STATUS_REG_ALARM)
                events = RTC_IRQF | RTC_AF;
 
@@ -334,6 +356,13 @@ static int __devinit palmas_rtc_probe(struct platform_device *pdev)
                }
        }
 
+       ret = palmas_rtc_write(palmas, PALMAS_RTC_INTERRUPTS_REG, 0);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "RTC_INTERRUPTS_REG write failed: %d\n",
+                               ret);
+               return ret;
+       }
+
        /* Clear pending interrupts */
        ret = palmas_rtc_read(palmas, PALMAS_RTC_STATUS_REG,
                &rtc_reg);
@@ -371,13 +400,15 @@ static int __devinit palmas_rtc_probe(struct platform_device *pdev)
        palmas_rtc->irq += PALMAS_RTC_ALARM_IRQ;
 
        ret = request_threaded_irq(palmas_rtc->irq, NULL,
-               palmas_rtc_interrupt, IRQF_TRIGGER_LOW,
+               palmas_rtc_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT |
+               IRQF_EARLY_RESUME,
                "palmas-rtc", &pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "IRQ is not free.\n");
                return ret;
        }
        device_init_wakeup(&pdev->dev, 1);
+       platform_set_drvdata(pdev, palmas_rtc);
 
        palmas_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
                &palmas_rtc_ops, THIS_MODULE);
@@ -388,8 +419,6 @@ static int __devinit palmas_rtc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       platform_set_drvdata(pdev, palmas_rtc);
-
        return 0;
 }
 
@@ -413,21 +442,11 @@ static int palmas_rtc_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
-       u8 alarm = PALMAS_RTC_INTERRUPTS_REG_IT_ALARM;
-       int ret;
 
        if (device_may_wakeup(dev))
                enable_irq_wake(palmas->rtc->irq);
 
-       /* Store current list of enabled interrupts*/
-       ret = palmas_rtc_read(palmas, PALMAS_RTC_INTERRUPTS_REG,
-               &palmas->rtc->irqstat);
-       if (ret < 0)
-               return ret;
-
-       /* Enable RTC ALARM interrupt only */
-       return palmas_rtc_write(palmas,
-               PALMAS_RTC_INTERRUPTS_REG, alarm);
+       return 0;
 }
 
 static int palmas_rtc_resume(struct device *dev)
@@ -438,9 +457,7 @@ static int palmas_rtc_resume(struct device *dev)
        if (device_may_wakeup(dev))
                disable_irq_wake(palmas->rtc->irq);
 
-       /* Restore list of enabled interrupts before suspend */
-       return palmas_rtc_write(palmas,
-               PALMAS_RTC_INTERRUPTS_REG, palmas->rtc->irqstat);
+       return 0;
 }
 
 static const struct dev_pm_ops palmas_rtc_pm_ops = {